-module(glerd). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([generate/1, main/0]). -export_type([context/0]). -type context() :: {context, binary(), binary()}. -spec module_name_from_path({context(), IZT}) -> {binary(), {context(), IZT}}. module_name_from_path(Ctx) -> {{context, Dir, Path}, _} = Ctx, Module_name = begin _pipe = Path, _pipe@1 = gleam@string:replace( _pipe, <>, <<""/utf8>> ), gleam@string:replace(_pipe@1, <<".gleam"/utf8>>, <<""/utf8>>) end, {Module_name, Ctx}. -spec content_from_path({context(), IZV}) -> {binary(), {context(), IZV}}. content_from_path(Ctx) -> {{context, _, Path}, _} = Ctx, _assert_subject = simplifile:read(Path), {ok, Content} = 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 => <<"glerd"/utf8>>, function => <<"content_from_path"/utf8>>, line => 148}) end, {Content, Ctx}. -spec lexems_from_content( {context(), gleam@dict:dict(gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_())} ) -> {list({glexer@token:token(), glexer:position()}), {context(), gleam@dict:dict(gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_())}}. lexems_from_content(Ctx) -> functx:call( Ctx, fun content_from_path/1, fun(Content, Ctx@1) -> Lexems = begin _pipe = Content, _pipe@1 = glexer:new(_pipe), glexer:lex(_pipe@1) end, {Lexems, Ctx@1} end ). -spec ast_from_content( {context(), gleam@dict:dict(gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_())} ) -> {list(glance:variant()), {context(), gleam@dict:dict(gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_())}}. ast_from_content(Ctx) -> functx:call( Ctx, fun content_from_path/1, fun(Content, Ctx@1) -> _assert_subject = glance:module(Content), {ok, Module} = 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 => <<"glerd"/utf8>>, function => <<"ast_from_content"/utf8>>, line => 135}) end, {module, _, Custom_types_definitions, _, _, _} = Module, Variants@1 = (gleam@list:flat_map( Custom_types_definitions, fun(Custom_type_definition) -> {definition, _, Custom_type} = Custom_type_definition, {custom_type, _, _, _, _, Variants} = Custom_type, Variants end )), {Variants@1, Ctx@1} end ). -spec lexems_to_meta(binary(), list({glexer@token:token(), glexer:position()})) -> binary(). lexems_to_meta(Record_name, Lexems) -> _assert_subject = begin _pipe = Lexems, _pipe@1 = gleam@list:window_by_2(_pipe), _pipe@2 = gleam@list:find_map(_pipe@1, fun(Pair) -> case Pair of {{{comment_doc, Meta}, {position, _}}, {{upper_name, Rec_name}, {position, _}}} when Rec_name =:= Record_name -> {ok, Meta}; _ -> {error, nil} end end), _pipe@3 = gleam@result:'or'(_pipe@2, {ok, <<""/utf8>>}), gleam@result:map(_pipe@3, fun(S) -> _pipe@4 = S, gleam@string:trim_left(_pipe@4) end) end, {ok, Meta@1} = 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 => <<"glerd"/utf8>>, function => <<"lexems_to_meta"/utf8>>, line => 153}) end, Meta@1. -spec type_args(list(glance:type())) -> binary(). type_args(Types) -> _pipe = Types, _pipe@1 = gleam@list:map(_pipe, fun field_type/1), _pipe@2 = gleam@list:intersperse(_pipe@1, <<","/utf8>>), gleam@string:join(_pipe@2, <<""/utf8>>). -spec field_type(glance:type()) -> binary(). field_type(Typ) -> case Typ of {named_type, Type_name, _, _} when Type_name =:= <<"String"/utf8>> -> <<"types.IsString"/utf8>>; {named_type, Type_name@1, _, _} when Type_name@1 =:= <<"Int"/utf8>> -> <<"types.IsInt"/utf8>>; {named_type, Type_name@2, _, _} when Type_name@2 =:= <<"Float"/utf8>> -> <<"types.IsFloat"/utf8>>; {named_type, Type_name@3, _, _} when Type_name@3 =:= <<"Bool"/utf8>> -> <<"types.IsBool"/utf8>>; {named_type, Type_name@4, _, [Typ@1]} when Type_name@4 =:= <<"List"/utf8>> -> <<<<"types.IsList("/utf8, (field_type(Typ@1))/binary>>/binary, ")"/utf8>>; {named_type, Type_name@5, _, [Key_type, Val_type]} when Type_name@5 =:= <<"Dict"/utf8>> -> <<<<"types.IsDict("/utf8, (type_args([Key_type, Val_type]))/binary>>/binary, ")"/utf8>>; {named_type, Type_name@6, _, [Typ@2]} when Type_name@6 =:= <<"Option"/utf8>> -> <<<<"types.IsOption("/utf8, (field_type(Typ@2))/binary>>/binary, ")"/utf8>>; {named_type, Type_name@7, _, [Typ1, Typ2]} when Type_name@7 =:= <<"Result"/utf8>> -> <<<<"types.IsResult("/utf8, (type_args([Typ1, Typ2]))/binary>>/binary, ")"/utf8>>; {tuple_type, [Typ1@1, Typ2@1]} -> <<<<"types.IsTuple2("/utf8, (type_args([Typ1@1, Typ2@1]))/binary>>/binary, ")"/utf8>>; {tuple_type, [Typ1@2, Typ2@2, Typ3]} -> <<<<"types.IsTuple3("/utf8, (type_args([Typ1@2, Typ2@2, Typ3]))/binary>>/binary, ")"/utf8>>; {tuple_type, [Typ1@3, Typ2@3, Typ3@1, Typ4]} -> <<<<"types.IsTuple4("/utf8, (type_args([Typ1@3, Typ2@3, Typ3@1, Typ4]))/binary>>/binary, ")"/utf8>>; {tuple_type, [Typ1@4, Typ2@4, Typ3@2, Typ4@1, Typ5]} -> <<<<"types.IsTuple5("/utf8, (type_args([Typ1@4, Typ2@4, Typ3@2, Typ4@1, Typ5]))/binary>>/binary, ")"/utf8>>; {tuple_type, [Typ1@5, Typ2@5, Typ3@3, Typ4@2, Typ5@1, Typ6]} -> <<<<"types.IsTuple6("/utf8, (type_args([Typ1@5, Typ2@5, Typ3@3, Typ4@2, Typ5@1, Typ6]))/binary>>/binary, ")"/utf8>>; {named_type, Record_name, _, _} -> <<<<"types.IsRecord(\""/utf8, Record_name/binary>>/binary, "\")"/utf8>>; _ -> <<"types.Unknown"/utf8>> end. -spec normalize_fields(list(glance:field(glance:type()))) -> binary(). normalize_fields(Fields) -> _pipe = Fields, _pipe@1 = gleam@list:map( _pipe, fun(Field) -> {field, Field_name, Typ} = Field, _assert_subject = gleam@option:'or'( Field_name, {some, <<"__none__"/utf8>>} ), {some, Field_name@1} = case _assert_subject of {some, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"glerd"/utf8>>, function => <<"normalize_fields"/utf8>>, line => 173}) end, <<<<<<<<"#(\""/utf8, Field_name@1/binary>>/binary, "\", "/utf8>>/binary, (field_type(Typ))/binary>>/binary, ")"/utf8>> end ), gleam@string:join(_pipe@1, <<","/utf8>>). -spec ast_to_code( {context(), gleam@dict:dict(gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_())} ) -> {list(binary()), {context(), gleam@dict:dict(gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_())}}. ast_to_code(Ctx) -> functx:call( Ctx, fun lexems_from_content/1, fun(Lexems, Ctx@1) -> functx:call( Ctx@1, fun module_name_from_path/1, fun(M, Ctx@2) -> functx:call( Ctx@2, fun ast_from_content/1, fun(Variants, Ctx@3) -> Code = (gleam@list:map( Variants, fun(_use0) -> {variant, R, Fields} = _use0, F = normalize_fields(Fields), Mt = lexems_to_meta(R, Lexems), <<<<<<<<<<<<<<<<<<"#(\""/utf8, R/binary>>/binary, "\",\""/utf8>>/binary, M/binary>>/binary, "\","/utf8>>/binary, "["/utf8>>/binary, F/binary>>/binary, "],\""/utf8>>/binary, Mt/binary>>/binary, "\")"/utf8>> end )), {Code, Ctx@3} end ) end ) end ). -spec generate(binary()) -> nil. generate(Root) -> Records_info = begin _pipe = fswalk:builder(), _pipe@1 = fswalk:with_path(_pipe, Root), _pipe@2 = fswalk:walk(_pipe@1), _pipe@3 = gleam@iterator:filter( _pipe@2, fun(Entry_result) -> case Entry_result of {ok, {entry, Path, {stat, Is_dir}}} -> ((Is_dir =:= false) andalso gleam@string:ends_with( Path, <<".gleam"/utf8>> )) andalso not gleam_stdlib:contains_string( Path, <<"glerd_gen.gleam"/utf8>> ); _ -> false end end ), _pipe@8 = gleam@iterator:flat_map( _pipe@3, fun(Entry_result@1) -> {ok, {entry, Path@1, _}} = case Entry_result@1 of {ok, {entry, _, _}} -> Entry_result@1; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"glerd"/utf8>>, function => <<"generate"/utf8>>, line => 40}) end, _pipe@4 = {context, Root, Path@1}, _pipe@5 = functx:make_ctx(_pipe@4), _pipe@6 = ast_to_code(_pipe@5), _pipe@7 = gleam@pair:first(_pipe@6), gleam@iterator:from_list(_pipe@7) end ), gleam@iterator:fold( _pipe@8, <<""/utf8>>, fun(Acc, El) -> <<<>/binary, ",\n"/utf8>> end ) end, Gen_file_path = <<<<"./"/utf8, Root/binary>>/binary, "/glerd_gen.gleam"/utf8>>, _assert_subject = simplifile:write( Gen_file_path, <<<<"// this file was generated via \"gleam run -m glerd\" import glerd/types pub const record_info = ["/utf8, Records_info/binary>>/binary, "]"/utf8>> ), {ok, _} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail@1, module => <<"glerd"/utf8>>, function => <<"generate"/utf8>>, line => 51}) end, _assert_subject@1 = gleamyshell_ffi:execute( <<"gleam"/utf8>>, <<"."/utf8>>, [<<"format"/utf8>>, Gen_file_path] ), {ok, _} = case _assert_subject@1 of {ok, _} -> _assert_subject@1; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail@2, module => <<"glerd"/utf8>>, function => <<"generate"/utf8>>, line => 61}) end, nil. -spec main() -> nil. main() -> generate(<<"src"/utf8>>).