Packages
caffeine_lang
6.1.0
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_lang@frontend@parser.erl
-module(caffeine_lang@frontend@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/frontend/parser.gleam").
-export([parse_measurements_file/1, parse_expects_file/1]).
-export_type([parser_state/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type parser_state() :: {parser_state,
list(caffeine_lang@frontend@token:positioned_token()),
integer(),
integer(),
integer(),
integer()}.
-file("src/caffeine_lang/frontend/parser.gleam", 143).
?DOC(" Consume current token and advance state.\n").
-spec advance(parser_state()) -> parser_state().
advance(State) ->
case erlang:element(2, State) of
[_ | Rest] ->
case Rest of
[{positioned_token, _, Line, Column} | _] ->
{parser_state,
Rest,
Line,
Column,
erlang:element(3, State),
erlang:element(4, State)};
[] ->
{parser_state,
Rest,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(3, State),
erlang:element(4, State)}
end;
[] ->
State
end.
-file("src/caffeine_lang/frontend/parser.gleam", 135).
?DOC(" Peek at the current token without consuming it.\n").
-spec peek(parser_state()) -> caffeine_lang@frontend@token:token().
peek(State) ->
case erlang:element(2, State) of
[{positioned_token, Tok, _, _} | _] ->
Tok;
[] ->
e_o_f
end.
-file("src/caffeine_lang/frontend/parser.gleam", 110).
-spec consume_comments_loop(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {list(caffeine_lang@frontend@ast:comment()), parser_state()}.
consume_comments_loop(State, Acc) ->
case peek(State) of
{comment_line, Text} ->
consume_comments_loop(advance(State), [{line_comment, Text} | Acc]);
{comment_section, Text@1} ->
consume_comments_loop(
advance(State),
[{section_comment, Text@1} | Acc]
);
{comment_doc, Text@2} ->
consume_comments_loop(advance(State), [{doc_comment, Text@2} | Acc]);
_ ->
{lists:reverse(Acc), State}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 106).
?DOC(" Consume consecutive comment tokens from the stream, returning them as Comment list.\n").
-spec consume_comments(parser_state()) -> {list(caffeine_lang@frontend@ast:comment()),
parser_state()}.
consume_comments(State) ->
consume_comments_loop(State, []).
-file("src/caffeine_lang/frontend/parser.gleam", 572).
-spec at_measurement_item_boundary(caffeine_lang@frontend@token:token()) -> boolean().
at_measurement_item_boundary(Tok) ->
case Tok of
{literal_string, _} ->
true;
e_o_f ->
true;
_ ->
false
end.
-file("src/caffeine_lang/frontend/parser.gleam", 558).
?DOC(
" Advance the state until `peek(state)` satisfies `predicate`.\n"
" Used by recovery loops to resync to the next item/block boundary.\n"
).
-spec skip_until(
parser_state(),
fun((caffeine_lang@frontend@token:token()) -> boolean())
) -> parser_state().
skip_until(State, Predicate) ->
case Predicate(peek(State)) of
true ->
State;
false ->
skip_until(advance(State), Predicate)
end.
-file("src/caffeine_lang/frontend/parser.gleam", 168).
?DOC(" Expect a specific token, consuming it if matched.\n").
-spec expect(parser_state(), caffeine_lang@frontend@token:token(), binary()) -> {ok,
parser_state()} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
expect(State, Expected, Expected_name) ->
case peek(State) of
Tok when Tok =:= Expected ->
{ok, advance(State)};
Tok@1 ->
{error,
{unexpected_token,
Expected_name,
caffeine_lang@frontend@token:to_string(Tok@1),
erlang:element(5, State),
erlang:element(6, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 691).
-spec parse_identifier(parser_state()) -> {ok, {binary(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_identifier(State) ->
case peek(State) of
{identifier, Name} ->
{ok, {Name, advance(State)}};
Tok ->
{error,
{unexpected_token,
<<"identifier"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 865).
?DOC(" Parse a type-alias reference (`_name`) or surface UnknownType for a bare identifier.\n").
-spec parse_type_alias_ref_or_error(parser_state(), binary()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_type_alias_ref_or_error(State, Name) ->
case gleam_stdlib:string_starts_with(Name, <<"_"/utf8>>) of
true ->
{ok, {{parsed_type_alias_ref, Name}, advance(State)}};
false ->
{error,
{unknown_type,
Name,
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 820).
-spec parse_field(
parser_state(),
list(caffeine_lang@frontend@ast:comment()),
fun((parser_state()) -> {ok,
{caffeine_lang@frontend@ast:value(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()})
) -> {ok, {caffeine_lang@frontend@ast:field(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_field(State, Leading_comments, Parse_value) ->
case peek(State) of
{identifier, Name} ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_colon, <<":"/utf8>>),
fun(State@2) ->
gleam@result:'try'(
Parse_value(State@2),
fun(_use0) ->
{Value, State@3} = _use0,
{ok,
{{field, Name, Value, Leading_comments},
State@3}}
end
)
end
);
{literal_string, Name@1} ->
{error,
{quoted_field_name,
Name@1,
erlang:element(3, State),
erlang:element(4, State)}};
Tok ->
{error,
{unexpected_token,
<<"field name"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 792).
-spec parse_fields_loop(
parser_state(),
list(caffeine_lang@frontend@ast:field()),
list(caffeine_lang@frontend@ast:comment()),
fun((parser_state()) -> {ok,
{caffeine_lang@frontend@ast:value(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()})
) -> {ok,
{list(caffeine_lang@frontend@ast:field()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_fields_loop(State, Acc, Pending, Parse_value) ->
case peek(State) of
symbol_comma ->
State@1 = advance(State),
{Next_pending, State@2} = consume_comments(State@1),
case peek(State@2) of
symbol_right_brace ->
{ok, {lists:reverse(Acc), Next_pending, State@2}};
_ ->
gleam@result:'try'(
parse_field(State@2, Next_pending, Parse_value),
fun(_use0) ->
{Field, State@3} = _use0,
{Next_pending@1, State@4} = consume_comments(
State@3
),
parse_fields_loop(
State@4,
[Field | Acc],
Next_pending@1,
Parse_value
)
end
)
end;
_ ->
{ok, {lists:reverse(Acc), Pending, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 767).
-spec parse_fields(
parser_state(),
list(caffeine_lang@frontend@ast:comment()),
fun((parser_state()) -> {ok,
{caffeine_lang@frontend@ast:value(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()})
) -> {ok,
{list(caffeine_lang@frontend@ast:field()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_fields(State, Pending, Parse_value) ->
case peek(State) of
symbol_right_brace ->
{ok, {[], Pending, State}};
{identifier, _} ->
gleam@result:'try'(
parse_field(State, Pending, Parse_value),
fun(_use0) ->
{Field, State@1} = _use0,
{Next_pending, State@2} = consume_comments(State@1),
parse_fields_loop(
State@2,
[Field],
Next_pending,
Parse_value
)
end
);
{literal_string, Name} ->
{error,
{quoted_field_name,
Name,
erlang:element(3, State),
erlang:element(4, State)}};
Tok ->
{error,
{unexpected_token,
<<"field name or }"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 752).
?DOC(" Generic struct parser parameterized by field value parser.\n").
-spec parse_struct(
parser_state(),
fun((parser_state()) -> {ok,
{caffeine_lang@frontend@ast:value(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()})
) -> {ok, {caffeine_lang@frontend@ast:struct(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_struct(State, Parse_value) ->
gleam@result:'try'(
expect(State, symbol_left_brace, <<"{"/utf8>>),
fun(State@1) ->
{Pending, State@2} = consume_comments(State@1),
gleam@result:'try'(
parse_fields(State@2, Pending, Parse_value),
fun(_use0) ->
{Fields, Trailing_comments, State@3} = _use0,
gleam@result:'try'(
expect(State@3, symbol_right_brace, <<"}"/utf8>>),
fun(State@4) ->
{ok, {{struct, Fields, Trailing_comments}, State@4}}
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1295).
?DOC(
" Convert a Literal to its string representation for use in refinements/defaults.\n"
" List literals are serialized as \"[a, b, c]\" using the same element format as\n"
" types.gleam's value-to-string, so list defaults can be round-tripped at the\n"
" resolver. Round-trip via comma-split does not preserve commas embedded inside\n"
" individual string elements.\n"
).
-spec literal_to_string(caffeine_lang@frontend@ast:literal()) -> binary().
literal_to_string(Literal) ->
case Literal of
{literal_string, S} ->
S;
{literal_integer, N} ->
erlang:integer_to_binary(N);
{literal_float, F} ->
gleam_stdlib:float_to_string(F);
{literal_percentage, F@1} ->
<<(gleam_stdlib:float_to_string(F@1))/binary, "%"/utf8>>;
{literal_duration, Amount, Unit} ->
<<(gleam_stdlib:float_to_string(Amount))/binary, Unit/binary>>;
literal_true ->
<<"true"/utf8>>;
literal_false ->
<<"false"/utf8>>;
{literal_list, Elements} ->
<<<<"["/utf8,
(begin
_pipe = Elements,
_pipe@1 = gleam@list:map(_pipe, fun literal_to_string/1),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end)/binary>>/binary,
"]"/utf8>>;
{literal_struct, _, _} ->
<<"{}"/utf8>>;
{literal_external_indicator, Source, _, _} ->
<<<<"<from "/utf8, Source/binary>>/binary, ">"/utf8>>
end.
-file("src/caffeine_lang/frontend/parser.gleam", 708).
?DOC(
" Consume `, item , item ...` until a non-comma token. Does not allow\n"
" trailing commas (the parse_one callback runs after every comma).\n"
).
-spec sep_by_comma(
parser_state(),
list(LTF),
fun((parser_state()) -> {ok, {LTF, parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()})
) -> {ok, {list(LTF), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
sep_by_comma(State, Acc, Parse_one) ->
case peek(State) of
symbol_comma ->
State@1 = advance(State),
gleam@result:'try'(
Parse_one(State@1),
fun(_use0) ->
{Item, State@2} = _use0,
sep_by_comma(State@2, [Item | Acc], Parse_one)
end
);
_ ->
{ok, {lists:reverse(Acc), State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1049).
-spec expect_x(parser_state()) -> {ok, parser_state()} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
expect_x(State) ->
case peek(State) of
keyword_x ->
{ok, advance(State)};
Tok ->
{error,
{invalid_refinement,
<<"expected 'x', got "/utf8,
(caffeine_lang@frontend@token:to_string(Tok))/binary>>,
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 850).
?DOC(" Match a primitive type keyword and consume it. Returns Error(Nil) on miss.\n").
-spec try_parse_primitive_keyword(parser_state()) -> {ok,
{caffeine_lang@types:primitive_types(), parser_state()}} |
{error, nil}.
try_parse_primitive_keyword(State) ->
case peek(State) of
keyword_string ->
{ok, {string, advance(State)}};
keyword_integer ->
{ok, {{numeric_type, integer}, advance(State)}};
keyword_float ->
{ok, {{numeric_type, float}, advance(State)}};
keyword_boolean ->
{ok, {boolean, advance(State)}};
keyword_u_r_l ->
{ok, {{semantic_type, u_r_l}, advance(State)}};
keyword_percentage ->
{ok, {{numeric_type, percentage}, advance(State)}};
_ ->
{error, nil}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 973).
?DOC(
" Parses types valid as Dict keys: String primitive or type alias ref.\n"
" Only String is allowed as a primitive key (JSON keys must be strings).\n"
).
-spec parse_dict_key_type(parser_state()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_dict_key_type(State) ->
case peek(State) of
keyword_string ->
{ok, {{parsed_primitive, string}, advance(State)}};
{identifier, Name} ->
parse_type_alias_ref_or_error(State, Name);
Tok ->
{error,
{unknown_type,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1223).
?DOC(
" Parse `<field> = <literal>`. The field name is an identifier; the value\n"
" is a literal that supports `$$var$$` template interpolation via the\n"
" normal literal parser.\n"
).
-spec parse_match_clause(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:match_clause(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_match_clause(State) ->
gleam@result:'try'(
parse_identifier(State),
fun(_use0) ->
{Field, State@1} = _use0,
gleam@result:'try'(
expect(State@1, symbol_equals, <<"="/utf8>>),
fun(State@2) ->
gleam@result:'try'(
parse_literal(State@2),
fun(_use0@1) ->
{Value, State@3} = _use0@1,
{ok, {{match_clause, Field, Value}, State@3}}
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1206).
-spec parse_match_chain_loop(
parser_state(),
list(caffeine_lang@frontend@ast:match_clause())
) -> {ok, {list(caffeine_lang@frontend@ast:match_clause()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_match_chain_loop(State, Acc) ->
case peek(State) of
keyword_and ->
State@1 = advance(State),
gleam@result:'try'(
parse_match_clause(State@1),
fun(_use0) ->
{Clause, State@2} = _use0,
parse_match_chain_loop(State@2, [Clause | Acc])
end
);
_ ->
{ok, {lists:reverse(Acc), State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1199).
?DOC(
" Parse a chain of one or more match clauses separated by `and`. Stops at\n"
" the first non-`and` token. Returns the chain in source order.\n"
).
-spec parse_match_chain(parser_state()) -> {ok,
{list(caffeine_lang@frontend@ast:match_clause()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_match_chain(State) ->
gleam@result:'try'(
parse_match_clause(State),
fun(_use0) ->
{First, State@1} = _use0,
parse_match_chain_loop(State@1, [First])
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1190).
?DOC(
" Parse a `where <chain>` clause: consumes `where`, then one or more\n"
" `and`-separated match clauses. Used by the single-line surface form.\n"
).
-spec parse_where_chain(parser_state()) -> {ok,
{list(caffeine_lang@frontend@ast:match_clause()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_where_chain(State) ->
gleam@result:'try'(
expect(State, keyword_where, <<"where"/utf8>>),
fun(State@1) -> parse_match_chain(State@1) end
).
-file("src/caffeine_lang/frontend/parser.gleam", 732).
?DOC(" Parses a struct with typed fields (for Requires blocks).\n").
-spec parse_type_struct(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:struct(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_type_struct(State) ->
parse_struct(
State,
fun(S) ->
gleam@result:'try'(
parse_type(S),
fun(_use0) ->
{Type_, S@1} = _use0,
{ok, {{type_value, Type_}, S@1}}
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 910).
?DOC(
" Parses a record type: `{ field: Type, ... }`.\n"
" Reuses parse_type_struct to parse the struct, then converts fields to a dict.\n"
).
-spec parse_record_type(parser_state()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_record_type(State) ->
gleam@result:'try'(
parse_type_struct(State),
fun(_use0) ->
{S, State@1} = _use0,
Fields = begin
_pipe = erlang:element(2, S),
_pipe@1 = gleam@list:map(
_pipe,
fun(Field) ->
T@1 = case erlang:element(3, Field) of
{type_value, T} -> T;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"caffeine_lang/frontend/parser"/utf8>>,
function => <<"parse_record_type"/utf8>>,
line => 917,
value => _assert_fail,
start => 30056,
'end' => 30097,
pattern_start => 30067,
pattern_end => 30083})
end,
{erlang:element(2, Field), T@1}
end
),
maps:from_list(_pipe@1)
end,
{ok, {{parsed_record, Fields}, State@1}}
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1260).
-spec parse_literal_list_contents(parser_state()) -> {ok,
{list(caffeine_lang@frontend@ast:literal()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_literal_list_contents(State) ->
case peek(State) of
symbol_right_bracket ->
{ok, {[], State}};
symbol_right_brace ->
{ok, {[], State}};
_ ->
gleam@result:'try'(
parse_literal(State),
fun(_use0) ->
{First, State@1} = _use0,
sep_by_comma(State@1, [First], fun parse_literal/1)
end
)
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1061).
-spec parse_refinement_body(parser_state(), caffeine_lang@types:parsed_type()) -> {ok,
{caffeine_lang@types:refinement_types(caffeine_lang@types:parsed_type()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_refinement_body(State, Inner) ->
case peek(State) of
symbol_left_brace ->
State@1 = advance(State),
gleam@result:'try'(
parse_literal_list_contents(State@1),
fun(_use0) ->
{Values, State@2} = _use0,
gleam@result:'try'(
expect(State@2, symbol_right_brace, <<"}"/utf8>>),
fun(State@3) ->
String_values = gleam@list:map(
Values,
fun literal_to_string/1
),
{ok,
{{one_of,
Inner,
gleam@set:from_list(String_values)},
State@3}}
end
)
end
);
symbol_left_paren ->
State@4 = advance(State),
gleam@result:'try'(
parse_literal(State@4),
fun(_use0@1) ->
{Min, State@5} = _use0@1,
gleam@result:'try'(
expect(State@5, symbol_dot_dot, <<".."/utf8>>),
fun(State@6) ->
gleam@result:'try'(
parse_literal(State@6),
fun(_use0@2) ->
{Max, State@7} = _use0@2,
gleam@result:'try'(
expect(
State@7,
symbol_right_paren,
<<")"/utf8>>
),
fun(State@8) ->
{ok,
{{inclusive_range,
Inner,
literal_to_string(Min),
literal_to_string(Max)},
State@8}}
end
)
end
)
end
)
end
);
Tok ->
{error,
{unexpected_token,
<<"{ or ("/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1035).
?DOC(
" Parse `{ x | x in <body> }` wrapping an arbitrary inner type. Shared\n"
" implementation for primitive refinements and Defaulted-with-refinement.\n"
).
-spec parse_refinement_with_inner(
parser_state(),
caffeine_lang@types:parsed_type()
) -> {ok,
{caffeine_lang@types:refinement_types(caffeine_lang@types:parsed_type()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_refinement_with_inner(State, Inner) ->
gleam@result:'try'(
expect(State, symbol_left_brace, <<"{"/utf8>>),
fun(State@1) ->
gleam@result:'try'(
expect_x(State@1),
fun(State@2) ->
gleam@result:'try'(
expect(State@2, symbol_pipe, <<"|"/utf8>>),
fun(State@3) ->
gleam@result:'try'(
expect_x(State@3),
fun(State@4) ->
gleam@result:'try'(
expect(
State@4,
keyword_in,
<<"in"/utf8>>
),
fun(State@5) ->
gleam@result:'try'(
parse_refinement_body(
State@5,
Inner
),
fun(_use0) ->
{Refinement, State@6} = _use0,
gleam@result:'try'(
expect(
State@6,
symbol_right_brace,
<<"}"/utf8>>
),
fun(State@7) ->
{ok,
{Refinement,
State@7}}
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 998).
-spec parse_defaulted_type(parser_state()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_defaulted_type(State) ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_left_paren, <<"("/utf8>>),
fun(State@2) ->
gleam@result:'try'(
parse_type(State@2),
fun(_use0) ->
{Inner, State@3} = _use0,
gleam@result:'try'(
expect(State@3, symbol_comma, <<","/utf8>>),
fun(State@4) ->
gleam@result:'try'(
parse_literal(State@4),
fun(_use0@1) ->
{Default, State@5} = _use0@1,
gleam@result:'try'(
expect(
State@5,
symbol_right_paren,
<<")"/utf8>>
),
fun(State@6) ->
Defaulted = {parsed_modifier,
{defaulted,
Inner,
literal_to_string(Default)}},
case peek(State@6) of
symbol_left_brace ->
gleam@result:'try'(
parse_refinement_with_inner(
State@6,
Defaulted
),
fun(_use0@2) ->
{Refinement,
State@7} = _use0@2,
{ok,
{{parsed_refinement,
Refinement},
State@7}}
end
);
_ ->
{ok, {Defaulted, State@6}}
end
end
)
end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 988).
-spec parse_optional_type(parser_state()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_optional_type(State) ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_left_paren, <<"("/utf8>>),
fun(State@2) ->
gleam@result:'try'(
parse_type(State@2),
fun(_use0) ->
{Inner, State@3} = _use0,
gleam@result:'try'(
expect(State@3, symbol_right_paren, <<")"/utf8>>),
fun(State@4) ->
{ok,
{{parsed_modifier, {optional, Inner}}, State@4}}
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 947).
-spec parse_list_type(parser_state()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_list_type(State) ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_left_paren, <<"("/utf8>>),
fun(State@2) ->
gleam@result:'try'(
parse_collection_inner_type(State@2),
fun(_use0) ->
{Element, State@3} = _use0,
gleam@result:'try'(
expect(State@3, symbol_right_paren, <<")"/utf8>>),
fun(State@4) ->
{ok,
{{parsed_collection, {list, Element}}, State@4}}
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 926).
?DOC(
" Parses types valid inside collections: primitives, nested collections, or type alias refs.\n"
" Does not allow modifiers (Optional/Defaulted) or refinements directly.\n"
).
-spec parse_collection_inner_type(parser_state()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_collection_inner_type(State) ->
case try_parse_primitive_keyword(State) of
{ok, {Primitive, State@1}} ->
{ok, {{parsed_primitive, Primitive}, State@1}};
{error, _} ->
case peek(State) of
keyword_list ->
parse_list_type(State);
keyword_dict ->
parse_dict_type(State);
symbol_left_brace ->
parse_record_type(State);
{identifier, Name} ->
parse_type_alias_ref_or_error(State, Name);
Tok ->
{error,
{unknown_type,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end
end.
-file("src/caffeine_lang/frontend/parser.gleam", 957).
-spec parse_dict_type(parser_state()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_dict_type(State) ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_left_paren, <<"("/utf8>>),
fun(State@2) ->
gleam@result:'try'(
parse_dict_key_type(State@2),
fun(_use0) ->
{Key, State@3} = _use0,
gleam@result:'try'(
expect(State@3, symbol_comma, <<","/utf8>>),
fun(State@4) ->
gleam@result:'try'(
parse_collection_inner_type(State@4),
fun(_use0@1) ->
{Value, State@5} = _use0@1,
gleam@result:'try'(
expect(
State@5,
symbol_right_paren,
<<")"/utf8>>
),
fun(State@6) ->
{ok,
{{parsed_collection,
{dict, Key, Value}},
State@6}}
end
)
end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1026).
?DOC(" Parse `{ x | x in <body> }` for a primitive base type.\n").
-spec parse_refinement(parser_state(), caffeine_lang@types:primitive_types()) -> {ok,
{caffeine_lang@types:refinement_types(caffeine_lang@types:parsed_type()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_refinement(State, Primitive) ->
parse_refinement_with_inner(State, {parsed_primitive, Primitive}).
-file("src/caffeine_lang/frontend/parser.gleam", 875).
-spec parse_type(parser_state()) -> {ok,
{caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_type(State) ->
case try_parse_primitive_keyword(State) of
{ok, {Primitive, State@1}} ->
case peek(State@1) of
symbol_left_brace ->
gleam@result:'try'(
parse_refinement(State@1, Primitive),
fun(_use0) ->
{Refinement, State@2} = _use0,
{ok, {{parsed_refinement, Refinement}, State@2}}
end
);
_ ->
{ok, {{parsed_primitive, Primitive}, State@1}}
end;
{error, _} ->
case peek(State) of
keyword_list ->
parse_list_type(State);
keyword_dict ->
parse_dict_type(State);
keyword_optional ->
parse_optional_type(State);
keyword_defaulted ->
parse_defaulted_type(State);
symbol_left_brace ->
parse_record_type(State);
{identifier, Name} ->
parse_type_alias_ref_or_error(State, Name);
Tok ->
{error,
{unknown_type,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1235).
?DOC(
" Parse `value: <path> as <type>` if present (block form only). Returns\n"
" None if the next token isn't an Identifier opening the value-extraction\n"
" line, so callers can fall through to `}`.\n"
).
-spec parse_optional_value_extraction(parser_state()) -> {ok,
{gleam@option:option(caffeine_lang@frontend@ast:value_extraction()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_optional_value_extraction(State) ->
case peek(State) of
{identifier, <<"value"/utf8>>} ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_colon, <<":"/utf8>>),
fun(State@2) ->
gleam@result:'try'(
parse_identifier(State@2),
fun(_use0) ->
{Path, State@3} = _use0,
gleam@result:'try'(
expect(State@3, keyword_as, <<"as"/utf8>>),
fun(State@4) ->
gleam@result:'try'(
parse_type(State@4),
fun(_use0@1) ->
{Type_, State@5} = _use0@1,
{ok,
{{some,
{value_extraction,
Path,
Type_}},
State@5}}
end
)
end
)
end
)
end
);
_ ->
{ok, {none, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1173).
?DOC(
" Parse `{ where: <chain> [value: <path> as <type>] }`. Requires `where:`\n"
" to come first; `value:` is optional. The block form is what enables\n"
" value extraction; the single-line form is sugar for the where-only case.\n"
).
-spec parse_external_indicator_block(parser_state(), binary()) -> {ok,
{caffeine_lang@frontend@ast:literal(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_external_indicator_block(State, Source) ->
gleam@result:'try'(
expect(State, symbol_left_brace, <<"{"/utf8>>),
fun(State@1) ->
gleam@result:'try'(
expect(State@1, keyword_where, <<"where"/utf8>>),
fun(State@2) ->
gleam@result:'try'(
expect(State@2, symbol_colon, <<":"/utf8>>),
fun(State@3) ->
gleam@result:'try'(
parse_match_chain(State@3),
fun(_use0) ->
{Match, State@4} = _use0,
gleam@result:'try'(
parse_optional_value_extraction(State@4),
fun(_use0@1) ->
{Value_extraction, State@5} = _use0@1,
gleam@result:'try'(
expect(
State@5,
symbol_right_brace,
<<"}"/utf8>>
),
fun(State@6) ->
{ok,
{{literal_external_indicator,
Source,
Match,
Value_extraction},
State@6}}
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1149).
?DOC(
" Parse a `from <source> ...` external-indicator literal. Dispatches on the\n"
" token after the source identifier: `{` opens the block form, `where`\n"
" starts the single-line form.\n"
).
-spec parse_external_indicator(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:literal(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_external_indicator(State) ->
gleam@result:'try'(
expect(State, keyword_from, <<"from"/utf8>>),
fun(State@1) ->
gleam@result:'try'(
parse_identifier(State@1),
fun(_use0) ->
{Source, State@2} = _use0,
case peek(State@2) of
symbol_left_brace ->
parse_external_indicator_block(State@2, Source);
keyword_where ->
gleam@result:'try'(
parse_where_chain(State@2),
fun(_use0@1) ->
{Match, State@3} = _use0@1,
{ok,
{{literal_external_indicator,
Source,
Match,
none},
State@3}}
end
);
Tok ->
{error,
{unexpected_token,
<<<<"`where` or `{` after `from "/utf8,
Source/binary>>/binary,
"`"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State@2),
erlang:element(4, State@2)}}
end
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1272).
-spec parse_literal_struct_value(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:literal(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_literal_struct_value(State) ->
Parse_value = fun(S) ->
gleam@result:'try'(
parse_literal(S),
fun(_use0) ->
{Literal, S@1} = _use0,
{ok, {{literal_value, Literal}, S@1}}
end
)
end,
gleam@result:'try'(
expect(State, symbol_left_brace, <<"{"/utf8>>),
fun(State@1) ->
{Pending, State@2} = consume_comments(State@1),
gleam@result:'try'(
parse_fields(State@2, Pending, Parse_value),
fun(_use0@1) ->
{Fields, Trailing_comments, State@3} = _use0@1,
gleam@result:'try'(
expect(State@3, symbol_right_brace, <<"}"/utf8>>),
fun(State@4) ->
{ok,
{{literal_struct, Fields, Trailing_comments},
State@4}}
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1251).
-spec parse_literal_list(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:literal(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_literal_list(State) ->
gleam@result:'try'(
expect(State, symbol_left_bracket, <<"["/utf8>>),
fun(State@1) ->
gleam@result:'try'(
parse_literal_list_contents(State@1),
fun(_use0) ->
{Elements, State@2} = _use0,
gleam@result:'try'(
expect(State@2, symbol_right_bracket, <<"]"/utf8>>),
fun(State@3) ->
{ok, {{literal_list, Elements}, State@3}}
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1100).
-spec parse_literal(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:literal(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_literal(State) ->
case peek(State) of
{literal_string, S} ->
{ok, {{literal_string, S}, advance(State)}};
{literal_integer, N} ->
{ok, {{literal_integer, N}, advance(State)}};
{literal_float, F} ->
{ok, {{literal_float, F}, advance(State)}};
{literal_percentage, F@1} ->
{ok, {{literal_percentage, F@1}, advance(State)}};
{literal_duration, Amount, Unit} ->
{ok, {{literal_duration, Amount, Unit}, advance(State)}};
literal_true ->
{ok, {literal_true, advance(State)}};
literal_false ->
{ok, {literal_false, advance(State)}};
symbol_left_bracket ->
parse_literal_list(State);
symbol_left_brace ->
parse_literal_struct_value(State);
keyword_from ->
parse_external_indicator(State);
Tok ->
{error,
{unexpected_token,
<<"literal value"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 742).
?DOC(" Parses a struct with literal fields (for Provides blocks).\n").
-spec parse_literal_struct(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:struct(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_literal_struct(State) ->
parse_struct(
State,
fun(S) ->
gleam@result:'try'(
parse_literal(S),
fun(_use0) ->
{Literal, S@1} = _use0,
{ok, {{literal_value, Literal}, S@1}}
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 679).
-spec parse_extends_list(parser_state()) -> {ok,
{list(binary()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_extends_list(State) ->
case peek(State) of
symbol_right_bracket ->
{ok, {[], State}};
_ ->
gleam@result:'try'(
parse_identifier(State),
fun(_use0) ->
{First, State@1} = _use0,
sep_by_comma(State@1, [First], fun parse_identifier/1)
end
)
end.
-file("src/caffeine_lang/frontend/parser.gleam", 664).
-spec parse_optional_extends(parser_state()) -> {ok,
{list(binary()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_optional_extends(State) ->
case peek(State) of
keyword_extends ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_left_bracket, <<"["/utf8>>),
fun(State@2) ->
gleam@result:'try'(
parse_extends_list(State@2),
fun(_use0) ->
{Extends, State@3} = _use0,
gleam@result:'try'(
expect(
State@3,
symbol_right_bracket,
<<"]"/utf8>>
),
fun(State@4) -> {ok, {Extends, State@4}} end
)
end
)
end
);
_ ->
{ok, {[], State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 384).
?DOC(
" Recognises an optional `success_rate` or `time_slice` keyword in the\n"
" measurement header, e.g. `\"api\" success_rate:` or `\"api\" time_slice:`.\n"
" Returns None if the next token is `:` or `extends` (legacy untyped header).\n"
).
-spec parse_optional_expectation_type(parser_state()) -> {ok,
{gleam@option:option(caffeine_lang@frontend@ast:expectation_type()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_optional_expectation_type(State) ->
case peek(State) of
keyword_success_rate ->
{ok, {{some, success_rate_type}, advance(State)}};
keyword_time_slice ->
{ok, {{some, time_slice_type}, advance(State)}};
_ ->
{ok, {none, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 649).
-spec parse_string_literal(parser_state()) -> {ok, {binary(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_string_literal(State) ->
case peek(State) of
{literal_string, S} ->
{ok, {S, advance(State)}};
Tok ->
{error,
{unexpected_token,
<<"string"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 345).
-spec parse_measurement_item(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {ok, {caffeine_lang@frontend@ast:measurement_item(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_measurement_item(State, Leading_comments) ->
gleam@result:'try'(
parse_string_literal(State),
fun(_use0) ->
{Name, State@1} = _use0,
gleam@result:'try'(
parse_optional_expectation_type(State@1),
fun(_use0@1) ->
{Expectation_type, State@2} = _use0@1,
gleam@result:'try'(
parse_optional_extends(State@2),
fun(_use0@2) ->
{Extends, State@3} = _use0@2,
gleam@result:'try'(
expect(State@3, symbol_colon, <<":"/utf8>>),
fun(State@4) ->
{_, State@5} = consume_comments(State@4),
gleam@result:'try'(case peek(State@5) of
keyword_requires ->
State@6 = advance(State@5),
parse_type_struct(State@6);
_ ->
{ok,
{{struct, [], []}, State@5}}
end, fun(_use0@3) ->
{Requires, State@7} = _use0@3,
{_, State@8} = consume_comments(
State@7
),
gleam@result:'try'(
expect(
State@8,
keyword_provides,
<<"Provides"/utf8>>
),
fun(State@9) ->
gleam@result:'try'(
parse_literal_struct(
State@9
),
fun(_use0@4) ->
{Provides, State@10} = _use0@4,
{ok,
{{measurement_item,
Name,
Expectation_type,
Extends,
Requires,
Provides,
Leading_comments},
State@10}}
end
)
end
)
end)
end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 588).
-spec measurement_items_loop(
parser_state(),
list(caffeine_lang@frontend@ast:measurement_item()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment())
) -> {list(caffeine_lang@frontend@ast:measurement_item()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}.
measurement_items_loop(State, Items, Errors, Pending) ->
case peek(State) of
{literal_string, _} ->
case parse_measurement_item(State, Pending) of
{ok, {Item, State@1}} ->
{Next_pending, State@2} = consume_comments(State@1),
measurement_items_loop(
State@2,
[Item | Items],
Errors,
Next_pending
);
{error, Err} ->
State@3 = skip_until(
advance(State),
fun at_measurement_item_boundary/1
),
{Next_pending@1, State@4} = consume_comments(State@3),
measurement_items_loop(
State@4,
Items,
[Err | Errors],
Next_pending@1
)
end;
_ ->
{lists:reverse(Items), lists:reverse(Errors), Pending, State}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 581).
?DOC(
" Parse measurement items with recovery between items.\n"
" Measurement items start with a string literal name.\n"
).
-spec parse_measurement_items_recovering(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {list(caffeine_lang@frontend@ast:measurement_item()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}.
parse_measurement_items_recovering(State, Pending) ->
measurement_items_loop(State, [], [], Pending).
-file("src/caffeine_lang/frontend/parser.gleam", 325).
-spec parse_extendable_kind(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:extendable_kind(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_extendable_kind(State) ->
case peek(State) of
keyword_requires ->
{ok, {extendable_requires, advance(State)}};
keyword_provides ->
{ok, {extendable_provides, advance(State)}};
Tok ->
{error,
{unexpected_token,
<<"Type, Requires, or Provides"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 307).
-spec parse_extendable(
parser_state(),
binary(),
list(caffeine_lang@frontend@ast:comment())
) -> {ok, {caffeine_lang@frontend@ast:extendable(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_extendable(State, Name, Leading_comments) ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_left_paren, <<"("/utf8>>),
fun(State@2) ->
gleam@result:'try'(
parse_extendable_kind(State@2),
fun(_use0) ->
{Kind, State@3} = _use0,
gleam@result:'try'(
expect(State@3, symbol_right_paren, <<")"/utf8>>),
fun(State@4) ->
gleam@result:'try'(
expect(State@4, symbol_colon, <<":"/utf8>>),
fun(State@5) -> gleam@result:'try'(case Kind of
extendable_requires ->
parse_type_struct(State@5);
extendable_provides ->
parse_literal_struct(State@5)
end, fun(_use0@1) ->
{Body, State@6} = _use0@1,
{ok,
{{extendable,
Name,
Kind,
Body,
Leading_comments},
State@6}}
end) end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 288).
-spec parse_extendables_loop(
parser_state(),
list(caffeine_lang@frontend@ast:extendable()),
list(caffeine_lang@frontend@ast:comment())
) -> {ok,
{list(caffeine_lang@frontend@ast:extendable()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_extendables_loop(State, Acc, Pending) ->
case peek(State) of
{identifier, Name} ->
gleam@result:'try'(
parse_extendable(State, Name, Pending),
fun(_use0) ->
{Extendable, State@1} = _use0,
{Next_pending, State@2} = consume_comments(State@1),
parse_extendables_loop(
State@2,
[Extendable | Acc],
Next_pending
)
end
);
_ ->
{ok, {lists:reverse(Acc), Pending, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 281).
?DOC(" Parse zero or more extendables at file start.\n").
-spec parse_extendables(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {ok,
{list(caffeine_lang@frontend@ast:extendable()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_extendables(State, Pending) ->
parse_extendables_loop(State, [], Pending).
-file("src/caffeine_lang/frontend/parser.gleam", 237).
-spec parse_type_alias(
parser_state(),
binary(),
list(caffeine_lang@frontend@ast:comment())
) -> {ok, {caffeine_lang@frontend@ast:type_alias(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_type_alias(State, Name, Leading_comments) ->
case Name of
<<"_"/utf8>> ->
{error,
{invalid_type_alias_name,
Name,
<<"type alias name must have at least one character after the underscore"/utf8>>,
erlang:element(3, State),
erlang:element(4, State)}};
_ ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_left_paren, <<"("/utf8>>),
fun(State@2) -> case peek(State@2) of
keyword_type ->
State@3 = advance(State@2),
gleam@result:'try'(
expect(
State@3,
symbol_right_paren,
<<")"/utf8>>
),
fun(State@4) ->
gleam@result:'try'(
expect(
State@4,
symbol_colon,
<<":"/utf8>>
),
fun(State@5) ->
gleam@result:'try'(
parse_type(State@5),
fun(_use0) ->
{Type_, State@6} = _use0,
{ok,
{{type_alias,
Name,
Type_,
Leading_comments},
State@6}}
end
)
end
)
end
);
Tok ->
{error,
{unexpected_token,
<<"Type"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State@2),
erlang:element(4, State@2)}}
end end
)
end.
-file("src/caffeine_lang/frontend/parser.gleam", 225).
?DOC(
" Check if current position is a type alias definition.\n"
" Looks for pattern: Identifier ( KeywordType )\n"
).
-spec is_type_alias(parser_state()) -> boolean().
is_type_alias(State) ->
case erlang:element(2, State) of
[{positioned_token, {identifier, _}, _, _},
{positioned_token, symbol_left_paren, _, _},
{positioned_token, keyword_type, _, _} |
_] ->
true;
_ ->
false
end.
-file("src/caffeine_lang/frontend/parser.gleam", 198).
-spec parse_type_aliases_loop(
parser_state(),
list(caffeine_lang@frontend@ast:type_alias()),
list(caffeine_lang@frontend@ast:comment())
) -> {ok,
{list(caffeine_lang@frontend@ast:type_alias()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_type_aliases_loop(State, Acc, Pending) ->
case peek(State) of
{identifier, Name} ->
case is_type_alias(State) of
true ->
gleam@result:'try'(
parse_type_alias(State, Name, Pending),
fun(_use0) ->
{Type_alias, State@1} = _use0,
{Next_pending, State@2} = consume_comments(State@1),
parse_type_aliases_loop(
State@2,
[Type_alias | Acc],
Next_pending
)
end
);
false ->
{ok, {lists:reverse(Acc), Pending, State}}
end;
_ ->
{ok, {lists:reverse(Acc), Pending, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 191).
?DOC(
" Parse zero or more type aliases at file start.\n"
" Type alias syntax: _name (Type): <refinement_type>\n"
).
-spec parse_type_aliases(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {ok,
{list(caffeine_lang@frontend@ast:type_alias()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_type_aliases(State, Pending) ->
parse_type_aliases_loop(State, [], Pending).
-file("src/caffeine_lang/frontend/parser.gleam", 126).
?DOC(" Initialize parser state from a list of positioned tokens.\n").
-spec init_state(list(caffeine_lang@frontend@token:positioned_token())) -> parser_state().
init_state(Tokens) ->
case Tokens of
[{positioned_token, _, Line, Column} | _] ->
{parser_state, Tokens, Line, Column, Line, Column};
[] ->
{parser_state, Tokens, 1, 1, 1, 1}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 95).
?DOC(" Filter out whitespace tokens (keep comments in stream).\n").
-spec filter_whitespace(list(caffeine_lang@frontend@token:positioned_token())) -> list(caffeine_lang@frontend@token:positioned_token()).
filter_whitespace(Tokens) ->
gleam@list:filter(Tokens, fun(Ptok) -> case Ptok of
{positioned_token, whitespace_newline, _, _} ->
false;
{positioned_token, {whitespace_indent, _}, _, _} ->
false;
_ ->
true
end end).
-file("src/caffeine_lang/frontend/parser.gleam", 38).
?DOC(
" Parses a measurements file from source text.\n"
" Returns all recoverable parse errors rather than stopping at the first one.\n"
).
-spec parse_measurements_file(binary()) -> {ok,
caffeine_lang@frontend@ast:measurements_file(caffeine_lang@frontend@ast:parsed())} |
{error, list(caffeine_lang@frontend@parser_error:parser_error())}.
parse_measurements_file(Source) ->
gleam@result:'try'(
begin
_pipe = caffeine_lang@frontend@tokenizer:tokenize(Source),
gleam@result:map_error(_pipe, fun(E) -> [{tokenizer_error, E}] end)
end,
fun(Tokens) ->
Filtered = filter_whitespace(Tokens),
State = init_state(Filtered),
{Pending, State@1} = consume_comments(State),
gleam@result:'try'(
begin
_pipe@1 = parse_type_aliases(State@1, Pending),
gleam@result:map_error(_pipe@1, fun(E@1) -> [E@1] end)
end,
fun(_use0) ->
{Type_aliases, Pending@1, State@2} = _use0,
gleam@result:'try'(
begin
_pipe@2 = parse_extendables(State@2, Pending@1),
gleam@result:map_error(
_pipe@2,
fun(E@2) -> [E@2] end
)
end,
fun(_use0@1) ->
{Extendables, Pending@2, State@3} = _use0@1,
{Items, Errors, Pending@3, _} = parse_measurement_items_recovering(
State@3,
Pending@2
),
case Errors of
[] ->
{ok,
{measurements_file,
Type_aliases,
Extendables,
Items,
Pending@3}};
Errs ->
{error, Errs}
end
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 565).
-spec at_expect_item_boundary(caffeine_lang@frontend@token:token()) -> boolean().
at_expect_item_boundary(Tok) ->
case Tok of
{literal_string, _} ->
true;
e_o_f ->
true;
_ ->
false
end.
-file("src/caffeine_lang/frontend/parser.gleam", 503).
-spec parse_optional_measured_by(parser_state()) -> {ok,
{gleam@option:option(caffeine_lang@frontend@ast:measured_by()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_optional_measured_by(State) ->
case peek(State) of
keyword_as ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, keyword_measured, <<"measured"/utf8>>),
fun(State@2) ->
gleam@result:'try'(
expect(State@2, keyword_by, <<"by"/utf8>>),
fun(State@3) ->
gleam@result:'try'(
parse_string_literal(State@3),
fun(_use0) ->
{Measurement, State@4} = _use0,
gleam@result:'try'(
expect(
State@4,
keyword_with,
<<"with"/utf8>>
),
fun(State@5) ->
gleam@result:'try'(
expect(
State@5,
symbol_colon,
<<":"/utf8>>
),
fun(State@6) ->
gleam@result:'try'(
parse_literal_struct(
State@6
),
fun(_use0@1) ->
{With_args, State@7} = _use0@1,
{ok,
{{some,
{measured_by,
Measurement,
With_args}},
State@7}}
end
)
end
)
end
)
end
)
end
)
end
);
_ ->
{ok, {none, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 536).
-spec parse_duration_literal(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:duration_literal(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_duration_literal(State) ->
case peek(State) of
{literal_duration, Amount, Unit} ->
{ok, {{duration_literal, Amount, Unit}, advance(State)}};
Tok ->
{error,
{unexpected_token,
<<"duration (e.g. 10d, 50ms)"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 490).
-spec parse_optional_below(parser_state()) -> {ok,
{gleam@option:option(caffeine_lang@frontend@ast:duration_literal()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_optional_below(State) ->
case peek(State) of
keyword_below ->
State@1 = advance(State),
gleam@result:'try'(
parse_duration_literal(State@1),
fun(_use0) ->
{Dur, State@2} = _use0,
{ok, {{some, Dur}, State@2}}
end
);
_ ->
{ok, {none, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 521).
-spec parse_percentage_literal(parser_state()) -> {ok,
{float(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_percentage_literal(State) ->
case peek(State) of
{literal_percentage, F} ->
{ok, {F, advance(State)}};
Tok ->
{error,
{unexpected_token,
<<"percentage (e.g. 99.9%)"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 477).
-spec parse_guarantees(parser_state()) -> {ok,
{caffeine_lang@frontend@ast:guarantees(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_guarantees(State) ->
gleam@result:'try'(
expect(State, keyword_guarantees, <<"Guarantees"/utf8>>),
fun(State@1) ->
gleam@result:'try'(
parse_percentage_literal(State@1),
fun(_use0) ->
{Threshold, State@2} = _use0,
gleam@result:'try'(
parse_optional_below(State@2),
fun(_use0@1) ->
{Below, State@3} = _use0@1,
gleam@result:'try'(
expect(State@3, keyword_over, <<"over"/utf8>>),
fun(State@4) ->
gleam@result:'try'(
parse_duration_literal(State@4),
fun(_use0@2) ->
{Window, State@5} = _use0@2,
gleam@result:'try'(
expect(
State@5,
keyword_window,
<<"window"/utf8>>
),
fun(State@6) ->
gleam@result:'try'(
parse_optional_measured_by(
State@6
),
fun(_use0@3) ->
{Measured_by,
State@7} = _use0@3,
{ok,
{{guarantees,
Threshold,
Below,
Window,
Measured_by},
State@7}}
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 456).
-spec parse_dependency_line(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {ok, {caffeine_lang@frontend@ast:dependency(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_dependency_line(State, Leading_comments) ->
gleam@result:'try'(case peek(State) of
keyword_hard ->
{ok, {hard_dep, advance(State)}};
keyword_soft ->
{ok, {soft_dep, advance(State)}};
Tok ->
{error,
{unexpected_token,
<<"hard or soft"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)}}
end, fun(_use0) ->
{Kind, State@1} = _use0,
gleam@result:'try'(
expect(State@1, keyword_dependency, <<"dependency"/utf8>>),
fun(State@2) ->
gleam@result:'try'(
expect(State@2, keyword_on, <<"on"/utf8>>),
fun(State@3) ->
gleam@result:'try'(
parse_string_literal(State@3),
fun(_use0@1) ->
{Target, State@4} = _use0@1,
{ok,
{{dependency,
Kind,
Target,
Leading_comments},
State@4}}
end
)
end
)
end
)
end).
-file("src/caffeine_lang/frontend/parser.gleam", 441).
-spec parse_dependency_lines(
parser_state(),
list(caffeine_lang@frontend@ast:comment()),
list(caffeine_lang@frontend@ast:dependency())
) -> {ok,
{list(caffeine_lang@frontend@ast:dependency()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_dependency_lines(State, Leading, Acc) ->
case peek(State) of
keyword_hard ->
gleam@result:'try'(
parse_dependency_line(State, Leading),
fun(_use0) ->
{Dep, State@1} = _use0,
{Next_pending, State@2} = consume_comments(State@1),
parse_dependency_lines(State@2, Next_pending, [Dep | Acc])
end
);
keyword_soft ->
gleam@result:'try'(
parse_dependency_line(State, Leading),
fun(_use0) ->
{Dep, State@1} = _use0,
{Next_pending, State@2} = consume_comments(State@1),
parse_dependency_lines(State@2, Next_pending, [Dep | Acc])
end
);
_ ->
{ok, {lists:reverse(Acc), Leading, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 424).
-spec parse_optional_assumes(parser_state()) -> {ok,
{gleam@option:option(caffeine_lang@frontend@ast:assumes()),
parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_optional_assumes(State) ->
case peek(State) of
keyword_assumes ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, symbol_colon, <<":"/utf8>>),
fun(State@2) ->
{Pending, State@3} = consume_comments(State@2),
gleam@result:'try'(
parse_dependency_lines(State@3, Pending, []),
fun(_use0) ->
{Deps, Trailing, State@4} = _use0,
{ok, {{some, {assumes, Deps, Trailing}}, State@4}}
end
)
end
);
_ ->
{ok, {none, State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 408).
?DOC(
" Parses a single standalone expectation:\n"
"\n"
" \"<name>\" (extends [...])?:\n"
" (Assumes:\n"
" (hard|soft) dependency on \"<target>\"\n"
" ...)?\n"
" Guarantees <pct>% (below <dur>)? over <dur> window\n"
" (as measured by \"<measurement>\" with: { <fields> })?\n"
).
-spec parse_expect_item(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {ok, {caffeine_lang@frontend@ast:expect_item(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_expect_item(State, Leading_comments) ->
gleam@result:'try'(
parse_string_literal(State),
fun(_use0) ->
{Name, State@1} = _use0,
gleam@result:'try'(
parse_optional_extends(State@1),
fun(_use0@1) ->
{Extends, State@2} = _use0@1,
gleam@result:'try'(
expect(State@2, symbol_colon, <<":"/utf8>>),
fun(State@3) ->
{_, State@4} = consume_comments(State@3),
gleam@result:'try'(
parse_optional_assumes(State@4),
fun(_use0@2) ->
{Assumes, State@5} = _use0@2,
gleam@result:'try'(
parse_guarantees(State@5),
fun(_use0@3) ->
{Guarantees, State@6} = _use0@3,
{ok,
{{expect_item,
Name,
Extends,
Assumes,
Guarantees,
Leading_comments},
State@6}}
end
)
end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 621).
-spec expect_items_loop(
parser_state(),
list(caffeine_lang@frontend@ast:expect_item()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment())
) -> {list(caffeine_lang@frontend@ast:expect_item()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}.
expect_items_loop(State, Items, Errors, Pending) ->
case peek(State) of
{literal_string, _} ->
case parse_expect_item(State, Pending) of
{ok, {Item, State@1}} ->
{Next_pending, State@2} = consume_comments(State@1),
expect_items_loop(
State@2,
[Item | Items],
Errors,
Next_pending
);
{error, Err} ->
State@3 = skip_until(
advance(State),
fun at_expect_item_boundary/1
),
{Next_pending@1, State@4} = consume_comments(State@3),
expect_items_loop(
State@4,
Items,
[Err | Errors],
Next_pending@1
)
end;
_ ->
{lists:reverse(Items), lists:reverse(Errors), Pending, State}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 614).
?DOC(
" Parse expect items with recovery between items.\n"
" Each expect item starts with a string literal name (top-level, no grouping).\n"
).
-spec parse_expect_items_recovering(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {list(caffeine_lang@frontend@ast:expect_item()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}.
parse_expect_items_recovering(State, Pending) ->
expect_items_loop(State, [], [], Pending).
-file("src/caffeine_lang/frontend/parser.gleam", 72).
?DOC(
" Parses an expects file from source text.\n"
" Returns all recoverable parse errors rather than stopping at the first one.\n"
).
-spec parse_expects_file(binary()) -> {ok,
caffeine_lang@frontend@ast:expects_file(caffeine_lang@frontend@ast:parsed())} |
{error, list(caffeine_lang@frontend@parser_error:parser_error())}.
parse_expects_file(Source) ->
gleam@result:'try'(
begin
_pipe = caffeine_lang@frontend@tokenizer:tokenize(Source),
gleam@result:map_error(_pipe, fun(E) -> [{tokenizer_error, E}] end)
end,
fun(Tokens) ->
Filtered = filter_whitespace(Tokens),
State = init_state(Filtered),
{Pending, State@1} = consume_comments(State),
gleam@result:'try'(
begin
_pipe@1 = parse_extendables(State@1, Pending),
gleam@result:map_error(_pipe@1, fun(E@1) -> [E@1] end)
end,
fun(_use0) ->
{Extendables, Pending@1, State@2} = _use0,
{Items, Errors, Pending@2, _} = parse_expect_items_recovering(
State@2,
Pending@1
),
case Errors of
[] ->
{ok, {expects_file, Extendables, Items, Pending@2}};
Errs ->
{error, Errs}
end
end
)
end
).