Packages

A markup language to define ER schemas

Current section

Files

Jump to
prequel src prequel@internals@parser.erl
Raw

src/prequel@internals@parser.erl

-module(prequel@internals@parser).
-compile([no_auto_import, nowarn_unused_vars]).
-export([parse/1]).
-spec 'try'(
{ok, {HYR, list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()},
fun((HYR, list({prequel@internals@token:token(), prequel@span:span()})) -> {ok,
{HYU, list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()})
) -> {ok, {HYU, list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
'try'(Result, Do) ->
case Result of
{ok, {A, Tokens}} ->
Do(A, Tokens);
{error, Error} ->
{error, Error}
end.
-spec fail(prequel@error@parse_error:parse_error()) -> {ok,
{any(), list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
fail(Error) ->
{error, Error}.
-spec succeed(HYZ, list({prequel@internals@token:token(), prequel@span:span()})) -> {ok,
{HYZ, list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
succeed(Result, Tokens) ->
{ok, {Result, Tokens}}.
-spec totality_from_string(binary()) -> {ok, prequel@ast:totality()} |
{error, nil}.
totality_from_string(String) ->
case String of
<<"total"/utf8>> ->
{ok, total};
<<"partial"/utf8>> ->
{ok, partial};
_ ->
{error, nil}
end.
-spec overlapping_from_string(binary()) -> {ok, prequel@ast:overlapping()} |
{error, nil}.
overlapping_from_string(String) ->
case String of
<<"overlapped"/utf8>> ->
{ok, overlapped};
<<"disjoint"/utf8>> ->
{ok, disjoint};
_ ->
{error, nil}
end.
-spec parse_attribute_type(
list({prequel@internals@token:token(), prequel@span:span()})
) -> {ok,
{prequel@ast:type(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_attribute_type(Tokens) ->
_pipe = no_type,
succeed(_pipe, Tokens).
-spec parse_number(binary(), prequel@span:span(), prequel@span:span()) -> {ok,
integer()} |
{error, prequel@error@parse_error:parse_error()}.
parse_number(Raw_number, Raw_number_span, Enclosing_span) ->
_pipe = gleam@int:parse(Raw_number),
gleam@result:replace_error(
_pipe,
{internal_error,
{some, <<"TODO: add hint"/utf8>>},
{some, Enclosing_span},
Raw_number_span,
<<"This was assumed to be a number"/utf8>>}
).
-spec parse_cardinality(
list({prequel@internals@token:token(), prequel@span:span()}),
boolean(),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{prequel@ast:cardinality(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_cardinality(Tokens, Lenient, Enclosing_span, Preceding_span) ->
case Tokens of
[{open_parens, Start},
{{number, Raw_lower}, Raw_lower_span},
{minus, _},
{{number, Raw_upper}, Raw_upper_span},
{close_parens, End} |
Tokens@1] ->
Result = parse_number(Raw_lower, Raw_lower_span, Enclosing_span),
gleam@result:'try'(
Result,
fun(Lower) ->
Result@1 = parse_number(
Raw_upper,
Raw_upper_span,
Enclosing_span
),
gleam@result:'try'(
Result@1,
fun(Upper) ->
_pipe = {bounded,
prequel@span:merge(Start, End),
Lower,
Upper},
succeed(_pipe, Tokens@1)
end
)
end
);
[{open_parens, Start@1},
{{number, Raw_lower@1}, Raw_lower_span@1},
{minus, _},
{{word, <<"N"/utf8>>}, _},
{close_parens, End@1} |
Tokens@2] ->
Result@2 = parse_number(
Raw_lower@1,
Raw_lower_span@1,
Enclosing_span
),
gleam@result:'try'(
Result@2,
fun(Lower@1) ->
_pipe@1 = {unbounded,
prequel@span:merge(Start@1, End@1),
Lower@1},
succeed(_pipe@1, Tokens@2)
end
);
[{open_parens, _},
{{number, _}, _},
{minus, _},
{{word, _}, Span},
{close_parens, _} |
_] ->
_pipe@2 = {wrong_letter_in_unbounded_cardinality,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
Span},
fail(_pipe@2);
[{open_parens, Start@2},
{{number, _}, _},
{minus, _},
{{number, _}, End@2} |
_] ->
_pipe@3 = {incomplete_cardinality,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
prequel@span:merge(Start@2, End@2),
<<"a closed parentheses"/utf8>>},
fail(_pipe@3);
[{open_parens, Start@2},
{{number, _}, _},
{minus, _},
{{word, _}, End@2} |
_] ->
_pipe@3 = {incomplete_cardinality,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
prequel@span:merge(Start@2, End@2),
<<"a closed parentheses"/utf8>>},
fail(_pipe@3);
[{open_parens, Start@3}, {{number, _}, _}, {minus, End@3} | _] ->
_pipe@4 = {incomplete_cardinality,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
prequel@span:merge(Start@3, End@3),
<<"an upper bound"/utf8>>},
fail(_pipe@4);
[{open_parens, Start@4}, {{number, _}, End@4} | _] ->
_pipe@5 = {incomplete_cardinality,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
prequel@span:merge(Start@4, End@4),
<<"an upper bound"/utf8>>},
fail(_pipe@5);
[{open_parens, Span@1} | _] ->
_pipe@6 = {incomplete_cardinality,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
Span@1,
<<"a lower bound"/utf8>>},
fail(_pipe@6);
[{{number, _}, Span@2} | _] ->
_pipe@7 = {incomplete_cardinality,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
Span@2,
<<"an open parentheses"/utf8>>},
fail(_pipe@7);
[_ | _] when Lenient ->
_pipe@8 = {bounded, Preceding_span, 1, 1},
succeed(_pipe@8, Tokens);
[{Token, Span@3} | _] ->
_pipe@9 = {wrong_cardinality_annotation,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
Preceding_span,
prequel@internals@token:to_string(Token),
Span@3},
fail(_pipe@9);
[] ->
_pipe@10 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Enclosing_span},
Preceding_span,
<<"the cardinality of this element"/utf8>>},
fail(_pipe@10)
end.
-spec parse_attribute(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{prequel@ast:attribute(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_attribute(Tokens, Enclosing_span, Lollipop_span) ->
case Tokens of
[{{word, Name}, Name_span}, {colon, Colon_span} | Tokens@1] ->
'try'(
parse_attribute_type(Tokens@1),
fun(Type_, Tokens@2) ->
'try'(
parse_cardinality(
Tokens@2,
Type_ /= no_type,
Enclosing_span,
Colon_span
),
fun(Cardinality, Tokens@3) ->
_pipe = {attribute,
Name_span,
Name,
Cardinality,
Type_},
succeed(_pipe, Tokens@3)
end
)
end
);
[{{word, Name@1}, Name_span@1} | Tokens@4] ->
_pipe@1 = {attribute,
Name_span@1,
Name@1,
{bounded, Name_span@1, 1, 1},
no_type},
succeed(_pipe@1, Tokens@4);
[{Token, Span} | _] ->
_pipe@2 = {wrong_attribute_name,
{some, <<"TODO: add hint"/utf8>>},
Enclosing_span,
Lollipop_span,
prequel@internals@token:to_string(Token),
Span},
fail(_pipe@2);
[] ->
_pipe@3 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Enclosing_span},
Lollipop_span,
<<"this attribute"/utf8>>},
fail(_pipe@3)
end.
-spec parse_multi_attribute_key(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span(),
prequel@span:span(),
prequel@span:span(),
list(binary())
) -> {ok,
{prequel@ast:key(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_multi_attribute_key(
Tokens,
Entity_span,
Lollipop_span,
Last_ampersand_span,
First_word_span,
Keys
) ->
case Tokens of
[{{word, Key}, _}, {ampersand, Last_ampersand_span@1} | Tokens@1] ->
parse_multi_attribute_key(
Tokens@1,
Entity_span,
Lollipop_span,
Last_ampersand_span@1,
First_word_span,
[Key | Keys]
);
[{{word, _}, Last_word_span}, {colon, Colon_span} | _] ->
_pipe = {type_annotation_on_composed_key,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(First_word_span, Last_word_span),
Colon_span},
fail(_pipe);
[{{word, Key@1}, Last_word_span@1} | Tokens@2] ->
_pipe@1 = prequel@span:merge(First_word_span, Last_word_span@1),
_pipe@2 = {composed_key,
_pipe@1,
non_empty_list:reverse(non_empty_list:new(Key@1, Keys))},
succeed(_pipe@2, Tokens@2);
[{Token, Span} | _] ->
_pipe@3 = {incomplete_composed_key,
{some, <<"TODO: add hint"/utf8>>},
prequel@span:merge(Lollipop_span, Last_ampersand_span),
Entity_span,
prequel@internals@token:to_string(Token),
Span},
fail(_pipe@3);
[] ->
_pipe@4 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Lollipop_span,
<<"this key"/utf8>>},
fail(_pipe@4)
end.
-spec do_parse_key(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{prequel@ast:key(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
do_parse_key(Tokens, Entity_span, Lollipop_span) ->
case Tokens of
[{{word, Key}, First_word_span},
{ampersand, Last_ampersand_span} |
Tokens@1] ->
'try'(
parse_multi_attribute_key(
Tokens@1,
Entity_span,
Lollipop_span,
Last_ampersand_span,
First_word_span,
[Key]
),
fun(Key@1, Tokens@2) -> succeed(Key@1, Tokens@2) end
);
[{{word, Key@2}, Span}, {colon, _} | Tokens@3] ->
'try'(
parse_attribute_type(Tokens@3),
fun(Type_, Tokens@4) ->
succeed({single_key, Span, Key@2, {some, Type_}}, Tokens@4)
end
);
[{{word, Key@3}, Span@1} | Tokens@5] ->
succeed({single_key, Span@1, Key@3, none}, Tokens@5);
[{Token, Span@2} | _] ->
_pipe = {wrong_key_name,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
Lollipop_span,
prequel@internals@token:to_string(Token),
Span@2},
fail(_pipe);
[] ->
_pipe@1 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Lollipop_span,
<<"this key"/utf8>>},
fail(_pipe@1)
end.
-spec parse_key(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{prequel@ast:key(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_key(Tokens, Entity_span, Lollipop_span) ->
do_parse_key(Tokens, Entity_span, Lollipop_span).
-spec do_parse_inner_relationship_body(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span(),
list(prequel@ast:attribute())
) -> {ok,
{list(prequel@ast:attribute()),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
do_parse_inner_relationship_body(
Tokens,
Relationship_span,
Entity_span,
Attributes
) ->
case Tokens of
[{close_bracket, _} | Tokens@1] ->
_pipe = gleam@list:reverse(Attributes),
succeed(_pipe, Tokens@1);
[{circle_lollipop, Span} | Tokens@2] ->
'try'(
parse_attribute(Tokens@2, Relationship_span, Span),
fun(Attribute, Tokens@3) ->
do_parse_inner_relationship_body(
Tokens@3,
Relationship_span,
Entity_span,
[Attribute | Attributes]
)
end
);
[{star_lollipop, Lollipop_span} | _] ->
_pipe@1 = {key_inside_relationship,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
Lollipop_span},
fail(_pipe@1);
[{minus, Minus_span}, {{word, <<"o"/utf8>>}, O_span} | _] ->
_pipe@2 = {possible_circle_lollipop_typo,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
prequel@span:merge(Minus_span, O_span)},
fail(_pipe@2);
[{_, Token_span} | _] ->
_pipe@3 = {unexpected_token_in_binary_relationship,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
Token_span},
fail(_pipe@3);
[] ->
_pipe@4 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Relationship_span,
<<"the body of this relationship"/utf8>>},
fail(_pipe@4)
end.
-spec parse_inner_relationship_body(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{list(prequel@ast:attribute()),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_inner_relationship_body(Tokens, Relationship_span, Entity_span) ->
do_parse_inner_relationship_body(Tokens, Relationship_span, Entity_span, []).
-spec parse_inner_relationship(
list({prequel@internals@token:token(), prequel@span:span()}),
binary(),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{prequel@ast:relationship(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_inner_relationship(Tokens, Entity_name, Entity_span, Lollipop_span) ->
case Tokens of
[{{word, Relationship_name}, Relationship_span},
{colon, Colon_span} |
Tokens@1] ->
'try'(
parse_cardinality(Tokens@1, false, Entity_span, Colon_span),
fun(One_cardinality, Tokens@2) -> case Tokens@2 of
[{{word, Other_name}, Other_name_span} | Tokens@3] ->
'try'(
parse_cardinality(
Tokens@3,
false,
Entity_span,
Other_name_span
),
fun(Other_cardinality, Tokens@4) ->
One_entity = {relationship_entity,
Entity_span,
Entity_name,
One_cardinality},
Other_entity = begin
_pipe = {relationship_entity,
Other_name_span,
Other_name,
Other_cardinality},
non_empty_list:single(_pipe)
end,
case Tokens@4 of
[{open_bracket, _} | Tokens@5] ->
'try'(
parse_inner_relationship_body(
Tokens@5,
Relationship_span,
Entity_span
),
fun(Attributes, Tokens@6) ->
_pipe@1 = {relationship,
Relationship_span,
Relationship_name,
One_entity,
Other_entity,
Attributes},
succeed(_pipe@1, Tokens@6)
end
);
_ ->
_pipe@2 = Relationship_span,
_pipe@3 = {relationship,
_pipe@2,
Relationship_name,
One_entity,
Other_entity,
[]},
succeed(_pipe@3, Tokens@4)
end
end
);
[{Token, Span} | _] ->
_pipe@4 = {wrong_entity_name,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
erlang:element(2, One_cardinality),
prequel@internals@token:to_string(Token),
Span,
<<"the first cardinality annotation"/utf8>>},
fail(_pipe@4);
[] ->
_pipe@5 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Lollipop_span,
<<"this relationship"/utf8>>},
fail(_pipe@5)
end end
);
[{{word, _}, Name_span} | _] ->
_pipe@6 = {missing_cardinality_annotation,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
Name_span},
fail(_pipe@6);
[{Token@1, Span@1} | _] ->
_pipe@7 = {wrong_relationship_name,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Lollipop_span,
prequel@internals@token:to_string(Token@1),
Span@1},
fail(_pipe@7);
[] ->
_pipe@8 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Lollipop_span,
<<"this relationship"/utf8>>},
fail(_pipe@8)
end.
-spec parse_relationship_entity(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{prequel@ast:relationship_entity(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_relationship_entity(Tokens, Relationship_span, Lollipop_span) ->
case Tokens of
[{{word, Name}, Name_span}, {colon, Colon_span} | Tokens@1] ->
'try'(
parse_cardinality(
Tokens@1,
false,
Relationship_span,
Colon_span
),
fun(Cardinality, Tokens@2) ->
_pipe = {relationship_entity, Name_span, Name, Cardinality},
succeed(_pipe, Tokens@2)
end
);
[{{word, _}, Name_span@1} | _] ->
_pipe@1 = {missing_cardinality_annotation,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
Name_span@1},
fail(_pipe@1);
[{Token, Span} | _] ->
_pipe@2 = {wrong_entity_name,
{some, <<"TODO: add hint"/utf8>>},
{some, Relationship_span},
Lollipop_span,
prequel@internals@token:to_string(Token),
Span,
<<"the `->` lollipop"/utf8>>},
fail(_pipe@2);
[] ->
_pipe@3 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Relationship_span},
Lollipop_span,
<<"this entity"/utf8>>},
fail(_pipe@3)
end.
-spec do_parse(
list({prequel@internals@token:token(), prequel@span:span()}),
list(prequel@ast:entity()),
list(prequel@ast:relationship())
) -> {ok,
{prequel@ast:module_(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
do_parse(Tokens, Entities, Relationships) ->
case Tokens of
[] ->
_pipe = {module,
gleam@list:reverse(Entities),
gleam@list:reverse(Relationships)},
succeed(_pipe, []);
[{{word, <<"entity"/utf8>>}, Entity_keyword_span} | Tokens@1] ->
'try'(
parse_entity(Tokens@1, Entity_keyword_span),
fun(Entity, Tokens@2) ->
do_parse(Tokens@2, [Entity | Entities], Relationships)
end
);
[{{word, <<"relationship"/utf8>>}, Relationship_span} | Tokens@3] ->
'try'(
parse_relationship(Tokens@3, Relationship_span),
fun(Relationship, Tokens@4) ->
do_parse(Tokens@4, Entities, [Relationship | Relationships])
end
);
[{_, Span} | _] ->
_pipe@1 = {unexpected_token_in_top_level,
{some, <<"TODO: add hint"/utf8>>},
Span},
fail(_pipe@1)
end.
-spec parse(list({prequel@internals@token:token(), prequel@span:span()})) -> {ok,
prequel@ast:module_()} |
{error, prequel@error@parse_error:parse_error()}.
parse(Tokens) ->
case do_parse(Tokens, [], []) of
{ok, {Module, _}} ->
{ok, Module};
{error, Error} ->
{error, Error}
end.
-spec do_parse_entity_body(
list({prequel@internals@token:token(), prequel@span:span()}),
binary(),
prequel@span:span(),
list(prequel@ast:key()),
list(prequel@ast:attribute()),
list(prequel@ast:relationship()),
gleam@option:option(prequel@ast:hierarchy())
) -> {ok,
{prequel@ast:entity(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
do_parse_entity_body(
Tokens,
Entity_name,
Entity_span,
Keys,
Attributes,
Inner_relationships,
Children
) ->
case Tokens of
[{close_bracket, _} | Tokens@1] ->
_pipe = {entity,
Entity_span,
Entity_name,
gleam@list:reverse(Keys),
gleam@list:reverse(Attributes),
gleam@list:reverse(Inner_relationships),
Children},
succeed(_pipe, Tokens@1);
[{circle_lollipop, Lollipop_span} | Tokens@2] ->
'try'(
parse_attribute(Tokens@2, Entity_span, Lollipop_span),
fun(Attribute, Tokens@3) ->
do_parse_entity_body(
Tokens@3,
Entity_name,
Entity_span,
Keys,
[Attribute | Attributes],
Inner_relationships,
Children
)
end
);
[{star_lollipop, Lollipop_span@1} | Tokens@4] ->
'try'(
parse_key(Tokens@4, Entity_span, Lollipop_span@1),
fun(Key, Tokens@5) ->
do_parse_entity_body(
Tokens@5,
Entity_name,
Entity_span,
[Key | Keys],
Attributes,
Inner_relationships,
Children
)
end
);
[{arrow_lollipop, Lollipop_span@2} | Tokens@6] ->
'try'(
parse_inner_relationship(
Tokens@6,
Entity_name,
Entity_span,
Lollipop_span@2
),
fun(Relationship, Tokens@7) ->
do_parse_entity_body(
Tokens@7,
Entity_name,
Entity_span,
Keys,
Attributes,
[Relationship | Inner_relationships],
Children
)
end
);
[{{word, <<"total"/utf8>> = Totality_string}, Totality_span} | Tokens@8] ->
Error = {internal_error,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Totality_span,
<<"A call to `totality_from_string` failed despite this being assumed a correct totality"/utf8>>},
Result = gleam@result:replace_error(
totality_from_string(Totality_string),
Error
),
gleam@result:'try'(
Result,
fun(Totality) ->
'try'(
parse_hierarchy(
Tokens@8,
Entity_span,
Totality_span,
Children,
Totality
),
fun(Hierarchy, Tokens@9) ->
do_parse_entity_body(
Tokens@9,
Entity_name,
Entity_span,
Keys,
Attributes,
Inner_relationships,
{some, Hierarchy}
)
end
)
end
);
[{{word, <<"partial"/utf8>> = Totality_string}, Totality_span} |
Tokens@8] ->
Error = {internal_error,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Totality_span,
<<"A call to `totality_from_string` failed despite this being assumed a correct totality"/utf8>>},
Result = gleam@result:replace_error(
totality_from_string(Totality_string),
Error
),
gleam@result:'try'(
Result,
fun(Totality) ->
'try'(
parse_hierarchy(
Tokens@8,
Entity_span,
Totality_span,
Children,
Totality
),
fun(Hierarchy, Tokens@9) ->
do_parse_entity_body(
Tokens@9,
Entity_name,
Entity_span,
Keys,
Attributes,
Inner_relationships,
{some, Hierarchy}
)
end
)
end
);
[{minus, Minus_span}, {{word, <<"o"/utf8>>}, O_span} | _] ->
_pipe@1 = {possible_circle_lollipop_typo,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(Minus_span, O_span)},
fail(_pipe@1);
[{minus, Minus_span@1}, {{word, <<"*"/utf8>>}, Star_span} | _] ->
_pipe@2 = {possible_star_lollipop_typo,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(Minus_span@1, Star_span)},
fail(_pipe@2);
[{minus, Minus_span@2}, {{word, <<">"/utf8>>}, Arrow_span} | _] ->
_pipe@3 = {possible_arrow_lollipop_typo,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(Minus_span@2, Arrow_span)},
fail(_pipe@3);
[{{word, First}, First_span}, {{word, Second}, Second_span} | _] when (((First =:= <<"overlapped"/utf8>>) orelse (First =:= <<"overlapping"/utf8>>)) orelse (First =:= <<"disjoint"/utf8>>)) andalso ((Second =:= <<"total"/utf8>>) orelse (Second =:= <<"partial"/utf8>>)) ->
_pipe@4 = {wrong_order_of_hierarchy_qualifiers,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(First_span, Second_span),
First,
Second},
fail(_pipe@4);
[{{word, <<"hierarchy"/utf8>>}, Span} | _] ->
_pipe@5 = {unqualified_hierarchy,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
Span},
fail(_pipe@5);
[{_, Token_span} | _] ->
_pipe@6 = {unexpected_token_in_entity_body,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
Token_span},
fail(_pipe@6);
[] ->
_pipe@7 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
none,
Entity_span,
<<"the body of this entity"/utf8>>},
fail(_pipe@7)
end.
-spec parse_entity_body(
list({prequel@internals@token:token(), prequel@span:span()}),
binary(),
prequel@span:span()
) -> {ok,
{prequel@ast:entity(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_entity_body(Tokens, Entity_name, Entity_span) ->
do_parse_entity_body(Tokens, Entity_name, Entity_span, [], [], [], none).
-spec parse_entity(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span()
) -> {ok,
{prequel@ast:entity(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_entity(Tokens, Entity_keyword_span) ->
case Tokens of
[{{word, Entity_name}, Entity_span}, {open_bracket, _} | Tokens@1] ->
parse_entity_body(Tokens@1, Entity_name, Entity_span);
[{{word, Entity_name@1}, Entity_span@1} | Tokens@2] ->
_pipe = {entity, Entity_span@1, Entity_name@1, [], [], [], none},
succeed(_pipe, Tokens@2);
[{Token, Span} | _] ->
_pipe@1 = {wrong_entity_name,
{some, <<"TODO: add hint"/utf8>>},
none,
Entity_keyword_span,
prequel@internals@token:to_string(Token),
Span,
<<"the `entity` keyword"/utf8>>},
fail(_pipe@1);
[] ->
_pipe@2 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
none,
Entity_keyword_span,
<<"this entity"/utf8>>},
fail(_pipe@2)
end.
-spec do_parse_hierarchy_body(
list({prequel@internals@token:token(), prequel@span:span()}),
list(prequel@ast:entity()),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{non_empty_list:non_empty_list(prequel@ast:entity()),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
do_parse_hierarchy_body(Tokens, Entities, Entity_span, Hierarchy_span) ->
case Tokens of
[{close_bracket, _} | Tokens@1] ->
Error = {empty_hierarchy,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
Hierarchy_span},
_pipe = Entities,
_pipe@1 = gleam@list:reverse(_pipe),
_pipe@2 = non_empty_list:from_list(_pipe@1),
_pipe@3 = gleam@result:replace_error(_pipe@2, Error),
gleam@result:'try'(
_pipe@3,
fun(_capture) -> succeed(_capture, Tokens@1) end
);
[{{word, <<"entity"/utf8>>}, Span} | Tokens@2] ->
'try'(
parse_entity(Tokens@2, Span),
fun(Entity, Tokens@3) ->
do_parse_hierarchy_body(
Tokens@3,
[Entity | Entities],
Entity_span,
Hierarchy_span
)
end
);
[{_, Span@1} | _] ->
_pipe@4 = {unexpected_token_in_hierarchy_body,
{some, <<"TODO: add hint"/utf8>>},
Hierarchy_span,
Span@1},
fail(_pipe@4);
[] ->
_pipe@5 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Hierarchy_span,
<<"this hierarchy"/utf8>>},
fail(_pipe@5)
end.
-spec parse_hierarchy_body(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span()
) -> {ok,
{non_empty_list:non_empty_list(prequel@ast:entity()),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_hierarchy_body(Tokens, Entity_span, Hierarchy_span) ->
do_parse_hierarchy_body(Tokens, [], Entity_span, Hierarchy_span).
-spec parse_hierarchy(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span(),
prequel@span:span(),
gleam@option:option(prequel@ast:hierarchy()),
prequel@ast:totality()
) -> {ok,
{prequel@ast:hierarchy(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_hierarchy(Tokens, Entity_span, Totality_span, Entity_children, Totality) ->
case Tokens of
[{{word, <<"overlapped"/utf8>> = Word}, Word_span},
{{word, <<"hierarchy"/utf8>>}, Final_span},
{open_bracket, _} |
Tokens@1] ->
Error = {internal_error,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Word_span,
<<"A call to `overlapping_from_string` failed despite this being assumed a correct overlapping"/utf8>>},
Result = gleam@result:replace_error(
overlapping_from_string(Word),
Error
),
gleam@result:'try'(
Result,
fun(Overlapping) ->
Hierarchy_span = prequel@span:merge(
Totality_span,
Final_span
),
case Entity_children of
{some, First_hierarchy} ->
_pipe = {more_than_one_hierarchy,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
erlang:element(2, First_hierarchy),
Hierarchy_span},
fail(_pipe);
none ->
'try'(
parse_hierarchy_body(
Tokens@1,
Entity_span,
Hierarchy_span
),
fun(Entities, Tokens@2) ->
_pipe@1 = {hierarchy,
Hierarchy_span,
Overlapping,
Totality,
Entities},
succeed(_pipe@1, Tokens@2)
end
)
end
end
);
[{{word, <<"disjoint"/utf8>> = Word}, Word_span},
{{word, <<"hierarchy"/utf8>>}, Final_span},
{open_bracket, _} |
Tokens@1] ->
Error = {internal_error,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Word_span,
<<"A call to `overlapping_from_string` failed despite this being assumed a correct overlapping"/utf8>>},
Result = gleam@result:replace_error(
overlapping_from_string(Word),
Error
),
gleam@result:'try'(
Result,
fun(Overlapping) ->
Hierarchy_span = prequel@span:merge(
Totality_span,
Final_span
),
case Entity_children of
{some, First_hierarchy} ->
_pipe = {more_than_one_hierarchy,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
erlang:element(2, First_hierarchy),
Hierarchy_span},
fail(_pipe);
none ->
'try'(
parse_hierarchy_body(
Tokens@1,
Entity_span,
Hierarchy_span
),
fun(Entities, Tokens@2) ->
_pipe@1 = {hierarchy,
Hierarchy_span,
Overlapping,
Totality,
Entities},
succeed(_pipe@1, Tokens@2)
end
)
end
end
);
[{{word, <<"overlapped"/utf8>>}, _},
{{word, <<"hierarchy"/utf8>>}, Hierarchy_span@1} |
_] ->
_pipe@2 = {empty_hierarchy,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(Totality_span, Hierarchy_span@1)},
fail(_pipe@2);
[{{word, <<"disjoint"/utf8>>}, _},
{{word, <<"hierarchy"/utf8>>}, Hierarchy_span@1} |
_] ->
_pipe@2 = {empty_hierarchy,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(Totality_span, Hierarchy_span@1)},
fail(_pipe@2);
[{{word, <<"overlapped"/utf8>>}, Overlapping_span} | _] ->
_pipe@3 = {missing_hierarchy_keyword,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(Totality_span, Overlapping_span)},
fail(_pipe@3);
[{{word, <<"disjoint"/utf8>>}, Overlapping_span} | _] ->
_pipe@3 = {missing_hierarchy_keyword,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
prequel@span:merge(Totality_span, Overlapping_span)},
fail(_pipe@3);
[{Token, Span} | _] ->
_pipe@4 = {wrong_hierarchy_overlapping,
{some, <<"TODO: add hint"/utf8>>},
Entity_span,
Totality_span,
prequel@internals@token:to_string(Token),
Span},
fail(_pipe@4);
[] ->
_pipe@5 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
{some, Entity_span},
Totality_span,
<<"this hierarchy"/utf8>>},
fail(_pipe@5)
end.
-spec do_parse_relationship_body(
list({prequel@internals@token:token(), prequel@span:span()}),
binary(),
prequel@span:span(),
list(prequel@ast:relationship_entity()),
list(prequel@ast:attribute())
) -> {ok,
{prequel@ast:relationship(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
do_parse_relationship_body(
Tokens,
Relationship_name,
Relationship_span,
Entities,
Attributes
) ->
case Tokens of
[{close_bracket, _} | Tokens@1] ->
case Entities of
[One_entity, Other_entity | Other_entities] ->
_pipe = {relationship,
Relationship_span,
Relationship_name,
One_entity,
non_empty_list:new(Other_entity, Other_entities),
Attributes},
succeed(_pipe, Tokens@1);
[One_entity@1] ->
_pipe@1 = {relationship_body_with_just_one_entity,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
Relationship_name,
erlang:element(2, One_entity@1)},
fail(_pipe@1);
[] ->
_pipe@2 = {relationship_body_with_no_entities,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span},
fail(_pipe@2)
end;
[{circle_lollipop, Lollipop_span} | Tokens@2] ->
'try'(
parse_attribute(Tokens@2, Relationship_span, Lollipop_span),
fun(Attribute, Tokens@3) ->
do_parse_relationship_body(
Tokens@3,
Relationship_name,
Relationship_span,
Entities,
[Attribute | Attributes]
)
end
);
[{arrow_lollipop, Lollipop_span@1} | Tokens@4] ->
'try'(
parse_relationship_entity(
Tokens@4,
Relationship_span,
Lollipop_span@1
),
fun(Entity, Tokens@5) ->
do_parse_relationship_body(
Tokens@5,
Relationship_name,
Relationship_span,
[Entity | Entities],
Attributes
)
end
);
[{star_lollipop, Lollipop_span@2} | _] ->
_pipe@3 = {key_inside_relationship,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
Lollipop_span@2},
fail(_pipe@3);
[{minus, Minus_span}, {{word, <<"o"/utf8>>}, O_span} | _] ->
_pipe@4 = {possible_circle_lollipop_typo,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
prequel@span:merge(Minus_span, O_span)},
fail(_pipe@4);
[{minus, Minus_span@1}, {{word, <<">"/utf8>>}, Arrow_span} | _] ->
_pipe@5 = {possible_arrow_lollipop_typo,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
prequel@span:merge(Minus_span@1, Arrow_span)},
fail(_pipe@5);
[{_, Span} | _] ->
_pipe@6 = {unexpected_token_in_relationship_body,
{some, <<"TODO: add hint"/utf8>>},
Relationship_span,
Span},
fail(_pipe@6);
[] ->
_pipe@7 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
none,
Relationship_span,
<<"this relationship"/utf8>>},
fail(_pipe@7)
end.
-spec parse_relationship_body(
list({prequel@internals@token:token(), prequel@span:span()}),
binary(),
prequel@span:span()
) -> {ok,
{prequel@ast:relationship(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_relationship_body(Tokens, Relationship_name, Name_span) ->
do_parse_relationship_body(Tokens, Relationship_name, Name_span, [], []).
-spec parse_relationship(
list({prequel@internals@token:token(), prequel@span:span()}),
prequel@span:span()
) -> {ok,
{prequel@ast:relationship(),
list({prequel@internals@token:token(), prequel@span:span()})}} |
{error, prequel@error@parse_error:parse_error()}.
parse_relationship(Tokens, Relationship_keyword_span) ->
case Tokens of
[{{word, Relationship_name}, Relationship_span},
{open_bracket, _} |
Tokens@1] ->
parse_relationship_body(
Tokens@1,
Relationship_name,
Relationship_span
);
[{{word, _}, Name_span} | _] ->
_pipe = {relationship_body_with_no_entities,
{some, <<"TODO: add hint"/utf8>>},
Name_span},
fail(_pipe);
[{Token, Span} | _] ->
_pipe@1 = {wrong_relationship_name,
{some, <<"TODO: add hint"/utf8>>},
none,
Relationship_keyword_span,
prequel@internals@token:to_string(Token),
Span},
fail(_pipe@1);
[] ->
_pipe@2 = {unexpected_end_of_file,
{some, <<"TODO: add hint"/utf8>>},
none,
Relationship_keyword_span,
<<"this relationship"/utf8>>},
fail(_pipe@2)
end.