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_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", 445).
-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", 468).
-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", 475).
-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", 503).
-spec parse_comma_separated(
list({glexer@token:token(), glexer:position()}),
glexer@token:token(),
fun((list({glexer@token:token(), glexer:position()})) -> {ok,
token_response(ECD)} |
{error, token_response(parse_error())}),
list(ECD)
) -> {ok, token_response(list(ECD))} | {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", 456).
-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", 533).
-spec map_parse_result(
{ok, token_response(ECI)} | {error, token_response(parse_error())},
fun((ECI) -> ECK)
) -> {ok, token_response(ECK)} | {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", 543).
?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 => 544,
value => _assert_fail,
start => 15016,
'end' => 15087,
pattern_start => 15027,
pattern_end => 15033})
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 => 553,
value => _assert_fail@1,
start => 15247,
'end' => 15302,
pattern_start => 15258,
pattern_end => 15294})
end,
Name@1
end
),
{ok, Modules}
end.
-file("src/derived/ast.gleam", 409).
-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", 345).
-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", 329).
-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", 306).
-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", 279).
-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", 265).
-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", 251).
-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", 233).
-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)}}};
Tokens@3 ->
gleam@result:'try'(
parse_maybe_documented_variant(Tokens@3),
fun(_use0) ->
{token_response, Tokens@4, Variant} = _use0,
parse_variants(Tokens@4, [Variant | Reversed_variants])
end
)
end.
-file("src/derived/ast.gleam", 202).
-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", 139).
?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", 118).
?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())
) -> list(derived_type()).
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}} ->
gleam_stdlib:println(
<<"Warning: Encountered unexpected end of file"/utf8>>
),
Derived_types;
{error,
{token_response, [{Token, Position} | _], unexpected_token}} ->
gleam_stdlib:println(
<<<<<<"Encountered unexpected token: "/utf8,
(glexer:to_source([{Token, Position}]))/binary>>/binary,
" at byte offset "/utf8>>/binary,
(begin
_pipe = erlang:element(2, Position),
erlang:integer_to_binary(_pipe)
end)/binary>>
),
Derived_types
end;
[_ | Tokens@5] ->
parse_loop(Tokens@5, Derived_types);
[] ->
Derived_types
end.
-file("src/derived/ast.gleam", 14).
?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()) -> list(derived_type()).
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, []),
lists:reverse(_pipe@4).
-file("src/derived/ast.gleam", 421).
-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", 433).
-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
).