Current section

Files

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

src/caffeine_lang@frontend@formatter.erl

-module(caffeine_lang@frontend@formatter).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/frontend/formatter.gleam").
-export([format/1]).
-export_type([field_context/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 field_context() :: type_fields | literal_fields.
-file("src/caffeine_lang/frontend/formatter.gleam", 125).
-spec format_comments(list(caffeine_lang@frontend@ast:comment()), binary()) -> binary().
format_comments(Comments, Indent) ->
case Comments of
[] ->
<<""/utf8>>;
_ ->
_pipe = Comments,
_pipe@1 = gleam@list:map(_pipe, fun(C) -> case C of
{line_comment, Text} ->
<<<<<<Indent/binary, "#"/utf8>>/binary,
Text/binary>>/binary,
"\n"/utf8>>;
{section_comment, Text@1} ->
<<<<<<Indent/binary, "##"/utf8>>/binary,
Text@1/binary>>/binary,
"\n"/utf8>>;
{doc_comment, Text@2} ->
<<<<<<Indent/binary, "###"/utf8>>/binary,
Text@2/binary>>/binary,
"\n"/utf8>>
end end),
erlang:list_to_binary(_pipe@1)
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 394).
-spec needs_string_quoting(caffeine_lang@types:parsed_type()) -> boolean().
needs_string_quoting(T) ->
case T of
{parsed_primitive, string} ->
true;
{parsed_primitive, {semantic_type, _}} ->
true;
{parsed_refinement, {one_of, Inner, _}} ->
needs_string_quoting(Inner);
{parsed_refinement, {inclusive_range, Inner@1, _, _}} ->
needs_string_quoting(Inner@1);
{parsed_record, _} ->
false;
_ ->
false
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 406).
?DOC(" A default value needs quoting if it isn't a number, boolean, or percentage literal.\n").
-spec value_needs_quoting(binary()) -> boolean().
value_needs_quoting(Val) ->
case Val of
<<"true"/utf8>> ->
false;
<<"false"/utf8>> ->
false;
_ ->
Cleaned = case gleam_stdlib:string_ends_with(Val, <<"%"/utf8>>) of
true ->
gleam@string:drop_end(Val, 1);
false ->
Val
end,
case gleam_stdlib:parse_int(Cleaned) of
{ok, _} ->
false;
{error, _} ->
case gleam_stdlib:parse_float(Cleaned) of
{ok, _} ->
false;
{error, _} ->
true
end
end
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 383).
-spec quote_if_string_type(caffeine_lang@types:parsed_type(), binary()) -> binary().
quote_if_string_type(Inner, Val) ->
Quote = case Inner of
{parsed_type_alias_ref, _} ->
value_needs_quoting(Val);
_ ->
needs_string_quoting(Inner)
end,
gleam@bool:guard(
Quote,
<<<<"\""/utf8, Val/binary>>/binary, "\""/utf8>>,
fun() -> Val end
).
-file("src/caffeine_lang/frontend/formatter.gleam", 337).
-spec format_primitive_type(caffeine_lang@types:primitive_types()) -> binary().
format_primitive_type(P) ->
case P of
boolean ->
<<"Boolean"/utf8>>;
string ->
<<"String"/utf8>>;
{numeric_type, N} ->
case N of
integer ->
<<"Integer"/utf8>>;
float ->
<<"Float"/utf8>>;
percentage ->
<<"Percentage"/utf8>>
end;
{semantic_type, S} ->
case S of
u_r_l ->
<<"URL"/utf8>>
end
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 362).
-spec format_record_type(
gleam@dict:dict(binary(), caffeine_lang@types:parsed_type())
) -> binary().
format_record_type(Fields) ->
Field_strs = begin
_pipe = Fields,
_pipe@1 = maps:to_list(_pipe),
_pipe@2 = gleam@list:sort(
_pipe@1,
fun(A, B) ->
gleam@string:compare(erlang:element(1, A), erlang:element(1, B))
end
),
gleam@list:map(
_pipe@2,
fun(Pair) ->
<<<<(erlang:element(1, Pair))/binary, ": "/utf8>>/binary,
(format_type(erlang:element(2, Pair)))/binary>>
end
)
end,
<<<<"{ "/utf8, (gleam@string:join(Field_strs, <<", "/utf8>>))/binary>>/binary,
" }"/utf8>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 427).
-spec format_refinement_type(
caffeine_lang@types:refinement_types(caffeine_lang@types:parsed_type())
) -> binary().
format_refinement_type(R) ->
case R of
{one_of, Inner, Values} ->
Quote = needs_string_quoting(Inner),
Sorted_vals = begin
_pipe = Values,
_pipe@1 = gleam@set:to_list(_pipe),
_pipe@2 = gleam@list:sort(_pipe@1, fun gleam@string:compare/2),
_pipe@3 = gleam@list:map(
_pipe@2,
fun(V) ->
gleam@bool:guard(
Quote,
<<<<"\""/utf8, V/binary>>/binary, "\""/utf8>>,
fun() -> V end
)
end
),
gleam@string:join(_pipe@3, <<", "/utf8>>)
end,
<<<<<<(format_type(Inner))/binary, " { x | x in { "/utf8>>/binary,
Sorted_vals/binary>>/binary,
" } }"/utf8>>;
{inclusive_range, Inner@1, Low, High} ->
<<<<<<<<<<(format_type(Inner@1))/binary, " { x | x in ( "/utf8>>/binary,
Low/binary>>/binary,
".."/utf8>>/binary,
High/binary>>/binary,
" ) }"/utf8>>
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 371).
-spec format_modifier_type(
caffeine_lang@types:modifier_types(caffeine_lang@types:parsed_type())
) -> binary().
format_modifier_type(M) ->
case M of
{optional, Inner} ->
<<<<"Optional("/utf8, (format_type(Inner))/binary>>/binary,
")"/utf8>>;
{defaulted, Inner@1, Default_val} ->
<<<<<<<<"Defaulted("/utf8, (format_type(Inner@1))/binary>>/binary,
", "/utf8>>/binary,
(quote_if_string_type(Inner@1, Default_val))/binary>>/binary,
")"/utf8>>
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 354).
-spec format_collection_type(
caffeine_lang@types:collection_types(caffeine_lang@types:parsed_type())
) -> binary().
format_collection_type(C) ->
case C of
{list, Inner} ->
<<<<"List("/utf8, (format_type(Inner))/binary>>/binary, ")"/utf8>>;
{dict, Key, Value} ->
<<<<<<<<"Dict("/utf8, (format_type(Key))/binary>>/binary,
", "/utf8>>/binary,
(format_type(Value))/binary>>/binary,
")"/utf8>>
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 326).
-spec format_type(caffeine_lang@types:parsed_type()) -> binary().
format_type(T) ->
case T of
{parsed_primitive, P} ->
format_primitive_type(P);
{parsed_collection, C} ->
format_collection_type(C);
{parsed_modifier, M} ->
format_modifier_type(M);
{parsed_refinement, R} ->
format_refinement_type(R);
{parsed_type_alias_ref, Name} ->
Name;
{parsed_record, Fields} ->
format_record_type(Fields)
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 517).
?DOC(
" `name = \"x\" and field = \"y\"` style chain. Match-clause values can be any\n"
" literal, so we recurse back into `format_literal` — that's where things\n"
" like template variables (`\"$$->scorer$$\"`) get preserved verbatim.\n"
).
-spec format_match_chain(
list(caffeine_lang@frontend@ast:match_clause()),
integer(),
field_context()
) -> binary().
format_match_chain(Match, Indent, Context) ->
_pipe = Match,
_pipe@1 = gleam@list:map(
_pipe,
fun(Clause) ->
{match_clause, Field, Value} = Clause,
<<<<Field/binary, " = "/utf8>>/binary,
(format_literal(Value, Indent, Context))/binary>>
end
),
gleam@string:join(_pipe@1, <<" and "/utf8>>).
-file("src/caffeine_lang/frontend/formatter.gleam", 482).
?DOC(
" Format a `from <source> where ...` literal. Two surface forms:\n"
"\n"
" single-line (no value extraction):\n"
" from langfuse where name = \"outcome\" and value = \"pass\"\n"
"\n"
" block (with value extraction):\n"
" from langfuse {\n"
" where: name = \"faithfulness\"\n"
" value: value as Float\n"
" }\n"
"\n"
" Single-line stays single-line — match clauses don't get broken across lines\n"
" today even on long chains. If that ever bites, mirror `format_struct`'s\n"
" 80-column-aware inline/multiline split.\n"
).
-spec format_external_indicator(
binary(),
list(caffeine_lang@frontend@ast:match_clause()),
gleam@option:option(caffeine_lang@frontend@ast:value_extraction()),
integer(),
field_context()
) -> binary().
format_external_indicator(Source, Match, Value_extraction, Indent, Context) ->
case Value_extraction of
none ->
<<<<<<"from "/utf8, Source/binary>>/binary, " where "/utf8>>/binary,
(format_match_chain(Match, Indent, Context))/binary>>;
{some, {value_extraction, Path, Type_}} ->
Inner_indent = gleam@string:repeat(<<" "/utf8>>, Indent + 2),
Closing_indent = gleam@string:repeat(<<" "/utf8>>, Indent),
<<<<<<<<<<<<<<<<<<<<<<<<<<<<"from "/utf8, Source/binary>>/binary,
" {\n"/utf8>>/binary,
Inner_indent/binary>>/binary,
"where: "/utf8>>/binary,
(format_match_chain(
Match,
Indent + 2,
Context
))/binary>>/binary,
"\n"/utf8>>/binary,
Inner_indent/binary>>/binary,
"value: "/utf8>>/binary,
Path/binary>>/binary,
" as "/utf8>>/binary,
(format_type(Type_))/binary>>/binary,
"\n"/utf8>>/binary,
Closing_indent/binary>>/binary,
"}"/utf8>>
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 530).
-spec format_literal_list(
list(caffeine_lang@frontend@ast:literal()),
integer(),
field_context()
) -> binary().
format_literal_list(Elements, Indent, Context) ->
Element_strs = begin
_pipe = Elements,
gleam@list:map(_pipe, fun(E) -> format_literal(E, Indent, Context) end)
end,
<<<<"["/utf8, (gleam@string:join(Element_strs, <<", "/utf8>>))/binary>>/binary,
"]"/utf8>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 447).
-spec format_literal(
caffeine_lang@frontend@ast:literal(),
integer(),
field_context()
) -> binary().
format_literal(L, Indent, Context) ->
case L of
{literal_string, S} ->
<<<<"\""/utf8, S/binary>>/binary, "\""/utf8>>;
{literal_integer, I} ->
erlang:integer_to_binary(I);
{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} ->
format_literal_list(Elements, Indent, Context);
{literal_struct, Fields, Trailing_comments} ->
format_struct({struct, Fields, Trailing_comments}, Indent, Context);
{literal_external_indicator, Source, Match, Value_extraction} ->
format_external_indicator(
Source,
Match,
Value_extraction,
Indent,
Context
)
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 319).
-spec format_field(
caffeine_lang@frontend@ast:field(),
integer(),
field_context()
) -> binary().
format_field(F, Indent, Context) ->
case erlang:element(3, F) of
{type_value, T} ->
<<<<(erlang:element(2, F))/binary, ": "/utf8>>/binary,
(format_type(T))/binary>>;
{literal_value, L} ->
<<<<(erlang:element(2, F))/binary, ": "/utf8>>/binary,
(format_literal(L, Indent, Context))/binary>>
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 296).
-spec format_struct_multiline(
caffeine_lang@frontend@ast:struct(),
integer(),
field_context()
) -> binary().
format_struct_multiline(S, Indent, Context) ->
Indent_str = gleam@string:repeat(<<" "/utf8>>, Indent),
Field_lines = begin
_pipe = erlang:element(2, S),
gleam@list:map(
_pipe,
fun(F) ->
Comments = format_comments(erlang:element(4, F), Indent_str),
<<<<Comments/binary, Indent_str/binary>>/binary,
(format_field(F, Indent, Context))/binary>>
end
)
end,
Trailing = format_comments(erlang:element(3, S), Indent_str),
<<<<<<<<<<"{\n"/utf8,
(gleam@string:join(Field_lines, <<",\n"/utf8>>))/binary>>/binary,
"\n"/utf8>>/binary,
Trailing/binary>>/binary,
(gleam@string:repeat(<<" "/utf8>>, Indent - 2))/binary>>/binary,
"}"/utf8>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 289).
-spec format_struct_inline(
list(caffeine_lang@frontend@ast:field()),
field_context()
) -> binary().
format_struct_inline(Fields, Context) ->
Field_strs = begin
_pipe = Fields,
gleam@list:map(_pipe, fun(F) -> format_field(F, 0, Context) end)
end,
<<<<"{ "/utf8, (gleam@string:join(Field_strs, <<", "/utf8>>))/binary>>/binary,
" }"/utf8>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 256).
-spec format_struct(
caffeine_lang@frontend@ast:struct(),
integer(),
field_context()
) -> binary().
format_struct(S, Indent, Context) ->
Has_field_comments = gleam@list:any(
erlang:element(2, S),
fun(F) -> erlang:element(4, F) /= [] end
),
Has_trailing_comments = erlang:element(3, S) /= [],
Has_any_comments = Has_field_comments orelse Has_trailing_comments,
case erlang:element(2, S) of
[] ->
case Has_trailing_comments of
true ->
<<<<<<"{\n"/utf8,
(format_comments(
erlang:element(3, S),
gleam@string:repeat(
<<" "/utf8>>,
Indent + 2
)
))/binary>>/binary,
(gleam@string:repeat(<<" "/utf8>>, Indent))/binary>>/binary,
"}"/utf8>>;
false ->
<<"{}"/utf8>>
end;
Fields ->
gleam@bool:guard(
Has_any_comments,
format_struct_multiline(S, Indent + 2, Context),
fun() ->
Inline = format_struct_inline(Fields, Context),
Prefix_len = Indent + 10,
gleam@bool:guard(
(string:length(Inline) + Prefix_len) < 80,
Inline,
fun() ->
format_struct_multiline(S, Indent + 2, Context)
end
)
end
)
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 249).
-spec format_extends(list(binary())) -> binary().
format_extends(Extends) ->
case Extends of
[] ->
<<""/utf8>>;
Names ->
<<<<" extends ["/utf8,
(gleam@string:join(Names, <<", "/utf8>>))/binary>>/binary,
"]"/utf8>>
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 165).
-spec format_measurement_item(caffeine_lang@frontend@ast:measurement_item()) -> binary().
format_measurement_item(Item) ->
Comments = format_comments(erlang:element(7, Item), <<""/utf8>>),
Name_line = <<<<<<<<"\""/utf8, (erlang:element(2, Item))/binary>>/binary,
"\""/utf8>>/binary,
(format_extends(erlang:element(4, Item)))/binary>>/binary,
":"/utf8>>,
Requires = <<" Requires "/utf8,
(format_struct(erlang:element(5, Item), 2, type_fields))/binary>>,
Provides = <<" Provides "/utf8,
(format_struct(erlang:element(6, Item), 2, literal_fields))/binary>>,
<<<<<<<<<<Comments/binary, Name_line/binary>>/binary, "\n"/utf8>>/binary,
Requires/binary>>/binary,
"\n"/utf8>>/binary,
Provides/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 148).
-spec format_extendable(caffeine_lang@frontend@ast:extendable()) -> binary().
format_extendable(Ext) ->
Kind_str = case erlang:element(3, Ext) of
extendable_requires ->
<<"Requires"/utf8>>;
extendable_provides ->
<<"Provides"/utf8>>
end,
Context = case erlang:element(3, Ext) of
extendable_requires ->
type_fields;
extendable_provides ->
literal_fields
end,
<<<<<<<<<<(format_comments(erlang:element(5, Ext), <<""/utf8>>))/binary,
(erlang:element(2, Ext))/binary>>/binary,
" ("/utf8>>/binary,
Kind_str/binary>>/binary,
"): "/utf8>>/binary,
(format_struct(erlang:element(4, Ext), 0, Context))/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 141).
-spec format_type_alias(caffeine_lang@frontend@ast:type_alias()) -> binary().
format_type_alias(Alias) ->
<<<<<<(format_comments(erlang:element(4, Alias), <<""/utf8>>))/binary,
(erlang:element(2, Alias))/binary>>/binary,
" (Type): "/utf8>>/binary,
(format_type(erlang:element(3, Alias)))/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 72).
-spec format_measurements_file(
caffeine_lang@frontend@ast:measurements_file(caffeine_lang@frontend@ast:parsed())
) -> binary().
format_measurements_file(File) ->
Sections = [],
Sections@1 = case erlang:element(2, File) of
[] ->
Sections;
Aliases ->
lists:append(
Sections,
[begin
_pipe = gleam@list:map(Aliases, fun format_type_alias/1),
gleam@string:join(_pipe, <<"\n"/utf8>>)
end]
)
end,
Sections@2 = case erlang:element(3, File) of
[] ->
Sections@1;
Extendables ->
lists:append(
Sections@1,
[begin
_pipe@1 = gleam@list:map(
Extendables,
fun format_extendable/1
),
gleam@string:join(_pipe@1, <<"\n"/utf8>>)
end]
)
end,
Sections@3 = case erlang:element(4, File) of
[] ->
Sections@2;
Items ->
lists:append(
Sections@2,
[begin
_pipe@2 = gleam@list:map(
Items,
fun format_measurement_item/1
),
gleam@string:join(_pipe@2, <<"\n\n"/utf8>>)
end]
)
end,
Trailing = format_comments(erlang:element(5, File), <<""/utf8>>),
<<<<(gleam@string:join(Sections@3, <<"\n\n"/utf8>>))/binary, "\n"/utf8>>/binary,
Trailing/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 241).
?DOC(
" Renders the magnitude of a duration. Whole numbers drop the trailing \".0\"\n"
" so `30d` round-trips cleanly; fractional values keep their decimal form.\n"
).
-spec format_amount(float()) -> binary().
format_amount(F) ->
Rounded = erlang:float(erlang:round(F)),
case Rounded =:= F of
true ->
erlang:integer_to_binary(erlang:round(F));
false ->
gleam_stdlib:float_to_string(F)
end.
-file("src/caffeine_lang/frontend/formatter.gleam", 235).
-spec format_duration_literal(caffeine_lang@frontend@ast:duration_literal()) -> binary().
format_duration_literal(D) ->
<<(format_amount(erlang:element(2, D)))/binary,
(erlang:element(3, D))/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 217).
-spec format_guarantees(caffeine_lang@frontend@ast:guarantees()) -> binary().
format_guarantees(G) ->
Head = <<<<"Guarantees "/utf8,
(gleam_stdlib:float_to_string(erlang:element(2, G)))/binary>>/binary,
"%"/utf8>>,
Below = case erlang:element(3, G) of
{some, D} ->
<<" below "/utf8, (format_duration_literal(D))/binary>>;
none ->
<<""/utf8>>
end,
Window = <<<<" over "/utf8,
(format_duration_literal(erlang:element(4, G)))/binary>>/binary,
" window"/utf8>>,
Measured = case erlang:element(5, G) of
{some, Mb} ->
<<<<<<" as measured by \""/utf8, (erlang:element(2, Mb))/binary>>/binary,
"\" with: "/utf8>>/binary,
(format_struct(erlang:element(3, Mb), 2, literal_fields))/binary>>;
none ->
<<""/utf8>>
end,
<<<<<<Head/binary, Below/binary>>/binary, Window/binary>>/binary,
Measured/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 208).
-spec format_dependency_line(caffeine_lang@frontend@ast:dependency()) -> binary().
format_dependency_line(D) ->
Kind = case erlang:element(2, D) of
hard_dep ->
<<"hard"/utf8>>;
soft_dep ->
<<"soft"/utf8>>
end,
Leading = format_comments(erlang:element(4, D), <<" "/utf8>>),
<<<<<<<<<<Leading/binary, " "/utf8>>/binary, Kind/binary>>/binary,
" dependency on \""/utf8>>/binary,
(erlang:element(3, D))/binary>>/binary,
"\""/utf8>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 191).
-spec format_assumes(caffeine_lang@frontend@ast:assumes()) -> binary().
format_assumes(A) ->
Header = <<" Assumes:"/utf8>>,
Dep_lines = begin
_pipe = erlang:element(2, A),
_pipe@1 = gleam@list:map(_pipe, fun format_dependency_line/1),
gleam@string:join(_pipe@1, <<"\n"/utf8>>)
end,
Body = case Dep_lines of
<<""/utf8>> ->
<<""/utf8>>;
_ ->
<<"\n"/utf8, Dep_lines/binary>>
end,
Trailing = case erlang:element(3, A) of
[] ->
<<""/utf8>>;
_ ->
<<"\n"/utf8,
(format_comments(erlang:element(3, A), <<" "/utf8>>))/binary>>
end,
<<<<Header/binary, Body/binary>>/binary, Trailing/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 176).
-spec format_expect_item(caffeine_lang@frontend@ast:expect_item()) -> binary().
format_expect_item(Item) ->
Comments = format_comments(erlang:element(6, Item), <<""/utf8>>),
Name_line = <<<<<<<<"\""/utf8, (erlang:element(2, Item))/binary>>/binary,
"\""/utf8>>/binary,
(format_extends(erlang:element(3, Item)))/binary>>/binary,
":"/utf8>>,
Assumes_section = case erlang:element(4, Item) of
{some, A} ->
<<"\n"/utf8, (format_assumes(A))/binary>>;
none ->
<<""/utf8>>
end,
Guarantees_line = <<"\n "/utf8,
(format_guarantees(erlang:element(5, Item)))/binary>>,
<<<<<<Comments/binary, Name_line/binary>>/binary, Assumes_section/binary>>/binary,
Guarantees_line/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 104).
-spec format_expects_file(
caffeine_lang@frontend@ast:expects_file(caffeine_lang@frontend@ast:parsed())
) -> binary().
format_expects_file(File) ->
Sections = [],
Sections@1 = case erlang:element(2, File) of
[] ->
Sections;
Extendables ->
lists:append(
Sections,
[begin
_pipe = gleam@list:map(
Extendables,
fun format_extendable/1
),
gleam@string:join(_pipe, <<"\n"/utf8>>)
end]
)
end,
Sections@2 = case erlang:element(3, File) of
[] ->
Sections@1;
Items ->
lists:append(
Sections@1,
gleam@list:map(Items, fun format_expect_item/1)
)
end,
Trailing = format_comments(erlang:element(4, File), <<""/utf8>>),
<<<<(gleam@string:join(Sections@2, <<"\n\n"/utf8>>))/binary, "\n"/utf8>>/binary,
Trailing/binary>>.
-file("src/caffeine_lang/frontend/formatter.gleam", 40).
?DOC(
" Format a Caffeine source file. Auto-detects whether it's a measurements or expectations file.\n"
" Expectations files are detected by the presence of the `Guarantees` keyword;\n"
" all other files are treated as measurements files.\n"
).
-spec format(binary()) -> {ok, binary()} | {error, binary()}.
format(Source) ->
gleam@result:'try'(
begin
_pipe = caffeine_lang@frontend@tokenizer:tokenize(Source),
gleam@result:map_error(
_pipe,
fun(_) -> <<"Tokenization error"/utf8>> end
)
end,
fun(Tokens) ->
Has_expectations = gleam@list:any(Tokens, fun(Ptok) -> case Ptok of
{positioned_token, keyword_guarantees, _, _} ->
true;
_ ->
false
end end),
case Has_expectations of
true ->
gleam@result:'try'(
begin
_pipe@1 = caffeine_lang@frontend@parser:parse_expects_file(
Source
),
gleam@result:map_error(
_pipe@1,
fun(Err) ->
<<"Parse error: "/utf8,
(gleam@string:inspect(Err))/binary>>
end
)
end,
fun(Parsed) -> {ok, format_expects_file(Parsed)} end
);
false ->
gleam@result:'try'(
begin
_pipe@2 = caffeine_lang@frontend@parser:parse_measurements_file(
Source
),
gleam@result:map_error(
_pipe@2,
fun(Err@1) ->
<<"Parse error: "/utf8,
(gleam@string:inspect(Err@1))/binary>>
end
)
end,
fun(Parsed@1) ->
{ok, format_measurements_file(Parsed@1)}
end
)
end
end
).