Current section
Files
Jump to
Current section
Files
src/derived@ast.erl
-module(derived@ast).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-define(FILEPATH, "src/derived/ast.gleam").
-export([parse/1]).
-export_type([parse_error/0, derived_type/0, type/0, publicity/0, variant/0, field/0, attribute/0, target/0, field_type/0, token_response/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.
-type parse_error() :: unexpected_end_of_file | unexpected_token | ignored_token.
-type derived_type() :: {derived_type,
{integer(), integer()},
binary(),
list(attribute()),
publicity(),
boolean(),
type(),
list(binary())}.
-type type() :: {type, binary(), list(binary()), list(variant())}.
-type publicity() :: public | private.
-type variant() :: {variant,
binary(),
binary(),
list(field()),
list(attribute())}.
-type field() :: {labelled_field, field_type(), binary()} |
{unlabelled_field, field_type()}.
-type attribute() :: {target, target()} | {deprecated, binary()} | internal.
-type target() :: erlang | javascript.
-type field_type() :: {named_type,
binary(),
gleam@option:option(binary()),
list(field_type())} |
{tuple_type, list(field_type())} |
{function_type, list(field_type()), field_type()} |
{variable_type, binary()}.
-type token_response(DZT) :: {token_response,
list({glexer@token:token(), glexer:position()}),
DZT}.
-file("src/derived/ast.gleam", 441).
-spec parse_docstring(list({glexer@token:token(), glexer:position()}), binary()) -> {list({glexer@token:token(),
glexer:position()}),
binary()}.
parse_docstring(Tokens, Docstring) ->
case Tokens of
[{{comment_doc, New_docstring}, _} | Tokens@1] ->
parse_docstring(
Tokens@1,
<<<<Docstring/binary, "\n"/utf8>>/binary, New_docstring/binary>>
);
Tokens@2 ->
{Tokens@2, Docstring}
end.
-file("src/derived/ast.gleam", 464).
-spec parse_parameter_name(list({glexer@token:token(), glexer:position()})) -> {ok,
token_response(binary())} |
{error, token_response(parse_error())}.
parse_parameter_name(Tokens) ->
case Tokens of
[{{name, Name}, _} | Tokens@1] ->
{ok, {token_response, Tokens@1, Name}};
Tokens@2 ->
{error, {token_response, Tokens@2, unexpected_token}}
end.
-file("src/derived/ast.gleam", 471).
-spec parse_attribute(list({glexer@token:token(), glexer:position()})) -> {ok,
token_response(attribute())} |
{error, token_response(parse_error())}.
parse_attribute(Tokens) ->
case Tokens of
[{{name, <<"deprecated"/utf8>>}, _},
{left_paren, _},
{{string, Reason}, _},
{right_paren, _} |
Tokens@1] ->
{ok, {token_response, Tokens@1, {deprecated, Reason}}};
[{{name, <<"internal"/utf8>>}, _} | Tokens@2] ->
{ok, {token_response, Tokens@2, internal}};
[{{name, <<"target"/utf8>>}, _},
{left_paren, _},
{{name, Target}, _},
{right_paren, _} |
Tokens@3] ->
case Target of
<<"erlang"/utf8>> ->
{ok, {token_response, Tokens@3, {target, erlang}}};
<<"javascript"/utf8>> ->
{ok, {token_response, Tokens@3, {target, javascript}}};
_ ->
{error, {token_response, Tokens@3, unexpected_token}}
end;
Tokens@4 ->
{error, {token_response, Tokens@4, unexpected_token}}
end.
-file("src/derived/ast.gleam", 499).
-spec parse_comma_separated(
list({glexer@token:token(), glexer:position()}),
glexer@token:token(),
fun((list({glexer@token:token(), glexer:position()})) -> {ok,
token_response(ECH)} |
{error, token_response(parse_error())}),
list(ECH)
) -> {ok, token_response(list(ECH))} | {error, token_response(parse_error())}.
parse_comma_separated(Tokens, Terminator, Parser, Reversed_items) ->
case Tokens of
[{Tok, _} | Tokens@1] when Tok =:= Terminator ->
{ok, {token_response, Tokens@1, Reversed_items}};
[{comma, _} | Tokens@2] ->
parse_comma_separated(Tokens@2, Terminator, Parser, Reversed_items);
Tokens@3 ->
gleam@result:'try'(
Parser(Tokens@3),
fun(_use0) ->
{token_response, Tokens@4, Item} = _use0,
parse_comma_separated(
Tokens@4,
Terminator,
Parser,
[Item | Reversed_items]
)
end
)
end.
-file("src/derived/ast.gleam", 452).
-spec parse_type_parameter_names(
list({glexer@token:token(), glexer:position()}),
list(binary())
) -> {ok, token_response(list(binary()))} |
{error, token_response(parse_error())}.
parse_type_parameter_names(Tokens, Reversed_parameters) ->
parse_comma_separated(
Tokens,
right_paren,
fun parse_parameter_name/1,
Reversed_parameters
).
-file("src/derived/ast.gleam", 529).
-spec map_parse_result(
{ok, token_response(ECM)} | {error, token_response(parse_error())},
fun((ECM) -> ECO)
) -> {ok, token_response(ECO)} | {error, token_response(parse_error())}.
map_parse_result(Result, Mapper) ->
gleam@result:'try'(
Result,
fun(_use0) ->
{token_response, Tokens, Value} = _use0,
{ok, {token_response, Tokens, Mapper(Value)}}
end
).
-file("src/derived/ast.gleam", 539).
?DOC(
" Return all modules inside parens in magic !derived(return/this)\n"
" substrings of the string. Returns them in the order they appear.\n"
).
-spec extract_derived_names(binary()) -> {ok, list(binary())} | {error, nil}.
extract_derived_names(String) ->
Re@1 = case gleam@regexp:from_string(
<<"!derived\\(([a-z][a-z_/]*)\\)"/utf8>>
) of
{ok, Re} -> Re;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"derived/ast"/utf8>>,
function => <<"extract_derived_names"/utf8>>,
line => 540,
value => _assert_fail,
start => 14982,
'end' => 15053,
pattern_start => 14993,
pattern_end => 14999})
end,
Matches = gleam@regexp:scan(Re@1, String),
case Matches of
[] ->
{error, nil};
_ ->
Modules = gleam@list:map(
Matches,
fun(Match) ->
Name@1 = case Match of
{match, _, [{some, Name}]} -> Name;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"derived/ast"/utf8>>,
function => <<"extract_derived_names"/utf8>>,
line => 549,
value => _assert_fail@1,
start => 15213,
'end' => 15268,
pattern_start => 15224,
pattern_end => 15260})
end,
Name@1
end
),
{ok, Modules}
end.
-file("src/derived/ast.gleam", 405).
-spec parse_tuple_elements(
list({glexer@token:token(), glexer:position()}),
list(field_type())
) -> {ok, token_response(list(field_type()))} |
{error, token_response(parse_error())}.
parse_tuple_elements(Tokens, Reversed_elements) ->
parse_comma_separated(
Tokens,
right_paren,
fun parse_field_type/1,
Reversed_elements
).
-file("src/derived/ast.gleam", 341).
-spec parse_field_type(list({glexer@token:token(), glexer:position()})) -> {ok,
token_response(field_type())} |
{error, token_response(parse_error())}.
parse_field_type(Tokens) ->
case Tokens of
[{{upper_name, Name}, _}, {left_paren, _} | Tokens@1] ->
gleam@result:'try'(
parse_type_parameters(Tokens@1, []),
fun(_use0) ->
{token_response, Tokens@2, Parameters} = _use0,
{ok,
{token_response,
Tokens@2,
{named_type,
Name,
none,
begin
_pipe = Parameters,
lists:reverse(_pipe)
end}}}
end
);
[{{upper_name, Name@1}, _} | Tokens@3] ->
{ok, {token_response, Tokens@3, {named_type, Name@1, none, []}}};
[{hash, _}, {left_paren, _} | Tokens@4] ->
gleam@result:'try'(
parse_tuple_elements(Tokens@4, []),
fun(_use0@1) ->
{token_response, Tokens@5, Tuple_elements} = _use0@1,
{ok,
{token_response,
Tokens@5,
{tuple_type,
begin
_pipe@1 = Tuple_elements,
lists:reverse(_pipe@1)
end}}}
end
);
[{fn, _}, {left_paren, _} | Tokens@6] ->
gleam@result:'try'(
parse_function_parameters(Tokens@6, []),
fun(_use0@2) ->
{token_response, Tokens@7, Parameters@1} = _use0@2,
case Tokens@7 of
[{right_arrow, _} | Tokens@8] ->
gleam@result:'try'(
parse_field_type(Tokens@8),
fun(_use0@3) ->
{token_response, Tokens@9, Return_type} = _use0@3,
{ok,
{token_response,
Tokens@9,
{function_type,
begin
_pipe@2 = Parameters@1,
lists:reverse(_pipe@2)
end,
Return_type}}}
end
);
_ ->
{error,
{token_response, Tokens@7, unexpected_token}}
end
end
);
[{{name, Module}, _},
{dot, _},
{{upper_name, Name@2}, _},
{left_paren, _} |
Tokens@10] ->
gleam@result:'try'(
parse_type_parameters(Tokens@10, []),
fun(_use0@4) ->
{token_response, Tokens@11, Parameters@2} = _use0@4,
{ok,
{token_response,
Tokens@11,
{named_type,
Name@2,
{some, Module},
begin
_pipe@3 = Parameters@2,
lists:reverse(_pipe@3)
end}}}
end
);
[{{name, Module@1}, _}, {dot, _}, {{upper_name, Name@3}, _} | Tokens@12] ->
{ok,
{token_response,
Tokens@12,
{named_type, Name@3, {some, Module@1}, []}}};
[{comma, _} | Tokens@13] ->
{error, {token_response, Tokens@13, ignored_token}};
[{{name, Variable_name}, _} | Tokens@14] ->
{ok, {token_response, Tokens@14, {variable_type, Variable_name}}};
Tokens@15 ->
{error, {token_response, Tokens@15, unexpected_token}}
end.
-file("src/derived/ast.gleam", 325).
-spec parse_field(list({glexer@token:token(), glexer:position()})) -> {ok,
token_response(field())} |
{error, token_response(parse_error())}.
parse_field(Tokens) ->
case Tokens of
[{right_paren, _} | Tokens@1] ->
{error, {token_response, Tokens@1, ignored_token}};
[{{name, Label}, _}, {colon, _} | Tokens@2] ->
_pipe = parse_field_type(Tokens@2),
map_parse_result(
_pipe,
fun(_capture) -> {labelled_field, _capture, Label} end
);
Tokens@3 ->
_pipe@1 = parse_field_type(Tokens@3),
map_parse_result(
_pipe@1,
fun(Field@0) -> {unlabelled_field, Field@0} end
)
end.
-file("src/derived/ast.gleam", 302).
-spec parse_fields(
list({glexer@token:token(), glexer:position()}),
list(field())
) -> {ok, token_response(list(field()))} |
{error, token_response(parse_error())}.
parse_fields(Tokens, Reversed_fields) ->
case Tokens of
[{right_paren, _} | Tokens@1] ->
{ok, {token_response, Tokens@1, Reversed_fields}};
[{comma, _} | Tokens@2] ->
parse_fields(Tokens@2, Reversed_fields);
Tokens@3 ->
case parse_field(Tokens@3) of
{ok, {token_response, Tokens@4, Field}} ->
parse_fields(Tokens@4, [Field | Reversed_fields]);
{error, {token_response, Tokens@5, ignored_token}} ->
parse_fields(Tokens@5, Reversed_fields);
{error, Real_error} ->
{error, Real_error}
end
end.
-file("src/derived/ast.gleam", 275).
-spec parse_variant(
list({glexer@token:token(), glexer:position()}),
binary(),
list(attribute())
) -> {ok, token_response(variant())} | {error, token_response(parse_error())}.
parse_variant(Tokens, Docstring, Attributes) ->
case Tokens of
[{{upper_name, Name}, _}, {left_paren, _} | Tokens@1] ->
_pipe = parse_fields(Tokens@1, []),
map_parse_result(
_pipe,
fun(Reversed_fields) ->
{variant,
Name,
Docstring,
begin
_pipe@1 = Reversed_fields,
lists:reverse(_pipe@1)
end,
Attributes}
end
);
[{{upper_name, Name@1}, _} | Tokens@2] ->
{ok,
{token_response,
Tokens@2,
{variant, Name@1, Docstring, [], Attributes}}};
_ ->
{error, {token_response, Tokens, unexpected_token}}
end.
-file("src/derived/ast.gleam", 261).
-spec parse_variant_definition(
list({glexer@token:token(), glexer:position()}),
binary(),
list(attribute())
) -> {ok, token_response(variant())} | {error, token_response(parse_error())}.
parse_variant_definition(Tokens, Docstring, Attributes) ->
case Tokens of
[{at, _} | Tokens@1] ->
gleam@result:'try'(
parse_attribute(Tokens@1),
fun(_use0) ->
{token_response, Tokens@2, Attribute} = _use0,
parse_variant_definition(
Tokens@2,
Docstring,
[Attribute | Attributes]
)
end
);
Tokens@3 ->
parse_variant(
Tokens@3,
Docstring,
begin
_pipe = Attributes,
lists:reverse(_pipe)
end
)
end.
-file("src/derived/ast.gleam", 247).
-spec parse_maybe_documented_variant(
list({glexer@token:token(), glexer:position()})
) -> {ok, token_response(variant())} | {error, token_response(parse_error())}.
parse_maybe_documented_variant(Tokens) ->
case Tokens of
[{at, _} | _] ->
parse_variant_definition(Tokens, <<""/utf8>>, []);
[{{upper_name, _}, _} | _] ->
parse_variant(Tokens, <<""/utf8>>, []);
[{{comment_doc, Docstring}, _} | Tokens@1] ->
{Tokens@2, Docstring@1} = parse_docstring(Tokens@1, Docstring),
parse_variant_definition(Tokens@2, Docstring@1, []);
_ ->
{error, {token_response, Tokens, unexpected_token}}
end.
-file("src/derived/ast.gleam", 227).
-spec parse_variants(
list({glexer@token:token(), glexer:position()}),
list(variant())
) -> {ok, token_response({list(variant()), integer()})} |
{error, token_response(parse_error())}.
parse_variants(Tokens, Reversed_variants) ->
case Tokens of
[{left_brace, _} | Tokens@1] ->
parse_variants(Tokens@1, Reversed_variants);
[{right_brace, Position} | Tokens@2] ->
{ok,
{token_response,
Tokens@2,
{Reversed_variants, erlang:element(2, Position)}}};
[{{comment_normal, _}, _} | Tokens@3] ->
parse_variants(Tokens@3, Reversed_variants);
Tokens@4 ->
gleam@result:'try'(
parse_maybe_documented_variant(Tokens@4),
fun(_use0) ->
{token_response, Tokens@5, Variant} = _use0,
parse_variants(Tokens@5, [Variant | Reversed_variants])
end
)
end.
-file("src/derived/ast.gleam", 196).
-spec parse_type(list({glexer@token:token(), glexer:position()})) -> {ok,
token_response({type(), integer()})} |
{error, token_response(parse_error())}.
parse_type(Tokens) ->
case Tokens of
[{{upper_name, Name}, _}, {left_paren, _} | Tokens@1] ->
gleam@result:'try'(
parse_type_parameter_names(Tokens@1, []),
fun(_use0) ->
{token_response, Tokens@2, Parameters} = _use0,
gleam@result:'try'(
parse_variants(Tokens@2, []),
fun(_use0@1) ->
{token_response,
Tokens@3,
{Parsed_variants, End_pos}} = _use0@1,
{ok,
{token_response,
Tokens@3,
{{type,
Name,
begin
_pipe = Parameters,
lists:reverse(_pipe)
end,
begin
_pipe@1 = Parsed_variants,
lists:reverse(_pipe@1)
end},
End_pos}}}
end
)
end
);
[{{upper_name, Name@1}, _} | Tokens@4] ->
_pipe@2 = parse_variants(Tokens@4, []),
map_parse_result(
_pipe@2,
fun(Variants_and_pos) ->
{Parsed_variants@1, End_pos@1} = Variants_and_pos,
{{type,
Name@1,
[],
begin
_pipe@3 = Parsed_variants@1,
lists:reverse(_pipe@3)
end},
End_pos@1}
end
);
Tokens@5 ->
{error, {token_response, Tokens@5, unexpected_token}}
end.
-file("src/derived/ast.gleam", 133).
?DOC(" Parse an entity that may be a CustomType or may be something else\n").
-spec maybe_parse_derived_type(
list({glexer@token:token(), glexer:position()}),
binary(),
glexer:position(),
list(binary()),
list(attribute()),
publicity(),
boolean()
) -> {ok, token_response(derived_type())} |
{error, token_response(parse_error())}.
maybe_parse_derived_type(
Tokens,
Docstring,
Docstring_start,
Derived_names,
Attributes,
Publicity,
Opaque_
) ->
case Tokens of
[{at, _} | Tokens@1] ->
gleam@result:'try'(
parse_attribute(Tokens@1),
fun(_use0) ->
{token_response, Tokens@2, Attribute} = _use0,
maybe_parse_derived_type(
Tokens@2,
Docstring,
Docstring_start,
Derived_names,
[Attribute | Attributes],
Publicity,
Opaque_
)
end
);
[{pub, _} | Tokens@3] ->
maybe_parse_derived_type(
Tokens@3,
Docstring,
Docstring_start,
Derived_names,
Attributes,
public,
Opaque_
);
[{opaque, _} | Tokens@4] ->
maybe_parse_derived_type(
Tokens@4,
Docstring,
Docstring_start,
Derived_names,
Attributes,
Publicity,
true
);
[{type, _} | Tokens@5] ->
_pipe = parse_type(Tokens@5),
map_parse_result(
_pipe,
fun(Type_and_pos) ->
{Parsed_type, End_pos} = Type_and_pos,
{derived_type,
{erlang:element(2, Docstring_start), End_pos},
Docstring,
begin
_pipe@1 = Attributes,
lists:reverse(_pipe@1)
end,
Publicity,
Opaque_,
Parsed_type,
Derived_names}
end
);
_ ->
{error, {token_response, Tokens, ignored_token}}
end.
-file("src/derived/ast.gleam", 112).
?DOC(
" Parse a documented entity, returning it only if the wrapped entity is a custom type\n"
" with a !derived() entry.\n"
).
-spec parse_documented_if_derived_type(
list({glexer@token:token(), glexer:position()}),
binary(),
glexer:position()
) -> {ok, token_response(derived_type())} |
{error, token_response(parse_error())}.
parse_documented_if_derived_type(Tokens, Docstring, Docstring_start) ->
case extract_derived_names(Docstring) of
{ok, Derived_names} ->
maybe_parse_derived_type(
Tokens,
Docstring,
Docstring_start,
Derived_names,
[],
private,
false
);
{error, nil} ->
{error, {token_response, Tokens, ignored_token}}
end.
-file("src/derived/ast.gleam", 84).
-spec parse_loop(
list({glexer@token:token(), glexer:position()}),
list(derived_type())
) -> {ok, list(derived_type())} | {error, parse_error()}.
parse_loop(Tokens, Derived_types) ->
case Tokens of
[{{comment_doc, Docstring}, Start} | Tokens@1] ->
{Tokens@2, Docstring@1} = parse_docstring(Tokens@1, Docstring),
case parse_documented_if_derived_type(Tokens@2, Docstring@1, Start) of
{ok, {token_response, Tokens@3, Custom_type}} ->
parse_loop(
Tokens@3,
gleam@list:prepend(Derived_types, Custom_type)
);
{error, {token_response, Tokens@4, ignored_token}} ->
parse_loop(Tokens@4, Derived_types);
{error, {token_response, [], unexpected_token}} ->
{error, unexpected_end_of_file};
{error, {token_response, _, unexpected_end_of_file}} ->
{error, unexpected_end_of_file};
{error, {token_response, _, unexpected_token}} ->
{error, unexpected_token}
end;
[_ | Tokens@5] ->
parse_loop(Tokens@5, Derived_types);
[] ->
{ok, Derived_types}
end.
-file("src/derived/ast.gleam", 12).
?DOC(
" Extract any custom types marked with !derived() from the input string\n"
" including their docstrings.\n"
"\n"
" All other syntaxes (including invalid syntaxes) are ignored\n"
).
-spec parse(binary()) -> {ok, list(derived_type())} | {error, parse_error()}.
parse(Input) ->
_pipe = Input,
_pipe@1 = glexer:new(_pipe),
_pipe@2 = glexer:discard_whitespace(_pipe@1),
_pipe@3 = glexer:lex(_pipe@2),
_pipe@4 = parse_loop(_pipe@3, []),
gleam@result:map(_pipe@4, fun lists:reverse/1).
-file("src/derived/ast.gleam", 417).
-spec parse_function_parameters(
list({glexer@token:token(), glexer:position()}),
list(field_type())
) -> {ok, token_response(list(field_type()))} |
{error, token_response(parse_error())}.
parse_function_parameters(Tokens, Reversed_parameters) ->
parse_comma_separated(
Tokens,
right_paren,
fun parse_field_type/1,
Reversed_parameters
).
-file("src/derived/ast.gleam", 429).
-spec parse_type_parameters(
list({glexer@token:token(), glexer:position()}),
list(field_type())
) -> {ok, token_response(list(field_type()))} |
{error, token_response(parse_error())}.
parse_type_parameters(Tokens, Reversed_parameters) ->
parse_comma_separated(
Tokens,
right_paren,
fun parse_field_type/1,
Reversed_parameters
).