Current section

Files

Jump to
caffeine_lang src caffeine_lang@frontend@parser.erl
Raw

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", 96).
?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", 125).
?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", 134).
?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", 142).
?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", 111).
-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]
);
_ ->
{lists:reverse(Acc), State}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 107).
?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", 167).
?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", 224).
?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", 324).
-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", 400).
?DOC(" Skip tokens until the next block boundary (Expectations, Unmeasured, or EOF).\n").
-spec skip_to_block_boundary(parser_state()) -> parser_state().
skip_to_block_boundary(State) ->
case peek(State) of
keyword_expectations ->
State;
keyword_unmeasured ->
State;
e_o_f ->
State;
_ ->
skip_to_block_boundary(advance(State))
end.
-file("src/caffeine_lang/frontend/parser.gleam", 408).
?DOC(" Skip tokens until the next item boundary (*, block keyword, or EOF).\n").
-spec skip_to_item_boundary(parser_state()) -> parser_state().
skip_to_item_boundary(State) ->
case peek(State) of
symbol_star ->
State;
keyword_expectations ->
State;
keyword_unmeasured ->
State;
e_o_f ->
State;
_ ->
skip_to_item_boundary(advance(State))
end.
-file("src/caffeine_lang/frontend/parser.gleam", 525).
?DOC(" Generic single-block recovery parameterized by header parser, item parser, and block constructor.\n").
-spec block_recovering(
parser_state(),
list(caffeine_lang@frontend@ast:comment()),
fun((parser_state()) -> {ok, {LJU, parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}),
fun((parser_state()) -> {list(LJX),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}),
fun((LJU, list(LJX), list(caffeine_lang@frontend@ast:comment())) -> LKD)
) -> {{ok, {LKD, list(caffeine_lang@frontend@ast:comment())}} |
{error, caffeine_lang@frontend@parser_error:parser_error()},
list(caffeine_lang@frontend@parser_error:parser_error()),
parser_state()}.
block_recovering(
State,
Leading_comments,
Parse_header,
Parse_items,
Build_block
) ->
case Parse_header(State) of
{error, Err} ->
{{error, Err}, [], State};
{ok, {Header_data, State@1}} ->
{Items, Item_errors, Trailing, State@2} = Parse_items(State@1),
{{ok, {Build_block(Header_data, Items, Leading_comments), Trailing}},
Item_errors,
State@2}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 585).
?DOC(" Skip tokens until the next measurement item boundary (string literal or EOF).\n").
-spec skip_to_measurement_item_boundary(parser_state()) -> parser_state().
skip_to_measurement_item_boundary(State) ->
case peek(State) of
{literal_string, _} ->
State;
e_o_f ->
State;
_ ->
skip_to_measurement_item_boundary(advance(State))
end.
-file("src/caffeine_lang/frontend/parser.gleam", 601).
?DOC(" Generic item-level recovery loop parameterized by item parser.\n").
-spec items_recovering_loop(
parser_state(),
list(LKV),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
fun((parser_state(), list(caffeine_lang@frontend@ast:comment())) -> {ok,
{LKV, parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()})
) -> {list(LKV),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}.
items_recovering_loop(State, Item_acc, Error_acc, Pending, Parse_item) ->
case peek(State) of
symbol_star ->
case Parse_item(State, Pending) of
{ok, {Item, State@1}} ->
{Next_pending, State@2} = consume_comments(State@1),
items_recovering_loop(
State@2,
[Item | Item_acc],
Error_acc,
Next_pending,
Parse_item
);
{error, Err} ->
State@3 = skip_to_item_boundary(advance(State)),
{Next_pending@1, State@4} = consume_comments(State@3),
items_recovering_loop(
State@4,
Item_acc,
[Err | Error_acc],
Next_pending@1,
Parse_item
)
end;
_ ->
{lists:reverse(Item_acc), lists:reverse(Error_acc), Pending, State}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 643).
-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", 497).
?DOC(
" Parse just the header of an expects block.\n"
" Handles both `Expectations measured by \"name\"` and `Unmeasured Expectations`.\n"
).
-spec parse_expects_block_header(parser_state()) -> {ok,
{gleam@option:option(binary()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_expects_block_header(State) ->
case peek(State) of
keyword_unmeasured ->
State@1 = advance(State),
gleam@result:'try'(
expect(State@1, keyword_expectations, <<"Expectations"/utf8>>),
fun(State@2) -> {ok, {none, State@2}} end
);
_ ->
gleam@result:'try'(
expect(State, keyword_expectations, <<"Expectations"/utf8>>),
fun(State@3) ->
gleam@result:'try'(
expect(State@3, keyword_measured, <<"measured"/utf8>>),
fun(State@4) ->
gleam@result:'try'(
expect(State@4, keyword_by, <<"by"/utf8>>),
fun(State@5) ->
gleam@result:'try'(
parse_string_literal(State@5),
fun(_use0) ->
{Measurement, State@6} = _use0,
{ok, {{some, Measurement}, State@6}}
end
)
end
)
end
)
end
)
end.
-file("src/caffeine_lang/frontend/parser.gleam", 692).
-spec parse_extends_list_loop(parser_state(), list(binary())) -> {ok,
{list(binary()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_extends_list_loop(State, Acc) ->
case peek(State) of
symbol_comma ->
State@1 = advance(State),
case peek(State@1) of
{identifier, Name} ->
State@2 = advance(State@1),
parse_extends_list_loop(State@2, [Name | Acc]);
Tok ->
{error,
{unexpected_token,
<<"identifier"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State@1),
erlang:element(4, State@1)}}
end;
_ ->
{ok, {lists:reverse(Acc), State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 673).
-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}};
{identifier, Name} ->
State@1 = advance(State),
parse_extends_list_loop(State@1, [Name]);
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", 658).
-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", 814).
-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", 786).
-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", 761).
-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", 746).
?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", 987).
?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 ->
State@1 = advance(State),
{ok, {{parsed_primitive, string}, State@1}};
{identifier, Name} ->
case gleam_stdlib:string_starts_with(Name, <<"_"/utf8>>) of
true ->
State@2 = advance(State),
{ok, {{parsed_type_alias_ref, Name}, State@2}};
false ->
{error,
{unknown_type,
Name,
erlang:element(3, State),
erlang:element(4, State)}}
end;
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", 1121).
-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", 1256).
?DOC(" Convert a Literal to its string representation for use in refinements/defaults.\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_true ->
<<"true"/utf8>>;
literal_false ->
<<"false"/utf8>>;
{literal_list, _} ->
<<"[]"/utf8>>;
{literal_struct, _, _} ->
<<"{}"/utf8>>
end.
-file("src/caffeine_lang/frontend/parser.gleam", 726).
?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", 843).
-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 peek(State) of
keyword_string ->
parse_type_with_refinement(State, string);
keyword_integer ->
parse_type_with_refinement(State, {numeric_type, integer});
keyword_float ->
parse_type_with_refinement(State, {numeric_type, float});
keyword_boolean ->
parse_type_with_refinement(State, boolean);
keyword_u_r_l ->
parse_type_with_refinement(State, {semantic_type, u_r_l});
keyword_percentage ->
parse_type_with_refinement(State, {numeric_type, percentage});
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} ->
case gleam_stdlib:string_starts_with(Name, <<"_"/utf8>>) of
true ->
State@1 = advance(State),
{ok, {{parsed_type_alias_ref, Name}, State@1}};
false ->
{error,
{unknown_type,
Name,
erlang:element(3, State),
erlang:element(4, State)}}
end;
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", 971).
-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", 911).
?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 peek(State) of
keyword_string ->
State@1 = advance(State),
{ok, {{parsed_primitive, string}, State@1}};
keyword_integer ->
State@2 = advance(State),
{ok, {{parsed_primitive, {numeric_type, integer}}, State@2}};
keyword_float ->
State@3 = advance(State),
{ok, {{parsed_primitive, {numeric_type, float}}, State@3}};
keyword_boolean ->
State@4 = advance(State),
{ok, {{parsed_primitive, boolean}, State@4}};
keyword_u_r_l ->
State@5 = advance(State),
{ok, {{parsed_primitive, {semantic_type, u_r_l}}, State@5}};
keyword_percentage ->
State@6 = advance(State),
{ok, {{parsed_primitive, {numeric_type, percentage}}, State@6}};
keyword_list ->
parse_list_type(State);
keyword_dict ->
parse_dict_type(State);
symbol_left_brace ->
parse_record_type(State);
{identifier, Name} ->
case gleam_stdlib:string_starts_with(Name, <<"_"/utf8>>) of
true ->
State@7 = advance(State),
{ok, {{parsed_type_alias_ref, Name}, State@7}};
false ->
{error,
{unknown_type,
Name,
erlang:element(3, State),
erlang:element(4, State)}}
end;
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", 895).
?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 => 902,
value => _assert_fail,
start => 28940,
'end' => 28981,
pattern_start => 28951,
pattern_end => 28967})
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", 236).
-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", 197).
-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", 190).
?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", 961).
-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", 1013).
-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", 1211).
-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,
parse_literal_list_loop(State@1, [First])
end
)
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1223).
-spec parse_literal_list_loop(
parser_state(),
list(caffeine_lang@frontend@ast:literal())
) -> {ok, {list(caffeine_lang@frontend@ast:literal()), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_literal_list_loop(State, Acc) ->
case peek(State) of
symbol_comma ->
State@1 = advance(State),
gleam@result:'try'(
parse_literal(State@1),
fun(_use0) ->
{Literal, State@2} = _use0,
parse_literal_list_loop(State@2, [Literal | Acc])
end
);
_ ->
{ok, {lists:reverse(Acc), State}}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 1179).
-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_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);
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", 1202).
-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", 736).
?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", 306).
-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", 287).
-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", 280).
?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", 344).
-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_extends(State@1),
fun(_use0@1) ->
{Extends, State@2} = _use0@1,
gleam@result:'try'(
expect(State@2, symbol_colon, <<":"/utf8>>),
fun(State@3) ->
gleam@result:'try'(
expect(
State@3,
keyword_requires,
<<"Requires"/utf8>>
),
fun(State@4) ->
gleam@result:'try'(
parse_type_struct(State@4),
fun(_use0@2) ->
{Requires, State@5} = _use0@2,
gleam@result:'try'(
expect(
State@5,
keyword_provides,
<<"Provides"/utf8>>
),
fun(State@6) ->
gleam@result:'try'(
parse_literal_struct(
State@6
),
fun(_use0@3) ->
{Provides, State@7} = _use0@3,
{ok,
{{measurement_item,
Name,
Extends,
Requires,
Provides,
Leading_comments},
State@7}}
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 371).
-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'(
expect(State, symbol_star, <<"*"/utf8>>),
fun(State@1) ->
gleam@result:'try'(
parse_string_literal(State@1),
fun(_use0) ->
{Name, State@2} = _use0,
gleam@result:'try'(
parse_optional_extends(State@2),
fun(_use0@1) ->
{Extends, State@3} = _use0@1,
gleam@result:'try'(
expect(State@3, symbol_colon, <<":"/utf8>>),
fun(State@4) -> case peek(State@4) of
keyword_requires ->
{error,
{unexpected_token,
<<"Provides"/utf8>>,
<<"Requires"/utf8>>,
erlang:element(3, State@4),
erlang:element(4, State@4)}};
_ ->
gleam@result:'try'(
expect(
State@4,
keyword_provides,
<<"Provides"/utf8>>
),
fun(State@5) ->
gleam@result:'try'(
parse_literal_struct(
State@5
),
fun(_use0@2) ->
{Provides, State@6} = _use0@2,
{ok,
{{expect_item,
Name,
Extends,
Provides,
Leading_comments},
State@6}}
end
)
end
)
end end
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 560).
?DOC(" Recovery loop for measurement items, detecting boundaries by string literal tokens.\n").
-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_to_measurement_item_boundary(advance(State)),
{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", 552).
?DOC(
" Parse measurement items with recovery between items.\n"
" Measurement items start with a string literal name (no `*` prefix).\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", 39).
?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", 593).
?DOC(" Parse expect items with recovery between items.\n").
-spec parse_expect_items_recovering(parser_state()) -> {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, State@1} = consume_comments(State),
items_recovering_loop(State@1, [], [], Pending, fun parse_expect_item/2).
-file("src/caffeine_lang/frontend/parser.gleam", 476).
?DOC(" Parse a single expects block, recovering from item-level errors.\n").
-spec parse_expects_block_recovering(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {{ok,
{caffeine_lang@frontend@ast:expects_block(),
list(caffeine_lang@frontend@ast:comment())}} |
{error, caffeine_lang@frontend@parser_error:parser_error()},
list(caffeine_lang@frontend@parser_error:parser_error()),
parser_state()}.
parse_expects_block_recovering(State, Leading_comments) ->
block_recovering(
State,
Leading_comments,
fun parse_expects_block_header/1,
fun parse_expect_items_recovering/1,
fun(Measurement, Items, Comments) ->
{expects_block, Measurement, Items, Comments}
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 428).
?DOC(" Custom block-level recovery loop that matches either KeywordExpectations or KeywordUnmeasured.\n").
-spec expects_blocks_loop(
parser_state(),
list(caffeine_lang@frontend@ast:expects_block()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment())
) -> {list(caffeine_lang@frontend@ast:expects_block()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}.
expects_blocks_loop(State, Block_acc, Error_acc, Pending) ->
case peek(State) of
e_o_f ->
{lists:reverse(Block_acc), Error_acc, Pending, State};
keyword_expectations ->
{Block_result, Item_errors, State@1} = parse_expects_block_recovering(
State,
Pending
),
{More_comments, State@2} = consume_comments(State@1),
case Block_result of
{ok, {Block, Trailing}} ->
Next_pending = lists:append(Trailing, More_comments),
expects_blocks_loop(
State@2,
[Block | Block_acc],
lists:append(Error_acc, Item_errors),
Next_pending
);
{error, Err} ->
State@3 = skip_to_block_boundary(advance(State@2)),
{Next_pending@1, State@4} = consume_comments(State@3),
expects_blocks_loop(
State@4,
Block_acc,
lists:append(Error_acc, [Err | Item_errors]),
Next_pending@1
)
end;
keyword_unmeasured ->
{Block_result, Item_errors, State@1} = parse_expects_block_recovering(
State,
Pending
),
{More_comments, State@2} = consume_comments(State@1),
case Block_result of
{ok, {Block, Trailing}} ->
Next_pending = lists:append(Trailing, More_comments),
expects_blocks_loop(
State@2,
[Block | Block_acc],
lists:append(Error_acc, Item_errors),
Next_pending
);
{error, Err} ->
State@3 = skip_to_block_boundary(advance(State@2)),
{Next_pending@1, State@4} = consume_comments(State@3),
expects_blocks_loop(
State@4,
Block_acc,
lists:append(Error_acc, [Err | Item_errors]),
Next_pending@1
)
end;
Tok ->
Err@1 = {unexpected_token,
<<"Expectations or Unmeasured Expectations"/utf8>>,
caffeine_lang@frontend@token:to_string(Tok),
erlang:element(3, State),
erlang:element(4, State)},
{lists:reverse(Block_acc),
lists:append(Error_acc, [Err@1]),
Pending,
State}
end.
-file("src/caffeine_lang/frontend/parser.gleam", 420).
?DOC(
" Parse expects blocks with error recovery between blocks and items.\n"
" Recognizes both `Expectations measured by \"...\"` and `Unmeasured Expectations` headers.\n"
).
-spec parse_expects_blocks_recovering(
parser_state(),
list(caffeine_lang@frontend@ast:comment())
) -> {list(caffeine_lang@frontend@ast:expects_block()),
list(caffeine_lang@frontend@parser_error:parser_error()),
list(caffeine_lang@frontend@ast:comment()),
parser_state()}.
parse_expects_blocks_recovering(State, Pending) ->
expects_blocks_loop(State, [], [], Pending).
-file("src/caffeine_lang/frontend/parser.gleam", 73).
?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,
{Blocks, Errors, Pending@2, _} = parse_expects_blocks_recovering(
State@2,
Pending@1
),
case Errors of
[] ->
{ok, {expects_file, Extendables, Blocks, Pending@2}};
Errs ->
{error, Errs}
end
end
)
end
).
-file("src/caffeine_lang/frontend/parser.gleam", 1064).
-spec parse_defaulted_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_defaulted_refinement_body(State, Defaulted) ->
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,
Defaulted,
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,
Defaulted,
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", 1047).
?DOC(" Parse refinement on a Defaulted type: { x | x in { ... } } or { x | x in ( ... ) }\n").
-spec parse_defaulted_refinement(
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_defaulted_refinement(State, Defaulted) ->
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_defaulted_refinement_body(
State@5,
Defaulted
),
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", 1023).
-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_defaulted_refinement(
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", 1133).
-spec parse_refinement_body(
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_body(State, Primitive) ->
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,
{parsed_primitive, Primitive},
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,
{parsed_primitive,
Primitive},
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", 1107).
-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) ->
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,
Primitive
),
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", 879).
-spec parse_type_with_refinement(
parser_state(),
caffeine_lang@types:primitive_types()
) -> {ok, {caffeine_lang@types:parsed_type(), parser_state()}} |
{error, caffeine_lang@frontend@parser_error:parser_error()}.
parse_type_with_refinement(State, Primitive) ->
State@1 = advance(State),
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.
-file("src/caffeine_lang/frontend/parser.gleam", 1237).
-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
).