Packages

A CEL (Common Expression Language) parser and interpreter in pure Gleam

Current section

Files

Jump to
cel src cel@parser.erl
Raw

src/cel@parser.erl

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