Current section

Files

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

src/caffeine_lang@frontend@validator.erl

-module(caffeine_lang@frontend@validator).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/frontend/validator.gleam").
-export([validate_blueprints_file/1, validate_expects_file/1]).
-export_type([validator_error/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 validator_error() :: {duplicate_extendable, binary()} |
{undefined_extendable, binary(), binary(), list(binary())} |
{duplicate_extends_reference, binary(), binary()} |
{invalid_extendable_kind, binary(), binary(), binary()} |
{undefined_type_alias, binary(), binary(), list(binary())} |
{duplicate_type_alias, binary()} |
{circular_type_alias, binary(), list(binary())} |
{invalid_dict_key_type_alias, binary(), binary(), binary()} |
{extendable_overshadowing, binary(), binary(), binary()} |
{extendable_type_alias_name_collision, binary()} |
{invalid_refinement_value, binary(), binary(), binary()} |
{invalid_percentage_bounds, binary(), binary()}.
-file("src/caffeine_lang/frontend/validator.gleam", 165).
-spec validate_no_duplicates_loop(
list(NBE),
fun((NBE) -> binary()),
fun((binary()) -> validator_error()),
gleam@set:set(binary())
) -> {ok, nil} | {error, validator_error()}.
validate_no_duplicates_loop(Items, Get_name, Make_error, Seen) ->
case Items of
[] ->
{ok, nil};
[First | Rest] ->
Name = Get_name(First),
gleam@bool:guard(
gleam@set:contains(Seen, Name),
{error, Make_error(Name)},
fun() ->
validate_no_duplicates_loop(
Rest,
Get_name,
Make_error,
gleam@set:insert(Seen, Name)
)
end
)
end.
-file("src/caffeine_lang/frontend/validator.gleam", 157).
?DOC(" Validates that no two items in a list share the same name.\n").
-spec validate_no_duplicates(
list(NBA),
fun((NBA) -> binary()),
fun((binary()) -> validator_error())
) -> {ok, nil} | {error, validator_error()}.
validate_no_duplicates(Items, Get_name, Make_error) ->
validate_no_duplicates_loop(Items, Get_name, Make_error, gleam@set:new()).
-file("src/caffeine_lang/frontend/validator.gleam", 190).
?DOC(" Validates that no extendable shares a name with a type alias.\n").
-spec validate_no_extendable_type_alias_collision(
list(caffeine_lang@frontend@ast:extendable()),
list(caffeine_lang@frontend@ast:type_alias())
) -> {ok, nil} | {error, validator_error()}.
validate_no_extendable_type_alias_collision(Extendables, Type_aliases) ->
Type_alias_names = begin
_pipe = Type_aliases,
_pipe@1 = gleam@list:map(_pipe, fun(Ta) -> erlang:element(2, Ta) end),
gleam@set:from_list(_pipe@1)
end,
gleam@list:try_each(
Extendables,
fun(Ext) ->
gleam@bool:guard(
gleam@set:contains(Type_alias_names, erlang:element(2, Ext)),
{error,
{extendable_type_alias_name_collision,
erlang:element(2, Ext)}},
fun() -> {ok, nil} end
)
end
).
-file("src/caffeine_lang/frontend/validator.gleam", 209).
?DOC(" Validates that all extendables in an expects file are Provides kind.\n").
-spec validate_extendables_are_provides(
list(caffeine_lang@frontend@ast:extendable())
) -> {ok, nil} | {error, validator_error()}.
validate_extendables_are_provides(Extendables) ->
case Extendables of
[] ->
{ok, nil};
[First | Rest] ->
case erlang:element(3, First) of
extendable_provides ->
validate_extendables_are_provides(Rest);
extendable_requires ->
{error,
{invalid_extendable_kind,
erlang:element(2, First),
<<"Provides"/utf8>>,
<<"Requires"/utf8>>}}
end
end.
-file("src/caffeine_lang/frontend/validator.gleam", 293).
?DOC(" Validates that all names in extends list exist as extendables.\n").
-spec validate_extends_exist(list(binary()), binary(), gleam@set:set(binary())) -> {ok,
nil} |
{error, validator_error()}.
validate_extends_exist(Extends, Item_name, Extendable_names) ->
case Extends of
[] ->
{ok, nil};
[First | Rest] ->
gleam@bool:guard(
not gleam@set:contains(Extendable_names, First),
{error,
{undefined_extendable,
First,
Item_name,
gleam@set:to_list(Extendable_names)}},
fun() ->
validate_extends_exist(Rest, Item_name, Extendable_names)
end
)
end.
-file("src/caffeine_lang/frontend/validator.gleam", 322).
-spec validate_no_duplicate_extends_loop(
list(binary()),
binary(),
gleam@set:set(binary())
) -> {ok, nil} | {error, validator_error()}.
validate_no_duplicate_extends_loop(Extends, Item_name, Seen) ->
case Extends of
[] ->
{ok, nil};
[First | Rest] ->
gleam@bool:guard(
gleam@set:contains(Seen, First),
{error, {duplicate_extends_reference, First, Item_name}},
fun() ->
validate_no_duplicate_extends_loop(
Rest,
Item_name,
gleam@set:insert(Seen, First)
)
end
)
end.
-file("src/caffeine_lang/frontend/validator.gleam", 315).
?DOC(" Validates that no extendable is referenced twice in the same extends list.\n").
-spec validate_no_duplicate_extends(list(binary()), binary()) -> {ok, nil} |
{error, validator_error()}.
validate_no_duplicate_extends(Extends, Item_name) ->
validate_no_duplicate_extends_loop(Extends, Item_name, gleam@set:new()).
-file("src/caffeine_lang/frontend/validator.gleam", 347).
?DOC(" Builds a map of extendable name to its field names for overshadowing checks.\n").
-spec build_extendable_field_map(list(caffeine_lang@frontend@ast:extendable())) -> gleam@dict:dict(binary(), gleam@set:set(binary())).
build_extendable_field_map(Extendables) ->
_pipe = Extendables,
_pipe@3 = gleam@list:map(
_pipe,
fun(E) ->
Field_names = begin
_pipe@1 = erlang:element(2, erlang:element(4, E)),
_pipe@2 = gleam@list:map(
_pipe@1,
fun(F) -> erlang:element(2, F) end
),
gleam@set:from_list(_pipe@2)
end,
{erlang:element(2, E), Field_names}
end
),
maps:from_list(_pipe@3).
-file("src/caffeine_lang/frontend/validator.gleam", 362).
?DOC(" Validates that an item's field sets don't overshadow fields from its extended extendables.\n").
-spec validate_no_overshadowing(
binary(),
list(binary()),
list(gleam@set:set(binary())),
gleam@dict:dict(binary(), gleam@set:set(binary()))
) -> {ok, nil} | {error, validator_error()}.
validate_no_overshadowing(Item_name, Extends, Field_sets, Extendable_map) ->
gleam@list:try_each(
Extends,
fun(Ext_name) -> case gleam_stdlib:map_get(Extendable_map, Ext_name) of
{error, _} ->
{ok, nil};
{ok, Ext_fields} ->
gleam@list:try_each(
Field_sets,
fun(Item_fields) ->
case begin
_pipe = gleam@set:intersection(
Item_fields,
Ext_fields
),
gleam@set:to_list(_pipe)
end of
[] ->
{ok, nil};
[Field | _] ->
{error,
{extendable_overshadowing,
Field,
Item_name,
Ext_name}}
end
end
)
end end
).
-file("src/caffeine_lang/frontend/validator.gleam", 229).
?DOC(" Validates extends references for blueprint items.\n").
-spec validate_blueprint_items_extends(
list(caffeine_lang@frontend@ast:blueprint_item()),
list(caffeine_lang@frontend@ast:extendable())
) -> {ok, nil} | {error, validator_error()}.
validate_blueprint_items_extends(Items, Extendables) ->
Extendable_names = begin
_pipe = Extendables,
_pipe@1 = gleam@list:map(_pipe, fun(E) -> erlang:element(2, E) end),
gleam@set:from_list(_pipe@1)
end,
Extendable_map = build_extendable_field_map(Extendables),
gleam@list:try_each(
Items,
fun(Item) ->
gleam@result:'try'(
validate_extends_exist(
erlang:element(3, Item),
erlang:element(2, Item),
Extendable_names
),
fun(_) ->
gleam@result:'try'(
validate_no_duplicate_extends(
erlang:element(3, Item),
erlang:element(2, Item)
),
fun(_) ->
Requires_fields = begin
_pipe@2 = erlang:element(
2,
erlang:element(4, Item)
),
_pipe@3 = gleam@list:map(
_pipe@2,
fun(F) -> erlang:element(2, F) end
),
gleam@set:from_list(_pipe@3)
end,
Provides_fields = begin
_pipe@4 = erlang:element(
2,
erlang:element(5, Item)
),
_pipe@5 = gleam@list:map(
_pipe@4,
fun(F@1) -> erlang:element(2, F@1) end
),
gleam@set:from_list(_pipe@5)
end,
validate_no_overshadowing(
erlang:element(2, Item),
erlang:element(3, Item),
[Requires_fields, Provides_fields],
Extendable_map
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/validator.gleam", 262).
?DOC(" Validates extends references for expect items.\n").
-spec validate_expect_items_extends(
list(caffeine_lang@frontend@ast:expect_item()),
list(caffeine_lang@frontend@ast:extendable())
) -> {ok, nil} | {error, validator_error()}.
validate_expect_items_extends(Items, Extendables) ->
Extendable_names = begin
_pipe = Extendables,
_pipe@1 = gleam@list:map(_pipe, fun(E) -> erlang:element(2, E) end),
gleam@set:from_list(_pipe@1)
end,
Extendable_map = build_extendable_field_map(Extendables),
gleam@list:try_each(
Items,
fun(Item) ->
gleam@result:'try'(
validate_extends_exist(
erlang:element(3, Item),
erlang:element(2, Item),
Extendable_names
),
fun(_) ->
gleam@result:'try'(
validate_no_duplicate_extends(
erlang:element(3, Item),
erlang:element(2, Item)
),
fun(_) ->
Provides_fields = begin
_pipe@2 = erlang:element(
2,
erlang:element(4, Item)
),
_pipe@3 = gleam@list:map(
_pipe@2,
fun(F) -> erlang:element(2, F) end
),
gleam@set:from_list(_pipe@3)
end,
validate_no_overshadowing(
erlang:element(2, Item),
erlang:element(3, Item),
[Provides_fields],
Extendable_map
)
end
)
end
)
end
).
-file("src/caffeine_lang/frontend/validator.gleam", 392).
?DOC(" Builds a map of type alias name to its type for validation.\n").
-spec build_type_alias_map(list(caffeine_lang@frontend@ast:type_alias())) -> list({binary(),
caffeine_lang@types:parsed_type()}).
build_type_alias_map(Type_aliases) ->
caffeine_lang@frontend@ast:build_type_alias_pairs(Type_aliases).
-file("src/caffeine_lang/frontend/validator.gleam", 417).
?DOC(
" Checks if a type contains a circular reference.\n"
" Uses try_each_inner_parsed to handle the structural decomposition of compound types,\n"
" with leaf-specific logic for ParsedPrimitive and ParsedTypeAliasRef.\n"
).
-spec validate_type_alias_not_circular(
binary(),
caffeine_lang@types:parsed_type(),
list({binary(), caffeine_lang@types:parsed_type()}),
list(binary()),
gleam@set:set(binary())
) -> {ok, nil} | {error, validator_error()}.
validate_type_alias_not_circular(
Original_name,
Typ,
Type_alias_map,
Visited_path,
Visited_set
) ->
case Typ of
{parsed_primitive, _} ->
{ok, nil};
{parsed_type_alias_ref, Name} ->
gleam@bool:guard(
gleam@set:contains(Visited_set, Name),
{error, {circular_type_alias, Original_name, Visited_path}},
fun() -> case gleam@list:key_find(Type_alias_map, Name) of
{ok, Resolved} ->
validate_type_alias_not_circular(
Original_name,
Resolved,
Type_alias_map,
[Name | Visited_path],
gleam@set:insert(Visited_set, Name)
);
{error, _} ->
{ok, nil}
end end
);
_ ->
caffeine_lang@types:try_each_inner_parsed(
Typ,
fun(Inner) ->
validate_type_alias_not_circular(
Original_name,
Inner,
Type_alias_map,
Visited_path,
Visited_set
)
end
)
end.
-file("src/caffeine_lang/frontend/validator.gleam", 399).
?DOC(" Validates that no type alias has circular references.\n").
-spec validate_no_circular_type_aliases(
list(caffeine_lang@frontend@ast:type_alias())
) -> {ok, nil} | {error, validator_error()}.
validate_no_circular_type_aliases(Type_aliases) ->
Type_alias_map = build_type_alias_map(Type_aliases),
gleam@list:try_each(
Type_aliases,
fun(Ta) ->
validate_type_alias_not_circular(
erlang:element(2, Ta),
erlang:element(3, Ta),
Type_alias_map,
[erlang:element(2, Ta)],
gleam@set:from_list([erlang:element(2, Ta)])
)
end
).
-file("src/caffeine_lang/frontend/validator.gleam", 623).
?DOC(" Checks if a parsed type is String-based (String primitive or String refinement).\n").
-spec is_string_based_parsed_type(caffeine_lang@types:parsed_type()) -> boolean().
is_string_based_parsed_type(Typ) ->
case Typ of
{parsed_primitive, string} ->
true;
{parsed_refinement, {one_of, {parsed_primitive, string}, _}} ->
true;
_ ->
false
end.
-file("src/caffeine_lang/frontend/validator.gleam", 584).
?DOC(" Validates that a Dict key type resolves to a String-based type.\n").
-spec validate_dict_key_type(
caffeine_lang@types:parsed_type(),
binary(),
list({binary(), caffeine_lang@types:parsed_type()})
) -> {ok, nil} | {error, validator_error()}.
validate_dict_key_type(Key_type, Context_name, Type_alias_map) ->
case Key_type of
{parsed_primitive, string} ->
{ok, nil};
{parsed_type_alias_ref, Alias_name} ->
case gleam@list:key_find(Type_alias_map, Alias_name) of
{ok, Resolved} ->
gleam@bool:guard(
is_string_based_parsed_type(Resolved),
{ok, nil},
fun() ->
{error,
{invalid_dict_key_type_alias,
Alias_name,
caffeine_lang@types:parsed_type_to_string(
Resolved
),
Context_name}}
end
);
{error, _} ->
{ok, nil}
end;
{parsed_refinement, {one_of, {parsed_primitive, string}, _}} ->
{ok, nil};
_ ->
{error,
{invalid_dict_key_type_alias,
<<"inline"/utf8>>,
caffeine_lang@types:parsed_type_to_string(Key_type),
Context_name}}
end.
-file("src/caffeine_lang/frontend/validator.gleam", 669).
?DOC(" Extracts the primitive type from a ParsedType, unwrapping Defaulted modifiers.\n").
-spec extract_primitive_from_parsed(caffeine_lang@types:parsed_type()) -> {ok,
caffeine_lang@types:primitive_types()} |
{error, nil}.
extract_primitive_from_parsed(Typ) ->
case Typ of
{parsed_primitive, Primitive} ->
{ok, Primitive};
{parsed_modifier, {defaulted, Inner, _}} ->
extract_primitive_from_parsed(Inner);
_ ->
{error, nil}
end.
-file("src/caffeine_lang/frontend/validator.gleam", 678).
?DOC(" Validates that a string value is valid for the given primitive type.\n").
-spec validate_string_matches_primitive(
binary(),
caffeine_lang@types:primitive_types(),
binary()
) -> {ok, nil} | {error, validator_error()}.
validate_string_matches_primitive(Value, Primitive, Context_name) ->
Is_valid = case Primitive of
string ->
true;
{semantic_type, _} ->
true;
boolean ->
(Value =:= <<"true"/utf8>>) orelse (Value =:= <<"false"/utf8>>);
{numeric_type, integer} ->
gleam@result:is_ok(gleam_stdlib:parse_int(Value));
{numeric_type, float} ->
gleam@result:is_ok(gleam_stdlib:parse_float(Value));
{numeric_type, percentage} ->
Raw = case gleam_stdlib:string_ends_with(Value, <<"%"/utf8>>) of
true ->
gleam@string:drop_end(Value, 1);
false ->
Value
end,
case gleam_stdlib:parse_float(Raw) of
{ok, F} ->
gleam@bool:guard(
(F < +0.0) orelse (F > 100.0),
(false),
fun() -> true end
);
{error, _} ->
false
end
end,
case Is_valid of
true ->
{ok, nil};
false ->
case Primitive of
{numeric_type, percentage} ->
Raw@1 = case gleam_stdlib:string_ends_with(
Value,
<<"%"/utf8>>
) of
true ->
gleam@string:drop_end(Value, 1);
false ->
Value
end,
case gleam_stdlib:parse_float(Raw@1) of
{ok, _} ->
{error,
{invalid_percentage_bounds, Value, Context_name}};
{error, _} ->
{error,
{invalid_refinement_value,
Value,
caffeine_lang@types:primitive_type_to_string(
Primitive
),
Context_name}}
end;
_ ->
{error,
{invalid_refinement_value,
Value,
caffeine_lang@types:primitive_type_to_string(
Primitive
),
Context_name}}
end
end.
-file("src/caffeine_lang/frontend/validator.gleam", 636).
?DOC(" Validates that refinement string values match the declared primitive type.\n").
-spec validate_refinement_values(
caffeine_lang@types:refinement_types(caffeine_lang@types:parsed_type()),
binary()
) -> {ok, nil} | {error, validator_error()}.
validate_refinement_values(Refinement, Context_name) ->
case Refinement of
{one_of, Inner, Values} ->
case extract_primitive_from_parsed(Inner) of
{ok, Primitive} ->
_pipe = Values,
_pipe@1 = gleam@set:to_list(_pipe),
gleam@list:try_each(
_pipe@1,
fun(Value) ->
validate_string_matches_primitive(
Value,
Primitive,
Context_name
)
end
);
{error, _} ->
{ok, nil}
end;
{inclusive_range, Inner@1, Low, High} ->
case extract_primitive_from_parsed(Inner@1) of
{ok, Primitive@1} ->
gleam@result:'try'(
validate_string_matches_primitive(
Low,
Primitive@1,
Context_name
),
fun(_) ->
validate_string_matches_primitive(
High,
Primitive@1,
Context_name
)
end
);
{error, _} ->
{ok, nil}
end
end.
-file("src/caffeine_lang/frontend/validator.gleam", 523).
?DOC(
" Validates that all ParsedTypeAliasRef in a type are defined.\n"
" Uses try_each_inner_parsed to handle the structural decomposition of compound types.\n"
" Adds special Dict key validation and refinement value validation.\n"
).
-spec validate_type_refs(
caffeine_lang@types:parsed_type(),
binary(),
gleam@set:set(binary()),
list({binary(), caffeine_lang@types:parsed_type()})
) -> {ok, nil} | {error, validator_error()}.
validate_type_refs(Typ, Context_name, Type_alias_names, Type_alias_map) ->
case Typ of
{parsed_primitive, _} ->
{ok, nil};
{parsed_type_alias_ref, Name} ->
gleam@bool:guard(
gleam@set:contains(Type_alias_names, Name),
{ok, nil},
fun() ->
{error,
{undefined_type_alias,
Name,
Context_name,
gleam@set:to_list(Type_alias_names)}}
end
);
{parsed_collection, {dict, Key, _}} ->
gleam@result:'try'(
validate_dict_key_type(Key, Context_name, Type_alias_map),
fun(_) ->
caffeine_lang@types:try_each_inner_parsed(
Typ,
fun(Inner) ->
validate_type_refs(
Inner,
Context_name,
Type_alias_names,
Type_alias_map
)
end
)
end
);
{parsed_refinement, Refinement} ->
gleam@result:'try'(
validate_refinement_values(Refinement, Context_name),
fun(_) ->
caffeine_lang@types:try_each_inner_parsed(
Typ,
fun(Inner@1) ->
validate_type_refs(
Inner@1,
Context_name,
Type_alias_names,
Type_alias_map
)
end
)
end
);
_ ->
caffeine_lang@types:try_each_inner_parsed(
Typ,
fun(Inner@2) ->
validate_type_refs(
Inner@2,
Context_name,
Type_alias_names,
Type_alias_map
)
end
)
end.
-file("src/caffeine_lang/frontend/validator.gleam", 462).
?DOC(" Validates type alias definitions for type refs and refinement values.\n").
-spec validate_type_aliases_type_refs(
list(caffeine_lang@frontend@ast:type_alias()),
gleam@set:set(binary()),
list({binary(), caffeine_lang@types:parsed_type()})
) -> {ok, nil} | {error, validator_error()}.
validate_type_aliases_type_refs(Type_aliases, Type_alias_names, Type_alias_map) ->
gleam@list:try_each(
Type_aliases,
fun(Ta) ->
validate_type_refs(
erlang:element(3, Ta),
erlang:element(2, Ta),
Type_alias_names,
Type_alias_map
)
end
).
-file("src/caffeine_lang/frontend/validator.gleam", 505).
?DOC(" Validates type alias references in a list of fields.\n").
-spec validate_fields_type_refs(
list(caffeine_lang@frontend@ast:field()),
binary(),
gleam@set:set(binary()),
list({binary(), caffeine_lang@types:parsed_type()})
) -> {ok, nil} | {error, validator_error()}.
validate_fields_type_refs(
Fields,
Context_name,
Type_alias_names,
Type_alias_map
) ->
gleam@list:try_each(Fields, fun(Field) -> case erlang:element(3, Field) of
{type_value, Typ} ->
validate_type_refs(
Typ,
Context_name,
Type_alias_names,
Type_alias_map
);
{literal_value, _} ->
{ok, nil}
end end).
-file("src/caffeine_lang/frontend/validator.gleam", 473).
?DOC(" Validates type alias references in extendables.\n").
-spec validate_extendables_type_refs(
list(caffeine_lang@frontend@ast:extendable()),
gleam@set:set(binary()),
list({binary(), caffeine_lang@types:parsed_type()})
) -> {ok, nil} | {error, validator_error()}.
validate_extendables_type_refs(Extendables, Type_alias_names, Type_alias_map) ->
gleam@list:try_each(
Extendables,
fun(Ext) ->
validate_fields_type_refs(
erlang:element(2, erlang:element(4, Ext)),
erlang:element(2, Ext),
Type_alias_names,
Type_alias_map
)
end
).
-file("src/caffeine_lang/frontend/validator.gleam", 489).
?DOC(" Validates type alias references in blueprint items.\n").
-spec validate_blueprint_items_type_refs(
list(caffeine_lang@frontend@ast:blueprint_item()),
gleam@set:set(binary()),
list({binary(), caffeine_lang@types:parsed_type()})
) -> {ok, nil} | {error, validator_error()}.
validate_blueprint_items_type_refs(Items, Type_alias_names, Type_alias_map) ->
gleam@list:try_each(
Items,
fun(Item) ->
validate_fields_type_refs(
erlang:element(2, erlang:element(4, Item)),
erlang:element(2, Item),
Type_alias_names,
Type_alias_map
)
end
).
-file("src/caffeine_lang/frontend/validator.gleam", 746).
?DOC(" Converts a single-error Result to a list of errors (empty on Ok).\n").
-spec errors_to_list({ok, nil} | {error, validator_error()}) -> list(validator_error()).
errors_to_list(Result) ->
case Result of
{ok, _} ->
[];
{error, Err} ->
[Err]
end.
-file("src/caffeine_lang/frontend/validator.gleam", 754).
?DOC(" Collects errors from a list of independent validation results.\n").
-spec collect_errors(list({ok, nil} | {error, validator_error()})) -> list(validator_error()).
collect_errors(Results) ->
_pipe = Results,
gleam@list:flat_map(_pipe, fun errors_to_list/1).
-file("src/caffeine_lang/frontend/validator.gleam", 762).
?DOC(
" Guards against accumulated errors. If errors is non-empty, returns them;\n"
" otherwise continues with the provided callback.\n"
).
-spec guard_errors(
list(validator_error()),
fun(() -> {ok, NEV} | {error, list(validator_error())})
) -> {ok, NEV} | {error, list(validator_error())}.
guard_errors(Errors, Otherwise) ->
case Errors of
[] ->
Otherwise();
_ ->
{error, Errors}
end.
-file("src/caffeine_lang/frontend/validator.gleam", 64).
?DOC(false).
-spec validate_blueprints_file(
caffeine_lang@frontend@ast:blueprints_file(caffeine_lang@frontend@ast:parsed())
) -> {ok,
caffeine_lang@frontend@ast:blueprints_file(caffeine_lang@frontend@ast:validated())} |
{error, list(validator_error())}.
validate_blueprints_file(File) ->
Type_aliases = erlang:element(2, File),
Extendables = erlang:element(3, File),
Items = begin
_pipe = erlang:element(4, File),
gleam@list:flat_map(_pipe, fun(Block) -> erlang:element(3, Block) end)
end,
Type_alias_errors = begin
_pipe@1 = validate_no_duplicates(
Type_aliases,
fun(Ta) -> erlang:element(2, Ta) end,
fun(Field@0) -> {duplicate_type_alias, Field@0} end
),
_pipe@2 = gleam@result:'try'(
_pipe@1,
fun(_) -> validate_no_circular_type_aliases(Type_aliases) end
),
errors_to_list(_pipe@2)
end,
Extendable_errors = collect_errors(
[validate_no_duplicates(
Extendables,
fun(E) -> erlang:element(2, E) end,
fun(Field@0) -> {duplicate_extendable, Field@0} end
),
validate_no_extendable_type_alias_collision(
Extendables,
Type_aliases
)]
),
Structural_errors = lists:append(Type_alias_errors, Extendable_errors),
guard_errors(
Structural_errors,
fun() ->
Type_alias_names = begin
_pipe@3 = Type_aliases,
_pipe@4 = gleam@list:map(
_pipe@3,
fun(Ta@1) -> erlang:element(2, Ta@1) end
),
gleam@set:from_list(_pipe@4)
end,
Type_alias_map = build_type_alias_map(Type_aliases),
Type_ref_errors = collect_errors(
[validate_type_aliases_type_refs(
Type_aliases,
Type_alias_names,
Type_alias_map
),
validate_extendables_type_refs(
Extendables,
Type_alias_names,
Type_alias_map
),
validate_blueprint_items_type_refs(
Items,
Type_alias_names,
Type_alias_map
)]
),
Extends_errors = begin
_pipe@5 = validate_blueprint_items_extends(Items, Extendables),
errors_to_list(_pipe@5)
end,
Dependent_errors = lists:append(Type_ref_errors, Extends_errors),
guard_errors(
Dependent_errors,
fun() ->
{ok,
caffeine_lang@frontend@ast:promote_blueprints_file(File)}
end
)
end
).
-file("src/caffeine_lang/frontend/validator.gleam", 132).
?DOC(false).
-spec validate_expects_file(
caffeine_lang@frontend@ast:expects_file(caffeine_lang@frontend@ast:parsed())
) -> {ok,
caffeine_lang@frontend@ast:expects_file(caffeine_lang@frontend@ast:validated())} |
{error, list(validator_error())}.
validate_expects_file(File) ->
Extendables = erlang:element(2, File),
Items = begin
_pipe = erlang:element(3, File),
gleam@list:flat_map(_pipe, fun(Block) -> erlang:element(3, Block) end)
end,
Structural_errors = collect_errors(
[validate_no_duplicates(
Extendables,
fun(E) -> erlang:element(2, E) end,
fun(Field@0) -> {duplicate_extendable, Field@0} end
),
validate_extendables_are_provides(Extendables)]
),
guard_errors(
Structural_errors,
fun() ->
Extends_errors = begin
_pipe@1 = validate_expect_items_extends(Items, Extendables),
errors_to_list(_pipe@1)
end,
guard_errors(
Extends_errors,
fun() ->
{ok, caffeine_lang@frontend@ast:promote_expects_file(File)}
end
)
end
).