-module(cel@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([expr/1, id/1, with_id/2, parse/1]). -export_type([binary_op/0, arithmetic/0, relation/0, logical/0, unary_op/0, atom_/0, member/0, expression/0, expression_data/0, context/0, error/0]). -type binary_op() :: {arithmetic, arithmetic()} | {relation, relation()} | {logical, logical()}. -type arithmetic() :: add | sub | mul | 'div' | mod. -type relation() :: less_than | less_than_eq | greater_than | greater_than_eq | equals | not_equals | in. -type logical() :: 'and' | 'or'. -type unary_op() :: 'not' | unary_sub. -type atom_() :: {int, integer()} | {u_int, integer()} | {float, float()} | {string, binary()} | {bytes, bitstring()} | {bool, boolean()} | null. -type member() :: {attribute, binary()} | {index, expression_data()}. -type expression() :: {binary_operation, expression_data(), binary_op(), expression_data()} | {unary, unary_op(), expression_data()} | {ternary, expression_data(), expression_data(), expression_data()} | {list, list(expression_data())} | {map, list({expression_data(), expression_data()})} | {member, expression_data(), member()} | {function_call, binary(), gleam@option:option(expression_data()), list(expression_data())} | {atom, atom_()} | {ident, binary()}. -opaque expression_data() :: {expression_data, expression(), integer()}. -type context() :: {ctx, list({cel@parser@lexer:token(), cel@parser@lexer:position()}), integer()}. -type error() :: unexpected_end_of_file | {unexpected_source_str, binary(), integer()} | {unexpected_token, cel@parser@lexer:token(), integer()} | {dead_end, list({cel@parser@lexer:token(), cel@parser@lexer:position()})}. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 84). -spec expr(expression_data()) -> expression(). expr(Data) -> erlang:element(2, Data). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 88). -spec id(expression_data()) -> integer(). id(Data) -> erlang:element(3, Data). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 93). -spec with_id(expression(), integer()) -> expression_data(). with_id(Expr, Id) -> {expression_data, Expr, Id}. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 101). -spec binary_operator(cel@parser@lexer:token()) -> {ok, binary_op()} | {error, nil}. binary_operator(Token) -> case Token of plus -> {ok, {arithmetic, add}}; minus -> {ok, {arithmetic, sub}}; star -> {ok, {arithmetic, mul}}; slash -> {ok, {arithmetic, 'div'}}; percent -> {ok, {arithmetic, mod}}; less_than -> {ok, {relation, less_than}}; less_than_eq -> {ok, {relation, less_than_eq}}; greater_than -> {ok, {relation, greater_than}}; greater_than_eq -> {ok, {relation, greater_than_eq}}; equals -> {ok, {relation, equals}}; not_equals -> {ok, {relation, not_equals}}; in -> {ok, {relation, in}}; 'and' -> {ok, {logical, 'and'}}; 'or' -> {ok, {logical, 'or'}}; _ -> {error, nil} end. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 131). -spec advance( context(), list({cel@parser@lexer:token(), cel@parser@lexer:position()}) ) -> context(). advance(Ctx, Tokens) -> erlang:setelement(2, Ctx, Tokens). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 237). -spec precedence(binary_op()) -> integer(). precedence(Operator) -> case Operator of {arithmetic, mul} -> 3; {arithmetic, 'div'} -> 3; {arithmetic, mod} -> 3; {arithmetic, add} -> 4; {arithmetic, sub} -> 4; {relation, _} -> 5; {logical, 'and'} -> 6; {logical, 'or'} -> 7 end. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 247). -spec new(expression(), context()) -> {expression_data(), context()}. new(Expr, Ctx) -> Id = erlang:element(3, Ctx), {{expression_data, Expr, Id}, erlang:setelement(3, Ctx, Id + 1)}. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 252). -spec make( expression(), context(), list({cel@parser@lexer:token(), cel@parser@lexer:position()}) ) -> {expression_data(), context()}. make(Expr, Ctx, Tokens) -> Id = erlang:element(3, Ctx), {{expression_data, Expr, Id}, {ctx, Tokens, Id + 1}}. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 197). -spec handle_operator( context(), gleam@option:option(binary_op()), list(binary_op()), list(expression_data()) ) -> {gleam@option:option(expression_data()), list(binary_op()), list(expression_data()), context()}. handle_operator(Ctx, Next, Operators, Values) -> case {Next, Operators, Values} of {{some, Operator}, [], _} -> {none, [Operator], Values, Ctx}; {{some, Next@1}, [Previous | Operators@1], [A, B | Rest_values]} -> case precedence(Previous) =< precedence(Next@1) of true -> {Expr, Ctx@1} = begin _pipe = {binary_operation, B, Previous, A}, new(_pipe, Ctx) end, Values@1 = [Expr | Rest_values], handle_operator( erlang:setelement( 3, Ctx@1, erlang:element(3, Ctx@1) + 1 ), {some, Next@1}, Operators@1, Values@1 ); false -> {none, [Next@1, Previous | Operators@1], Values, Ctx} end; {none, [Operator@1 | Operators@2], [A@1, B@1 | Values@2]} -> {Expr@1, Ctx@2} = begin _pipe@1 = {binary_operation, B@1, Operator@1, A@1}, make(_pipe@1, Ctx, erlang:element(2, Ctx)) end, Values@3 = [Expr@1 | Values@2], handle_operator(Ctx@2, none, Operators@2, Values@3); {none, [], [Expression]} -> {{some, Expression}, Operators, Values, Ctx}; {none, [], []} -> {none, Operators, Values, Ctx}; {_, _, _} -> erlang:error(#{gleam_error => panic, message => <<"parser bug, operator expression not full reduced"/utf8>>, module => <<"cel/parser"/utf8>>, function => <<"handle_operator"/utf8>>, line => 233}) end. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 398). -spec list( context(), fun((context()) -> {ok, {HCF, context()}} | {error, error()}), gleam@option:option(HCF), list(HCF) ) -> {ok, {list(HCF), context()}} | {error, error()}. list(Ctx, Parser, Discard, Acc) -> case erlang:element(2, Ctx) of [{right_square, _} | Tokens] -> {ok, {lists:reverse(Acc), advance(Ctx, Tokens)}}; [{comma, _}, {right_square, _} | Tokens@1] when Acc =/= [] -> {ok, {lists:reverse(Acc), advance(Ctx, Tokens@1)}}; _ -> gleam@result:'try'( Parser(Ctx), fun(_use0) -> {Element, Ctx@1} = _use0, Acc@1 = [Element | Acc], case erlang:element(2, Ctx@1) of [{right_square, _} | Tokens@2] -> {ok, {lists:reverse(Acc@1), advance(Ctx@1, Tokens@2)}}; [{comma, _}, {right_square, _} | Tokens@2] -> {ok, {lists:reverse(Acc@1), advance(Ctx@1, Tokens@2)}}; [{comma, _} | Tokens@3] -> list( advance(Ctx@1, Tokens@3), Parser, Discard, Acc@1 ); [{Other, Position} | _] -> {error, {unexpected_token, Other, erlang:element(2, Position)}}; [] -> {error, unexpected_end_of_file} end end ) end. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 516). -spec unexpected(list({cel@parser@lexer:token(), cel@parser@lexer:position()})) -> {ok, any()} | {error, error()}. unexpected(Tokens) -> case Tokens of [{Token, Pos} | _] -> {error, {unexpected_token, Token, erlang:element(2, Pos)}}; [] -> {error, unexpected_end_of_file} end. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 353). -spec comma_delimited( context(), list(HBW), fun((context()) -> {ok, {HBW, context()}} | {error, error()}), cel@parser@lexer:token() ) -> {ok, {list(HBW), context()}} | {error, error()}. comma_delimited(Ctx, Items, Parser, Final) -> case erlang:element(2, Ctx) of [] -> {error, unexpected_end_of_file}; [{Token, _} | Tokens] when Token =:= Final -> {ok, {lists:reverse(Items), advance(Ctx, Tokens)}}; _ -> gleam@result:'try'( Parser(Ctx), fun(_use0) -> {Element, Ctx@1} = _use0, case erlang:element(2, Ctx@1) of [{comma, _} | Tokens@1] -> comma_delimited( advance(Ctx@1, Tokens@1), [Element | Items], Parser, Final ); [{Token@1, _} | Tokens@2] when Token@1 =:= Final -> {ok, {lists:reverse([Element | Items]), advance(Ctx@1, Tokens@2)}}; _ -> unexpected(erlang:element(2, Ctx@1)) end end ) end. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 523). -spec tokenize(binary()) -> {ok, list({cel@parser@lexer:token(), cel@parser@lexer:position()})} | {error, error()}. tokenize(Source) -> Lexed = begin _pipe = cel@parser@lexer:new(Source), _pipe@1 = cel@parser@lexer:discard_comments(_pipe), _pipe@2 = cel@parser@lexer:discard_whitespace(_pipe@1), cel@parser@lexer:lex(_pipe@2) end, Check_last_token = case gleam@list:last(Lexed) of {ok, {{unexpected_grapheme, S}, {position, Offset, _}}} -> {error, {unexpected_source_str, S, Offset}}; {ok, {{unterminated_string, S@1}, {position, Offset@1, _}}} -> {error, {unexpected_source_str, S@1, Offset@1}}; {error, nil} -> {error, unexpected_end_of_file}; _ -> {ok, nil} end, gleam@result:map(Check_last_token, fun(_) -> Lexed end). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 135). -spec expression_loop(context(), list(binary_op()), list(expression_data())) -> {ok, {expression_data(), context()}} | {error, error()}. expression_loop(Ctx, Operators, Values) -> gleam@result:'try'( expression_unit(Ctx), fun(_use0) -> {Expr, Ctx@1} = _use0, Expr@2 = case Expr of none -> {error, {dead_end, erlang:element(2, Ctx@1)}}; {some, E} -> Values@1 = [E | Values], Binop = case erlang:element(2, Ctx@1) of [{Token, _} | Tokens] -> gleam@result:map( binary_operator(Token), fun(Op) -> {Op, advance(Ctx@1, Tokens)} end ); [] -> {error, nil} end, case Binop of {ok, {Operator, Ctx@2}} -> case handle_operator( Ctx@2, {some, Operator}, Operators, Values@1 ) of {{some, Expression}, _, _, Ctx@3} -> {ok, {Expression, Ctx@3}}; {none, Operators@1, Values@2, Ctx@4} -> expression_loop( Ctx@4, Operators@1, Values@2 ) end; _ -> {Expr@1, _, _, Ctx@5} = handle_operator( Ctx@1, none, Operators, Values@1 ), case Expr@1 of none -> {error, {dead_end, erlang:element(2, Ctx@5)}}; {some, Expression@1} -> {ok, {Expression@1, Ctx@5}} end end end, gleam@result:'try'( Expr@2, fun(_use0@1) -> {Expr@3, Ctx@6} = _use0@1, case erlang:element(2, Ctx@6) of [{question_mark, _} | Tokens@1] -> gleam@result:'try'( expression(advance(Ctx@6, Tokens@1)), fun(_use0@2) -> {Then, Ctx@7} = _use0@2, case erlang:element(2, Ctx@7) of [{colon, _} | Tokens@2] -> gleam@result:map( expression( advance(Ctx@7, Tokens@2) ), fun(_use0@3) -> {Otherwise, Ctx@8} = _use0@3, {Expr@4, Ctx@9} = begin _pipe = {ternary, Expr@3, Then, Otherwise}, make( _pipe, Ctx@8, erlang:element( 2, Ctx@8 ) ) end, {Expr@4, Ctx@9} end ); _ -> unexpected(erlang:element(2, Ctx@7)) end end ); _ -> {ok, {Expr@3, Ctx@6}} end end ) end ). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 127). -spec expression(context()) -> {ok, {expression_data(), context()}} | {error, error()}. expression(Ctx) -> expression_loop(Ctx, [], []). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 382). -spec map_field(context()) -> {ok, {{expression_data(), expression_data()}, context()}} | {error, error()}. map_field(Ctx) -> gleam@result:'try'( expression(Ctx), fun(_use0) -> {Key_expression, Ctx@1} = _use0, case erlang:element(2, Ctx@1) of [{colon, _} | Tokens] -> gleam@result:map( expression(advance(Ctx@1, Tokens)), fun(_use0@1) -> {Value_expression, Ctx@2} = _use0@1, {{Key_expression, Value_expression}, Ctx@2} end ); _ -> unexpected(erlang:element(2, Ctx@1)) end end ). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 541). -spec parse_(list({cel@parser@lexer:token(), cel@parser@lexer:position()})) -> {ok, expression_data()} | {error, error()}. parse_(Tokens) -> gleam@result:'try'( expression({ctx, Tokens, 0}), fun(_use0) -> {Expr, Rest} = _use0, case erlang:element(2, Rest) of [] -> {ok, Expr}; _ -> {error, {dead_end, erlang:element(2, Rest)}} end end ). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 550). -spec parse(binary()) -> {ok, expression_data()} | {error, error()}. parse(Source) -> _pipe = tokenize(Source), gleam@result:then(_pipe, fun parse_/1). -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 474). -spec call( context(), list(expression_data()), binary(), gleam@option:option(expression_data()) ) -> {ok, {expression_data(), context()}} | {error, error()}. call(Ctx, Arguments, Ident, This) -> case erlang:element(2, Ctx) of [] -> {error, unexpected_end_of_file}; [{right_paren, _} | Tokens] -> {Expr, Ctx@1} = begin _pipe = {function_call, Ident, This, lists:reverse(Arguments)}, make(_pipe, Ctx, Tokens) end, after_expression(Ctx@1, Expr); _ -> gleam@result:'try'( expression(Ctx), fun(_use0) -> {Argument, Ctx@2} = _use0, Arguments@1 = [Argument | Arguments], case erlang:element(2, Ctx@2) of [{comma, _} | Tokens@1] -> call( advance(Ctx@2, Tokens@1), Arguments@1, Ident, This ); [{right_paren, _} | Tokens@2] -> {Expr@1, Ctx@3} = begin _pipe@1 = {function_call, Ident, This, lists:reverse(Arguments@1)}, make(_pipe@1, Ctx@2, Tokens@2) end, after_expression(Ctx@3, Expr@1); _ -> unexpected(erlang:element(2, Ctx@2)) end end ) end. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 431). -spec after_expression(context(), expression_data()) -> {ok, {expression_data(), context()}} | {error, error()}. after_expression(Ctx, Parsed) -> case erlang:element(2, Ctx) of [{dot, _}, {{ident, Label}, _} | Tokens] -> {Expr, Ctx@1} = begin _pipe = {member, Parsed, {attribute, Label}}, make(_pipe, Ctx, Tokens) end, after_expression(Ctx@1, Expr); [{left_square, _} | Tokens@1] -> gleam@result:'try'( expression(advance(Ctx, Tokens@1)), fun(_use0) -> {Expression, Ctx@2} = _use0, case erlang:element(2, Ctx@2) of [{right_square, _} | Tokens@2] -> {Expr@1, Ctx@3} = begin _pipe@1 = {member, Parsed, {index, Expression}}, make(_pipe@1, Ctx@2, Tokens@2) end, {ok, {Expr@1, Ctx@3}}; _ -> unexpected(Tokens@1) end end ); [{left_paren, Pos} | Tokens@3] -> Ctx@4 = advance(Ctx, Tokens@3), case erlang:element(2, Parsed) of {ident, Ident} -> call(Ctx@4, [], Ident, none); {member, This, {attribute, Ident@1}} -> call(Ctx@4, [], Ident@1, {some, This}); _ -> {error, {unexpected_token, left_paren, erlang:element(2, Pos)}} end; _ -> {ok, {Parsed, Ctx}} end. -file("/Users/jonas/src/personal/cel-gleam/src/cel/parser.gleam", 261). -spec expression_unit(context()) -> {ok, {gleam@option:option(expression_data()), context()}} | {error, error()}. expression_unit(Ctx) -> gleam@result:'try'(case erlang:element(2, Ctx) of [{dot, _}, {{ident, Name}, _} | Tokens] -> {Expr, Ctx@1} = begin _pipe = {ident, Name}, make(_pipe, Ctx, Tokens) end, {ok, {{some, Expr}, Ctx@1}}; [{{ident, Name}, _} | Tokens] -> {Expr, Ctx@1} = begin _pipe = {ident, Name}, make(_pipe, Ctx, Tokens) end, {ok, {{some, Expr}, Ctx@1}}; [{{bool, Value}, _} | Tokens@1] -> {Expr@1, Ctx@2} = begin _pipe@1 = {atom, {bool, Value}}, make(_pipe@1, Ctx, Tokens@1) end, {ok, {{some, Expr@1}, Ctx@2}}; [{{int, Value@1}, _} | Tokens@2] -> _assert_subject = gleam_stdlib:parse_int(Value@1), {ok, N} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail, module => <<"cel/parser"/utf8>>, function => <<"expression_unit"/utf8>>, line => 277}) end, {Expr@2, Ctx@3} = begin _pipe@2 = {atom, {int, N}}, make(_pipe@2, Ctx, Tokens@2) end, {ok, {{some, Expr@2}, Ctx@3}}; [{{u_int, Value@2}, _} | Tokens@3] -> Excl_suffix = gleam@string:drop_end(Value@2, 1), _assert_subject@1 = gleam_stdlib:parse_int(Excl_suffix), {ok, N@1} = case _assert_subject@1 of {ok, _} -> _assert_subject@1; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail@1, module => <<"cel/parser"/utf8>>, function => <<"expression_unit"/utf8>>, line => 283}) end, {Expr@3, Ctx@4} = begin _pipe@3 = {atom, {u_int, N@1}}, make(_pipe@3, Ctx, Tokens@3) end, {ok, {{some, Expr@3}, Ctx@4}}; [{{float, Value@3}, _} | Tokens@4] -> _assert_subject@2 = gleam_stdlib:parse_float(Value@3), {ok, F} = case _assert_subject@2 of {ok, _} -> _assert_subject@2; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, value => _assert_fail@2, module => <<"cel/parser"/utf8>>, function => <<"expression_unit"/utf8>>, line => 288}) end, {Expr@4, Ctx@5} = begin _pipe@4 = {atom, {float, F}}, make(_pipe@4, Ctx, Tokens@4) end, {ok, {{some, Expr@4}, Ctx@5}}; [{{string, Value@4}, _} | Tokens@5] -> {Expr@5, Ctx@6} = begin _pipe@5 = {atom, {string, Value@4}}, make(_pipe@5, Ctx, Tokens@5) end, {ok, {{some, Expr@5}, Ctx@6}}; [{{bytes, Value@5}, _} | Tokens@6] -> {Expr@6, Ctx@7} = begin _pipe@6 = {atom, {bytes, Value@5}}, make(_pipe@6, Ctx, Tokens@6) end, {ok, {{some, Expr@6}, Ctx@7}}; [{left_square, _} | Tokens@7] -> gleam@result:map( list(advance(Ctx, Tokens@7), fun expression/1, none, []), fun(_use0) -> {Elements, Ctx@8} = _use0, {Expr@7, Ctx@9} = begin _pipe@7 = {list, Elements}, make(_pipe@7, Ctx@8, erlang:element(2, Ctx@8)) end, {{some, Expr@7}, Ctx@9} end ); [{left_curly, _} | Tokens@8] -> Result = comma_delimited( advance(Ctx, Tokens@8), [], fun map_field/1, right_curly ), gleam@result:map( Result, fun(_use0@1) -> {Fields, Ctx@10} = _use0@1, {Expr@8, Ctx@11} = begin _pipe@8 = {map, Fields}, make(_pipe@8, Ctx@10, erlang:element(2, Ctx@10)) end, {{some, Expr@8}, Ctx@11} end ); [{exclamation_mark, _} | Tokens@9] -> gleam@result:map( expression(advance(Ctx, Tokens@9)), fun(_use0@2) -> {Expression, Ctx@12} = _use0@2, {Expr@9, Ctx@13} = begin _pipe@9 = {unary, 'not', Expression}, make(_pipe@9, Ctx@12, erlang:element(2, Ctx@12)) end, {{some, Expr@9}, Ctx@13} end ); [{minus, _} | Tokens@10] -> gleam@result:map( expression(advance(Ctx, Tokens@10)), fun(_use0@3) -> {Expression@1, Ctx@14} = _use0@3, {Expr@10, Ctx@15} = begin _pipe@10 = {unary, unary_sub, Expression@1}, make(_pipe@10, Ctx@14, erlang:element(2, Ctx@14)) end, {{some, Expr@10}, Ctx@15} end ); [{left_paren, _} | Tokens@11] -> gleam@result:'try'( expression(advance(Ctx, Tokens@11)), fun(_use0@4) -> {Expression@2, Ctx@16} = _use0@4, case erlang:element(2, Ctx@16) of [{right_paren, _} | Tokens@12] -> {ok, {{some, Expression@2}, advance(Ctx@16, Tokens@12)}}; _ -> unexpected(Tokens@11) end end ); _ -> {ok, {none, Ctx}} end, fun(_use0@5) -> {Parsed, Ctx@17} = _use0@5, case Parsed of {some, Expression@3} -> _pipe@11 = after_expression(Ctx@17, Expression@3), gleam@result:map( _pipe@11, fun(Res) -> gleam@pair:map_first( Res, fun(Field@0) -> {some, Field@0} end ) end ); none -> {ok, {none, Ctx@17}} end end).