Current section

Files

Jump to
caffeine_lang src caffeine_lang@cql@parser.erl
Raw

src/caffeine_lang@cql@parser.erl

-module(caffeine_lang@cql@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/cql/parser.gleam").
-export([do_parse_expr/1, parse_expr/1]).
-export_type(['query'/0, exp_container/0, operator/0, exp/0, primary/0, word/0]).
-type 'query'() :: {'query', exp()}.
-type exp_container() :: {exp_container, exp()}.
-type operator() :: add | sub | mul | 'div'.
-type exp() :: {operator_expr, exp(), exp(), operator()} | {primary, primary()}.
-type primary() :: {primary_word, word()} | {primary_exp, exp()}.
-type word() :: {word, binary()}.
-file("src/caffeine_lang/cql/parser.gleam", 97).
-spec check_balanced_parens(binary(), integer(), integer()) -> boolean().
check_balanced_parens(Input, Pos, Count) ->
case Pos >= string:length(Input) of
true ->
Count =:= 0;
false ->
Char = gleam@string:slice(Input, Pos, 1),
New_count = case Char of
<<"("/utf8>> ->
Count + 1;
<<")"/utf8>> ->
Count - 1;
_ ->
Count
end,
case (New_count =:= 0) andalso (Pos < (string:length(Input) - 1)) of
true ->
false;
false ->
check_balanced_parens(Input, Pos + 1, New_count)
end
end.
-file("src/caffeine_lang/cql/parser.gleam", 85).
-spec is_fully_parenthesized(binary()) -> boolean().
is_fully_parenthesized(Input) ->
Length = string:length(Input),
case Length < 2 of
true ->
false;
false ->
check_balanced_parens(Input, 1, 1)
end.
-file("src/caffeine_lang/cql/parser.gleam", 115).
-spec find_rightmost_operator_at_level(
binary(),
binary(),
integer(),
integer(),
integer()
) -> {ok, {binary(), binary()}} | {error, binary()}.
find_rightmost_operator_at_level(
Input,
Operator,
Start_pos,
Paren_level,
Rightmost_pos
) ->
case Start_pos >= string:length(Input) of
true ->
case Rightmost_pos of
-1 ->
{error, <<"Operator not found"/utf8>>};
Pos ->
Left = gleam@string:trim(gleam@string:slice(Input, 0, Pos)),
Right_start = Pos + string:length(Operator),
Right_length = string:length(Input) - Right_start,
Right = gleam@string:trim(
gleam@string:slice(Input, Right_start, Right_length)
),
{ok, {Left, Right}}
end;
false ->
Char = gleam@string:slice(Input, Start_pos, 1),
New_paren_level = case Char of
<<"("/utf8>> ->
Paren_level + 1;
<<")"/utf8>> ->
Paren_level - 1;
_ ->
Paren_level
end,
Is_target_operator = (Paren_level =:= 0) andalso (gleam@string:slice(
Input,
Start_pos,
string:length(Operator)
)
=:= Operator),
New_rightmost_pos = case Is_target_operator of
true ->
Start_pos;
false ->
Rightmost_pos
end,
find_rightmost_operator_at_level(
Input,
Operator,
Start_pos + 1,
New_paren_level,
New_rightmost_pos
)
end.
-file("src/caffeine_lang/cql/parser.gleam", 78).
-spec find_operator(binary(), binary()) -> {ok, {binary(), binary()}} |
{error, binary()}.
find_operator(Input, Operator) ->
find_rightmost_operator_at_level(Input, Operator, 0, 0, -1).
-file("src/caffeine_lang/cql/parser.gleam", 56).
-spec try_operators(binary(), list({binary(), operator()})) -> {ok, exp()} |
{error, binary()}.
try_operators(Input, Operators) ->
case Operators of
[] ->
Word = {word, Input},
{ok, {primary, {primary_word, Word}}};
[{Op_str, Op} | Rest] ->
case find_operator(Input, Op_str) of
{ok, {Left, Right}} ->
gleam@result:'try'(
do_parse_expr(Left),
fun(Left_exp) ->
gleam@result:'try'(
do_parse_expr(Right),
fun(Right_exp) ->
{ok,
{operator_expr, Left_exp, Right_exp, Op}}
end
)
end
);
{error, _} ->
try_operators(Input, Rest)
end
end.
-file("src/caffeine_lang/cql/parser.gleam", 38).
-spec do_parse_expr(binary()) -> {ok, exp()} | {error, binary()}.
do_parse_expr(Input) ->
Trimmed = gleam@string:trim(Input),
case (gleam_stdlib:string_starts_with(Trimmed, <<"("/utf8>>) andalso gleam_stdlib:string_ends_with(
Trimmed,
<<")"/utf8>>
))
andalso is_fully_parenthesized(Trimmed) of
true ->
Inner = gleam@string:slice(Trimmed, 1, string:length(Trimmed) - 2),
gleam@result:'try'(
do_parse_expr(Inner),
fun(Inner_exp) -> {ok, {primary, {primary_exp, Inner_exp}}} end
);
false ->
Operators = [{<<"+"/utf8>>, add},
{<<"-"/utf8>>, sub},
{<<"*"/utf8>>, mul},
{<<"/"/utf8>>, 'div'}],
try_operators(Trimmed, Operators)
end.
-file("src/caffeine_lang/cql/parser.gleam", 33).
-spec parse_expr(binary()) -> {ok, exp_container()} | {error, binary()}.
parse_expr(Input) ->
gleam@result:'try'(
do_parse_expr(Input),
fun(Exp) -> {ok, {exp_container, Exp}} end
).