-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, <<<>/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 => <>, 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 => <>, 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 ).