Current section

Files

Jump to
glyph_codegen src glyph_codegen@codegen.erl
Raw

src/glyph_codegen@codegen.erl

-module(glyph_codegen@codegen).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([generate/1, main/0]).
-export_type([field_decoder/0, args/0]).
-type field_decoder() :: {field, binary(), binary()} |
{optional_field, binary(), binary()}.
-type args() :: {args,
list(binary()),
binary(),
binary(),
gleam@dict:dict(binary(), binary())}.
-spec parse_args(list(binary())) -> args().
parse_args(Arguments) ->
case Arguments of
[<<"--import-module"/utf8>> | Rest] ->
_assert_subject = gleam@list:split(Rest, 1),
{[Val], Rest@1} = case _assert_subject of
{[_], _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 300})
end,
_assert_subject@1 = parse_args(Rest@1),
{args, _, _, _, _} = Args = case _assert_subject@1 of
{args, _, _, _, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 301})
end,
erlang:setelement(4, Args, Val);
[<<"--type"/utf8>> | Rest@2] ->
_assert_subject@2 = gleam@list:split(Rest@2, 1),
{[Val@1], Rest@3} = case _assert_subject@2 of
{[_], _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@2,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 305})
end,
_assert_subject@3 = parse_args(Rest@3),
{args, _, _, _, _} = Args@1 = case _assert_subject@3 of
{args, _, _, _, _} -> _assert_subject@3;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@3,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 306})
end,
erlang:setelement(
2,
Args@1,
begin
_pipe = erlang:element(2, Args@1),
gleam@list:prepend(_pipe, Val@1)
end
);
[<<"--out-file"/utf8>> | Rest@4] ->
_assert_subject@4 = gleam@list:split(Rest@4, 1),
{[Val@2], Rest@5} = case _assert_subject@4 of
{[_], _} -> _assert_subject@4;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@4,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 314})
end,
_assert_subject@5 = parse_args(Rest@5),
{args, _, _, _, _} = Args@2 = case _assert_subject@5 of
{args, _, _, _, _} -> _assert_subject@5;
_assert_fail@5 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@5,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 315})
end,
erlang:setelement(3, Args@2, Val@2);
[<<"--rename"/utf8>> | Rest@6] ->
_assert_subject@6 = gleam@list:split(Rest@6, 2),
{[V1, V2], Rest@7} = case _assert_subject@6 of
{[_, _], _} -> _assert_subject@6;
_assert_fail@6 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@6,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 319})
end,
_assert_subject@7 = parse_args(Rest@7),
{args, _, _, _, _} = Args@3 = case _assert_subject@7 of
{args, _, _, _, _} -> _assert_subject@7;
_assert_fail@7 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@7,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 320})
end,
erlang:setelement(
5,
Args@3,
begin
_pipe@1 = erlang:element(5, Args@3),
gleam@dict:insert(_pipe@1, V1, V2)
end
);
[] ->
{args, [], <<""/utf8>>, <<""/utf8>>, gleam@dict:new()};
_ ->
erlang:error(#{gleam_error => panic,
message => <<"parsing error"/utf8>>,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"parse_args"/utf8>>,
line => 330})
end.
-spec do_template(binary(), list({binary(), gleam@bbmustache:argument()})) -> binary().
do_template(Templ, Args) ->
_assert_subject = gleam@bbmustache:compile(Templ),
{ok, Compiled} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"do_template"/utf8>>,
line => 377})
end,
gleam@bbmustache:render(Compiled, Args).
-spec format(binary(), list(binary())) -> binary().
format(Fmt, Args) ->
case gleam@string:split_once(Fmt, <<"%"/utf8>>) of
{ok, {Left, Right}} ->
case Args of
[] ->
<<""/utf8>>;
[E1] ->
<<<<Left/binary, E1/binary>>/binary, Right/binary>>;
[E1@1 | Rest] ->
<<<<Left/binary, E1@1/binary>>/binary,
(format(Right, Rest))/binary>>
end;
{error, _} ->
<<""/utf8>>
end.
-spec convert_type_to_decoder(glance:field(glance:type())) -> field_decoder().
convert_type_to_decoder(Field) ->
Id@1 = case erlang:element(2, Field) of
{some, Id} ->
Id;
_ ->
erlang:error(#{gleam_error => panic,
message => <<"unknown id"/utf8>>,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"convert_type_to_decoder"/utf8>>,
line => 119})
end,
gleam@io:debug(<<"parsing field: "/utf8, Id@1/binary>>),
gleam@io:debug(Field),
case erlang:element(3, Field) of
{named_type,
<<"List"/utf8>>,
_,
[{named_type, <<"String"/utf8>>, _, []}]} ->
{field, Id@1, <<"dynamic.list(dynamic.string)"/utf8>>};
{named_type, <<"List"/utf8>>, _, [{named_type, <<"Int"/utf8>>, _, []}]} ->
{field, Id@1, <<"dynamic.list(dynamic.int)"/utf8>>};
{named_type,
<<"List"/utf8>>,
_,
[{named_type, <<"Snowflake"/utf8>>, _, []}]} ->
{field, Id@1, <<"dynamic.list(dynamic.string)"/utf8>>};
{named_type, <<"List"/utf8>>, _, [{named_type, Name, _, []}]} when ((Name =/= <<"String"/utf8>>) andalso (Name =/= <<"Int"/utf8>>)) andalso (Name =/= <<"Bool"/utf8>>) ->
{field,
Id@1,
format(
<<"dynamic.list(decode_%)"/utf8>>,
[justin:snake_case(Name)]
)};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type, <<"Float"/utf8>>, _, []}]} ->
{optional_field, Id@1, <<"dynamic.float"/utf8>>};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type, <<"Nil"/utf8>>, _, []}]} ->
{optional_field, Id@1, <<"dynamic.string"/utf8>>};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type, <<"Snowflake"/utf8>>, _, []}]} ->
{optional_field, Id@1, <<"dynamic.string"/utf8>>};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type, <<"String"/utf8>>, _, []}]} ->
{optional_field, Id@1, <<"dynamic.string"/utf8>>};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type, <<"Int"/utf8>>, _, []}]} ->
{optional_field, Id@1, <<"dynamic.int"/utf8>>};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type, <<"Bool"/utf8>>, _, []}]} ->
{optional_field, Id@1, <<"dynamic.bool"/utf8>>};
{named_type, <<"Option"/utf8>>, _, [{named_type, Name@1, _, []}]} when ((Name@1 =/= <<"String"/utf8>>) andalso (Name@1 =/= <<"Int"/utf8>>)) andalso (Name@1 =/= <<"Bool"/utf8>>) ->
{optional_field,
Id@1,
format(<<"decode_%"/utf8>>, [justin:snake_case(Name@1)])};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type,
<<"Dict"/utf8>>,
_,
[{named_type, <<"Snowflake"/utf8>>, _, []},
{named_type, P2, _, []}]}]} ->
{optional_field,
Id@1,
format(
<<"dynamic.dict(dynamic.string, decode_%)"/utf8>>,
[justin:snake_case(P2)]
)};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type,
<<"List"/utf8>>,
_,
[{named_type, <<"Snowflake"/utf8>>, _, []}]}]} ->
{optional_field, Id@1, <<"dynamic.list(dynamic.string)"/utf8>>};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type, <<"List"/utf8>>, _, [{named_type, Name@2, _, []}]}]} when ((Name@2 =/= <<"String"/utf8>>) andalso (Name@2 =/= <<"Int"/utf8>>)) andalso (Name@2 =/= <<"Bool"/utf8>>) ->
{optional_field,
Id@1,
format(
<<"dynamic.list(decode_%)"/utf8>>,
[justin:snake_case(Name@2)]
)};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type,
<<"List"/utf8>>,
_,
[{named_type, <<"Int"/utf8>>, _, []}]}]} ->
{optional_field, Id@1, <<"dynamic.list(dynamic.int)"/utf8>>};
{named_type,
<<"Option"/utf8>>,
_,
[{named_type,
<<"List"/utf8>>,
_,
[{named_type, <<"String"/utf8>>, _, []}]}]} ->
{optional_field, Id@1, <<"dynamic.list(dynamic.string)"/utf8>>};
{named_type, <<"dynamic.Dynamic"/utf8>>, _, []} ->
{field, Id@1, <<"dynamic.dynamic"/utf8>>};
{named_type, Name@3, _, []} when (Name@3 =:= <<"Snowflake"/utf8>>) orelse (Name@3 =:= <<"String"/utf8>>) ->
{field, Id@1, <<"dynamic.string"/utf8>>};
{named_type, <<"Int"/utf8>>, _, []} ->
{field, Id@1, <<"dynamic.int"/utf8>>};
{named_type, <<"Dynamic"/utf8>>, _, []} ->
{field, Id@1, <<"dynamic.dynamic"/utf8>>};
{named_type, <<"Bool"/utf8>>, _, []} ->
{field, Id@1, <<"dynamic.bool"/utf8>>};
{named_type, Name@4, _, []} ->
{field,
Id@1,
format(<<"decode_%"/utf8>>, [justin:snake_case(Name@4)])};
{named_type,
<<"Dict"/utf8>>,
_,
[{named_type, P1, _, []}, {named_type, P2@1, _, []}]} ->
{field,
Id@1,
format(
<<"dynamic.dict(dynamic.%, dynamic.%)"/utf8>>,
[justin:snake_case(P1), justin:snake_case(P2@1)]
)};
_ ->
erlang:error(#{gleam_error => panic,
message => <<"unsupported type"/utf8>>,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"convert_type_to_decoder"/utf8>>,
line => 284})
end.
-spec get_fields(list(glance:field(glance:type()))) -> list(field_decoder()).
get_fields(Fields) ->
case Fields of
[Field | Fields@1] ->
[convert_type_to_decoder(Field) | get_fields(Fields@1)];
[] ->
[]
end.
-spec render_template(args(), binary(), list(field_decoder())) -> binary().
render_template(Args, Type_name, Fields) ->
Fields@1 = begin
_pipe = Fields,
gleam@list:index_map(
_pipe,
fun(X, Idx) ->
Comma = case (Idx + 1) =:= gleam@list:length(Fields) of
true ->
<<""/utf8>>;
_ ->
<<","/utf8>>
end,
{Func_name, Name@2, Arg@2} = case X of
{field, Name, Arg} ->
{<<"dynamic.field"/utf8>>, Name, Arg};
{optional_field, Name@1, Arg@1} ->
{<<"dynamic.optional_field"/utf8>>, Name@1, Arg@1}
end,
Name@3 = case gleam@dict:get(erlang:element(5, Args), Name@2) of
{ok, Renamed} ->
Renamed;
{error, _} ->
Name@2
end,
gleam_bbmustache_native:argument(
[{<<"index"/utf8>>,
gleam_bbmustache_native:argument(
<<"a"/utf8,
(begin
_pipe@1 = Idx + 1,
gleam@int:to_string(_pipe@1)
end)/binary>>
)},
{<<"func_name"/utf8>>,
gleam_bbmustache_native:argument(Func_name)},
{<<"key"/utf8>>,
gleam_bbmustache_native:argument(Name@3)},
{<<"value"/utf8>>,
gleam_bbmustache_native:argument(Arg@2)},
{<<"comma"/utf8>>,
gleam_bbmustache_native:argument(Comma)}]
)
end
)
end,
do_template(
<<"
pub fn decode_{{type_snake_case}}(
dyn: dynamic.Dynamic,
) -> Result(discord.{{type_name}}, dynamic.DecodeErrors) {
case
{{#fields}}{{func_name}}(\"{{key}}\", {{value}})(dyn){{comma}}{{/fields}}
{
{{#fields}}Ok({{index}}){{comma}}{{/fields}} ->
Ok(discord.{{type_name}}({{#fields}}{{index}}{{comma}}{{/fields}}
))
{{#fields}}{{index}}{{comma}}{{/fields}} ->
Error(list.concat([
{{#fields}}all_errors({{index}}){{comma}}{{/fields}}
]))
}
}
"/utf8>>,
[{<<"fields"/utf8>>, gleam_bbmustache_native:argument(Fields@1)},
{<<"type_name"/utf8>>, gleam_bbmustache_native:argument(Type_name)},
{<<"type_snake_case"/utf8>>,
gleam_bbmustache_native:argument(justin:snake_case(Type_name))}]
).
-spec codegen(args()) -> {ok, binary()} | {error, {integer(), binary()}}.
codegen(Args) ->
gleam@io:debug(simplifile:read_directory(<<"."/utf8>>)),
_assert_subject = simplifile:read(
<<<<"./src/"/utf8, (erlang:element(4, Args))/binary>>/binary,
".gleam"/utf8>>
),
{ok, Source} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"codegen"/utf8>>,
line => 61})
end,
_assert_subject@1 = glance:module(Source),
{ok, Module} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"codegen"/utf8>>,
line => 63})
end,
Output_path = erlang:element(3, Args),
case simplifile:delete(Output_path) of
{ok, _} ->
nil;
{error, enoent} ->
nil;
_ ->
erlang:error(#{gleam_error => panic,
message => <<"cannot delete a old file"/utf8>>,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"codegen"/utf8>>,
line => 70})
end,
Rendered = do_template(
<<"
import gleam/dynamic
import gleam/list
import {{module}}
fn all_errors(result: Result(a, dynamic.DecodeErrors)) -> dynamic.DecodeErrors {
case result {
Ok(_) -> []
Error(errors) -> errors
}
}
"/utf8>>,
[{<<"module"/utf8>>,
gleam_bbmustache_native:argument(erlang:element(4, Args))}]
),
_assert_subject@2 = simplifile:write(Output_path, Rendered),
{ok, _} = case _assert_subject@2 of
{ok, _} -> _assert_subject@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@2,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"codegen"/utf8>>,
line => 77})
end,
gleam@list:each(
erlang:element(2, Args),
fun(Type_name) ->
gleam@io:debug(<<"looking for the type: "/utf8, Type_name/binary>>),
_assert_subject@3 = begin
_pipe = erlang:element(3, Module),
gleam@list:find(
_pipe,
fun(X) ->
erlang:element(2, erlang:element(3, X)) =:= Type_name
end
)
end,
{ok, Found} = case _assert_subject@3 of
{ok, _} -> _assert_subject@3;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@3,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"codegen"/utf8>>,
line => 81})
end,
_assert_subject@4 = begin
_pipe@1 = erlang:element(6, erlang:element(3, Found)),
gleam@list:at(_pipe@1, 0)
end,
{ok, First_variant} = case _assert_subject@4 of
{ok, _} -> _assert_subject@4;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@4,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"codegen"/utf8>>,
line => 84})
end,
Fields_decoders = get_fields(erlang:element(3, First_variant)),
Rendered@1 = render_template(Args, Type_name, Fields_decoders),
_assert_subject@5 = simplifile:append(Output_path, Rendered@1),
{ok, _} = case _assert_subject@5 of
{ok, _} -> _assert_subject@5;
_assert_fail@5 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@5,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"codegen"/utf8>>,
line => 91})
end
end
),
gleam@io:debug(<<"formatting..."/utf8>>),
_assert_subject@6 = shellout:command(
<<"gleam"/utf8>>,
[<<"format"/utf8>>, Output_path],
<<"."/utf8>>,
[let_be_stdout]
),
{ok, _} = case _assert_subject@6 of
{ok, _} -> _assert_subject@6;
_assert_fail@6 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@6,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"codegen"/utf8>>,
line => 96})
end.
-spec generate(args()) -> {ok, binary()} | {error, {integer(), binary()}}.
generate(Args) ->
codegen(Args).
-spec main() -> {ok, binary()} | {error, {integer(), binary()}}.
main() ->
case simplifile:verify_is_file(<<"./gleam.toml"/utf8>>) of
{ok, Exists} when Exists =:= true ->
nil;
_ ->
erlang:error(#{gleam_error => panic,
message => <<"not in project root"/utf8>>,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"main"/utf8>>,
line => 52})
end,
_assert_subject = parse_args(erlang:element(4, argv:load())),
{args, _, _, _, _} = Args = case _assert_subject of
{args, _, _, _, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"glyph_codegen/codegen"/utf8>>,
function => <<"main"/utf8>>,
line => 55})
end,
codegen(Args).