-module(chomp@pratt). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([sub_expression/2, expression/3, prefix/3, postfix/3, infix_left/3, infix_right/3]). -export_type([config/4, operator/4]). -opaque config(IHV, IHW, IHX, IHY) :: {config, list(fun((config(IHV, IHW, IHX, IHY)) -> chomp:parser(IHV, IHW, IHX, IHY))), IHW, list(operator(IHV, IHW, IHX, IHY))}. -opaque operator(IHZ, IIA, IIB, IIC) :: {operator, fun((config(IHZ, IIA, IIB, IIC)) -> {integer(), fun((IHZ) -> chomp:parser(IHZ, IIA, IIB, IIC))})}. -spec operation(IJL, config(IJL, IJM, IJN, IJO), integer()) -> chomp:parser(IJL, IJM, IJN, IJO). operation(Expr, Config, Current_precedence) -> _pipe = erlang:element(4, Config), _pipe@1 = gleam@list:filter_map( _pipe, fun(Operator) -> {operator, Op} = Operator, case Op(Config) of {Precedence, Parser} when Precedence > Current_precedence -> {ok, Parser(Expr)}; _ -> {error, nil} end end ), chomp:one_of(_pipe@1). -spec sub_expression(config(IIZ, IJA, IJB, IJC), integer()) -> chomp:parser(IIZ, IJA, IJB, IJC). sub_expression(Config, Precedence) -> Expr = (chomp:lazy(fun() -> _pipe = erlang:element(2, Config), _pipe@1 = gleam@list:map(_pipe, fun(P) -> P(Config) end), _pipe@2 = chomp:one_of(_pipe@1), chomp:or_error(_pipe@2, erlang:element(3, Config)) end)), Go = fun(Expr@1) -> chomp:one_of( [begin _pipe@3 = operation(Expr@1, Config, Precedence), chomp:map(_pipe@3, fun(Field@0) -> {continue, Field@0} end) end, begin _pipe@4 = chomp:return(Expr@1), chomp:map(_pipe@4, fun(Field@0) -> {break, Field@0} end) end] ) end, chomp:do(Expr, fun(E) -> chomp:loop(E, Go) end). -spec expression( list(fun((config(IID, IIE, IIF, IIG)) -> chomp:parser(IID, IIE, IIF, IIG))), IIE, list(operator(IID, IIE, IIF, IIG)) ) -> chomp:parser(IID, IIE, IIF, IIG). expression(First, Or_error, Then) -> Config = {config, First, Or_error, Then}, sub_expression(Config, 0). -spec prefix(integer(), chomp:parser(any(), IJY, IJZ, IKA), fun((IKF) -> IKF)) -> fun((config(IKF, IJY, IJZ, IKA)) -> chomp:parser(IKF, IJY, IJZ, IKA)). prefix(Precedence, Operator, Apply) -> fun(Config) -> chomp:do( Operator, fun(_) -> chomp:do( sub_expression(Config, Precedence), fun(Subexpr) -> chomp:return(Apply(Subexpr)) end ) end ) end. -spec postfix(integer(), chomp:parser(any(), ILP, ILQ, ILR), fun((ILW) -> ILW)) -> operator(ILW, ILP, ILQ, ILR). postfix(Precedence, Operator, Apply) -> {operator, fun(_) -> {Precedence, fun(Lhs) -> chomp:do(Operator, fun(_) -> chomp:return(Apply(Lhs)) end) end} end}. -spec make_infix( {integer(), integer()}, chomp:parser(any(), IMC, IMD, IME), fun((IMJ, IMJ) -> IMJ) ) -> operator(IMJ, IMC, IMD, IME). make_infix(Precedence, Operator, Apply) -> {Left_precedence, Right_precedence} = Precedence, {operator, fun(Config) -> {Left_precedence, fun(Lhs) -> chomp:do( Operator, fun(_) -> chomp:do( sub_expression(Config, Right_precedence), fun(Subexpr) -> chomp:return(Apply(Lhs, Subexpr)) end ) end ) end} end}. -spec infix_left( integer(), chomp:parser(any(), IKP, IKQ, IKR), fun((IKW, IKW) -> IKW) ) -> operator(IKW, IKP, IKQ, IKR). infix_left(Precedence, Operator, Apply) -> make_infix({Precedence, Precedence}, Operator, Apply). -spec infix_right( integer(), chomp:parser(any(), ILC, ILD, ILE), fun((ILJ, ILJ) -> ILJ) ) -> operator(ILJ, ILC, ILD, ILE). infix_right(Precedence, Operator, Apply) -> make_infix({Precedence, Precedence - 1}, Operator, Apply).