-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 ).