Packages
caffeine_lang
4.3.6
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@lowering.erl
-module(caffeine_lang@frontend@lowering).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/frontend/lowering.gleam").
-export([literal_to_value/1, lower_expectations/1, lower_blueprints/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/caffeine_lang/frontend/lowering.gleam", 52).
?DOC(" Builds a map of extendable name to extendable for quick lookup.\n").
-spec build_extendable_map(list(caffeine_lang@frontend@ast:extendable())) -> gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable()).
build_extendable_map(Extendables) ->
_pipe = Extendables,
_pipe@1 = gleam@list:map(_pipe, fun(E) -> {erlang:element(2, E), E} end),
maps:from_list(_pipe@1).
-file("src/caffeine_lang/frontend/lowering.gleam", 61).
?DOC(" Builds a map of type alias name to its parsed type for quick lookup.\n").
-spec build_type_alias_map(list(caffeine_lang@frontend@ast:type_alias())) -> gleam@dict:dict(binary(), caffeine_lang@types:parsed_type()).
build_type_alias_map(Type_aliases) ->
_pipe = caffeine_lang@frontend@ast:build_type_alias_pairs(Type_aliases),
maps:from_list(_pipe).
-file("src/caffeine_lang/frontend/lowering.gleam", 92).
?DOC(" Converts a ParsedArtifactRef to an ArtifactType (infallible).\n").
-spec lower_artifact_ref(caffeine_lang@frontend@ast:parsed_artifact_ref()) -> caffeine_lang@linker@artifacts:artifact_type().
lower_artifact_ref(Ref) ->
case Ref of
parsed_s_l_o ->
s_l_o;
parsed_dependency_relations ->
dependency_relations
end.
-file("src/caffeine_lang/frontend/lowering.gleam", 112).
?DOC(" Collects fields from extended extendables matching a given kind.\n").
-spec collect_extended_fields(
list(binary()),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable()),
caffeine_lang@frontend@ast:extendable_kind()
) -> list(caffeine_lang@frontend@ast:field()).
collect_extended_fields(Extends, Extendables, Kind) ->
_pipe = Extends,
gleam@list:flat_map(
_pipe,
fun(Name) -> case gleam_stdlib:map_get(Extendables, Name) of
{ok, Ext} when erlang:element(3, Ext) =:= Kind ->
erlang:element(2, erlang:element(4, Ext));
_ ->
[]
end end
).
-file("src/caffeine_lang/frontend/lowering.gleam", 164).
?DOC(
" Removes duplicate field names, keeping the last occurrence (allows overrides).\n"
" Returns fields sorted by name for consistent output.\n"
).
-spec dedupe_fields(list(caffeine_lang@frontend@ast:field())) -> list(caffeine_lang@frontend@ast:field()).
dedupe_fields(Fields) ->
_pipe = Fields,
_pipe@1 = gleam@list:fold(
_pipe,
maps:new(),
fun(Acc, Field) ->
gleam@dict:insert(Acc, erlang:element(2, Field), Field)
end
),
_pipe@2 = maps:to_list(_pipe@1),
_pipe@3 = gleam@list:sort(
_pipe@2,
fun(A, B) ->
gleam@string:compare(erlang:element(1, A), erlang:element(1, B))
end
),
gleam@list:map(_pipe@3, fun(Pair) -> erlang:element(2, Pair) end).
-file("src/caffeine_lang/frontend/lowering.gleam", 128).
?DOC(
" Merges extended fields into a blueprint item's requires and provides.\n"
" Order: extended extendables left-to-right, then item's own fields (can override).\n"
).
-spec merge_blueprint_extends(
caffeine_lang@frontend@ast:blueprint_item(),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable())
) -> {caffeine_lang@frontend@ast:struct(), caffeine_lang@frontend@ast:struct()}.
merge_blueprint_extends(Item, Extendables) ->
Requires_fields = begin
_pipe = collect_extended_fields(
erlang:element(3, Item),
Extendables,
extendable_requires
),
_pipe@1 = lists:append(
_pipe,
erlang:element(2, erlang:element(4, Item))
),
dedupe_fields(_pipe@1)
end,
Provides_fields = begin
_pipe@2 = collect_extended_fields(
erlang:element(3, Item),
Extendables,
extendable_provides
),
_pipe@3 = lists:append(
_pipe@2,
erlang:element(2, erlang:element(5, Item))
),
dedupe_fields(_pipe@3)
end,
{{struct, Requires_fields, []}, {struct, Provides_fields, []}}.
-file("src/caffeine_lang/frontend/lowering.gleam", 150).
?DOC(
" Merges extended fields into an expect item's provides.\n"
" Order: extended extendables left-to-right, then item's own fields (can override).\n"
).
-spec merge_expect_extends(
caffeine_lang@frontend@ast:expect_item(),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable())
) -> caffeine_lang@frontend@ast:struct().
merge_expect_extends(Item, Extendables) ->
Provides_fields = begin
_pipe = collect_extended_fields(
erlang:element(3, Item),
Extendables,
extendable_provides
),
_pipe@1 = lists:append(
_pipe,
erlang:element(2, erlang:element(4, Item))
),
dedupe_fields(_pipe@1)
end,
{struct, Provides_fields, []}.
-file("src/caffeine_lang/frontend/lowering.gleam", 301).
-spec transform_template_vars_loop(binary(), binary()) -> binary().
transform_template_vars_loop(Remaining, Acc) ->
case gleam@string:split_once(Remaining, <<"$"/utf8>>) of
{ok, {Before, After}} ->
case gleam_stdlib:string_starts_with(After, <<"$"/utf8>>) of
true ->
transform_template_vars_loop(
gleam@string:drop_start(After, 1),
<<<<Acc/binary, Before/binary>>/binary, "$$"/utf8>>
);
false ->
case gleam@string:split_once(After, <<"$"/utf8>>) of
{ok, {Var_content, Rest}} ->
Transformed = gleam@string:replace(
Var_content,
<<".not"/utf8>>,
<<":not"/utf8>>
),
transform_template_vars_loop(
Rest,
<<<<<<<<Acc/binary, Before/binary>>/binary,
"$$"/utf8>>/binary,
Transformed/binary>>/binary,
"$$"/utf8>>
);
{error, nil} ->
<<<<<<Acc/binary, Before/binary>>/binary, "$"/utf8>>/binary,
After/binary>>
end
end;
{error, nil} ->
<<Acc/binary, Remaining/binary>>
end.
-file("src/caffeine_lang/frontend/lowering.gleam", 297).
?DOC(
" Transforms template variables from $var->attr$ to $$var->attr$$ format.\n"
" Also handles $var->attr.not$ to $$var->attr:not$$ format.\n"
).
-spec transform_template_vars(binary()) -> binary().
transform_template_vars(S) ->
transform_template_vars_loop(S, <<""/utf8>>).
-file("src/caffeine_lang/frontend/lowering.gleam", 273).
?DOC(false).
-spec literal_to_value(caffeine_lang@frontend@ast:literal()) -> caffeine_lang@value:value().
literal_to_value(Lit) ->
case Lit of
{literal_string, S} ->
{string_value, transform_template_vars(S)};
{literal_integer, I} ->
{int_value, I};
{literal_float, F} ->
{float_value, F};
literal_true ->
{bool_value, true};
literal_false ->
{bool_value, false};
{literal_list, Elements} ->
{list_value, gleam@list:map(Elements, fun literal_to_value/1)};
{literal_struct, Fields, _} ->
_pipe = Fields,
_pipe@1 = gleam@list:filter_map(
_pipe,
fun(Field) -> case erlang:element(3, Field) of
{literal_value, Inner} ->
{ok,
{erlang:element(2, Field),
literal_to_value(Inner)}};
{type_value, _} ->
{error, nil}
end end
),
_pipe@2 = maps:from_list(_pipe@1),
{dict_value, _pipe@2}
end.
-file("src/caffeine_lang/frontend/lowering.gleam", 260).
?DOC(" Converts a struct's literal-valued fields to an inputs dict.\n").
-spec struct_to_inputs(caffeine_lang@frontend@ast:struct()) -> gleam@dict:dict(binary(), caffeine_lang@value:value()).
struct_to_inputs(S) ->
_pipe = erlang:element(2, S),
_pipe@1 = gleam@list:filter_map(
_pipe,
fun(Field) -> case erlang:element(3, Field) of
{literal_value, Lit} ->
{ok, {erlang:element(2, Field), literal_to_value(Lit)}};
{type_value, _} ->
{error, nil}
end end
),
maps:from_list(_pipe@1).
-file("src/caffeine_lang/frontend/lowering.gleam", 100).
?DOC(" Generates a single expectation from an AST item.\n").
-spec generate_expect_item(
caffeine_lang@frontend@ast:expect_item(),
binary(),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable())
) -> caffeine_lang@linker@expectations:expectation().
generate_expect_item(Item, Blueprint, Extendables) ->
Merged_provides = merge_expect_extends(Item, Extendables),
Inputs = struct_to_inputs(Merged_provides),
{expectation, erlang:element(2, Item), Blueprint, Inputs}.
-file("src/caffeine_lang/frontend/lowering.gleam", 39).
?DOC(false).
-spec lower_expectations(caffeine_lang@frontend@ast:expects_file()) -> list(caffeine_lang@linker@expectations:expectation()).
lower_expectations(File) ->
Extendables = build_extendable_map(erlang:element(2, File)),
_pipe = erlang:element(3, File),
gleam@list:flat_map(_pipe, fun(Block) -> _pipe@1 = erlang:element(3, Block),
gleam@list:map(
_pipe@1,
fun(Item) ->
generate_expect_item(
Item,
erlang:element(2, Block),
Extendables
)
end
) end).
-file("src/caffeine_lang/frontend/lowering.gleam", 221).
?DOC(" Resolves inner types of a collection.\n").
-spec resolve_collection(
caffeine_lang@types:collection_types(caffeine_lang@types:parsed_type()),
gleam@dict:dict(binary(), caffeine_lang@types:parsed_type())
) -> caffeine_lang@types:collection_types(caffeine_lang@types:accepted_types()).
resolve_collection(Collection, Aliases) ->
case Collection of
{list, Inner} ->
{list, resolve_type_aliases(Inner, Aliases)};
{dict, Key, Value} ->
{dict,
resolve_type_aliases(Key, Aliases),
resolve_type_aliases(Value, Aliases)}
end.
-file("src/caffeine_lang/frontend/lowering.gleam", 195).
?DOC(
" Resolves all ParsedTypeAliasRef instances, converting ParsedType to AcceptedTypes.\n"
" This is the resolution boundary where parsed types become fully resolved types.\n"
).
-spec resolve_type_aliases(
caffeine_lang@types:parsed_type(),
gleam@dict:dict(binary(), caffeine_lang@types:parsed_type())
) -> caffeine_lang@types:accepted_types().
resolve_type_aliases(T, Aliases) ->
case T of
{parsed_primitive, P} ->
{primitive_type, P};
{parsed_type_alias_ref, Name} ->
case gleam_stdlib:map_get(Aliases, Name) of
{ok, Resolved} ->
resolve_type_aliases(Resolved, Aliases);
{error, _} ->
{primitive_type, string}
end;
{parsed_collection, Collection} ->
{collection_type, resolve_collection(Collection, Aliases)};
{parsed_modifier, Modifier} ->
{modifier_type, resolve_modifier(Modifier, Aliases)};
{parsed_refinement, Refinement} ->
{refinement_type, resolve_refinement(Refinement, Aliases)};
{parsed_record, Fields} ->
{record_type,
gleam@dict:map_values(
Fields,
fun(_, V) -> resolve_type_aliases(V, Aliases) end
)}
end.
-file("src/caffeine_lang/frontend/lowering.gleam", 176).
?DOC(
" Converts a struct's type-valued fields to a params dict.\n"
" Resolves type alias references before storing.\n"
).
-spec struct_to_params(
caffeine_lang@frontend@ast:struct(),
gleam@dict:dict(binary(), caffeine_lang@types:parsed_type())
) -> gleam@dict:dict(binary(), caffeine_lang@types:accepted_types()).
struct_to_params(S, Type_aliases) ->
_pipe = erlang:element(2, S),
_pipe@1 = gleam@list:filter_map(
_pipe,
fun(Field) -> case erlang:element(3, Field) of
{type_value, T} ->
Resolved = resolve_type_aliases(T, Type_aliases),
{ok, {erlang:element(2, Field), Resolved}};
{literal_value, _} ->
{error, nil}
end end
),
maps:from_list(_pipe@1).
-file("src/caffeine_lang/frontend/lowering.gleam", 69).
?DOC(" Generates a single blueprint from an AST item.\n").
-spec generate_blueprint_item(
caffeine_lang@frontend@ast:blueprint_item(),
list(caffeine_lang@frontend@ast:parsed_artifact_ref()),
gleam@dict:dict(binary(), caffeine_lang@frontend@ast:extendable()),
gleam@dict:dict(binary(), caffeine_lang@types:parsed_type())
) -> caffeine_lang@linker@blueprints:blueprint().
generate_blueprint_item(Item, Parsed_artifacts, Extendables, Type_aliases) ->
Artifact_refs = gleam@list:map(Parsed_artifacts, fun lower_artifact_ref/1),
{Merged_requires, Merged_provides} = merge_blueprint_extends(
Item,
Extendables
),
Params = struct_to_params(Merged_requires, Type_aliases),
Inputs = struct_to_inputs(Merged_provides),
{blueprint, erlang:element(2, Item), Artifact_refs, Params, Inputs}.
-file("src/caffeine_lang/frontend/lowering.gleam", 24).
?DOC(false).
-spec lower_blueprints(caffeine_lang@frontend@ast:blueprints_file()) -> list(caffeine_lang@linker@blueprints:blueprint()).
lower_blueprints(File) ->
Type_aliases = build_type_alias_map(erlang:element(2, File)),
Extendables = build_extendable_map(erlang:element(3, File)),
_pipe = erlang:element(4, File),
gleam@list:flat_map(_pipe, fun(Block) -> _pipe@1 = erlang:element(3, Block),
gleam@list:map(
_pipe@1,
fun(Item) ->
generate_blueprint_item(
Item,
erlang:element(2, Block),
Extendables,
Type_aliases
)
end
) end).
-file("src/caffeine_lang/frontend/lowering.gleam", 236).
?DOC(" Resolves inner types of a modifier.\n").
-spec resolve_modifier(
caffeine_lang@types:modifier_types(caffeine_lang@types:parsed_type()),
gleam@dict:dict(binary(), caffeine_lang@types:parsed_type())
) -> caffeine_lang@types:modifier_types(caffeine_lang@types:accepted_types()).
resolve_modifier(Modifier, Aliases) ->
case Modifier of
{optional, Inner} ->
{optional, resolve_type_aliases(Inner, Aliases)};
{defaulted, Inner@1, Default} ->
{defaulted, resolve_type_aliases(Inner@1, Aliases), Default}
end.
-file("src/caffeine_lang/frontend/lowering.gleam", 248).
?DOC(" Resolves inner types of a refinement.\n").
-spec resolve_refinement(
caffeine_lang@types:refinement_types(caffeine_lang@types:parsed_type()),
gleam@dict:dict(binary(), caffeine_lang@types:parsed_type())
) -> caffeine_lang@types:refinement_types(caffeine_lang@types:accepted_types()).
resolve_refinement(Refinement, Aliases) ->
case Refinement of
{one_of, Inner, Values} ->
{one_of, resolve_type_aliases(Inner, Aliases), Values};
{inclusive_range, Inner@1, Low, High} ->
{inclusive_range, resolve_type_aliases(Inner@1, Aliases), Low, High}
end.