-module(deriv@unify). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([gen/5]). -export_type([unify_func/0, field/0, unify_field_override/0]). -type unify_func() :: {unify_func, binary(), binary(), binary(), binary(), list(field())}. -type field() :: {field, binary(), binary()}. -type unify_field_override() :: {unify_field_override, binary(), binary(), binary(), binary(), glance:custom_type()}. -file("src/deriv/unify.gleam", 75). -spec get_param_types_and_variants( list(binary()), fun((binary()) -> {ok, glance:module_()} | {error, deriv@types:module_reader_err()}) ) -> list({glance:definition(glance:custom_type()), glance:variant(), binary()}). get_param_types_and_variants(Idents, Module_reader) -> _pipe = Idents, _pipe@1 = gleam@list:map( _pipe, fun(Ident) -> deriv@util:fetch_custom_type(Ident, Module_reader) end ), _pipe@2 = gleam@result:all(_pipe@1), _pipe@3 = (fun(X) -> case X of {error, Err} -> gleam@io:debug(Idents), gleam@io:debug(Err), erlang:error(#{gleam_error => panic, message => <<"`unify` issue with the above `idents`"/utf8>>, module => <<"deriv/unify"/utf8>>, function => <<"get_param_types_and_variants"/utf8>>, line => 89}); {ok, List} -> List end end)(_pipe@2), gleam@list:map( _pipe@3, fun(X@1) -> {Module_name, Type_} = X@1, case erlang:element(6, erlang:element(3, Type_)) of [Variant] -> {Type_, Variant, Module_name}; _ -> gleam@io:debug(Type_), erlang:error(#{gleam_error => panic, message => <<"`unify` derivation currently only supports invariant types"/utf8>>, module => <<"deriv/unify"/utf8>>, function => <<"get_param_types_and_variants"/utf8>>, line => 105}) end end ). -file("src/deriv/unify.gleam", 205). -spec build_field_override( deriv@types:deriv_field_opt(), deriv@types:deriv_field(), fun((binary()) -> {ok, glance:module_()} | {error, deriv@types:module_reader_err()}) ) -> unify_field_override(). build_field_override(Field_opt, Deriv_field, Module_reader) -> case Field_opt of {deriv_field_opt, [<<"unify"/utf8>>, <<"field"/utf8>>, Ident, Override]} -> {Module_name, Type_} = case deriv@util:fetch_custom_type( Ident, Module_reader ) of {error, Err} -> gleam@io:debug(Err), erlang:error(#{gleam_error => panic, message => <<"`panic` expression evaluated."/utf8>>, module => <<"deriv/unify"/utf8>>, function => <<"build_field_override"/utf8>>, line => 216}); {ok, {M, Td}} -> {M, erlang:element(3, Td)} end, Field = erlang:element(4, Deriv_field), {unify_field_override, Ident, Field, Override, Module_name, Type_}; _ -> gleam@io:debug(Field_opt), erlang:error(#{gleam_error => panic, message => <<"Invalid `unify` `DerivFieldOpt` (printed above)"/utf8>>, module => <<"deriv/unify"/utf8>>, function => <<"build_field_override"/utf8>>, line => 235}) end. -file("src/deriv/unify.gleam", 43). -spec build_field_overrides( gleam@dict:dict(deriv@types:deriv_field(), list(deriv@types:deriv_field_opt())), fun((binary()) -> {ok, glance:module_()} | {error, deriv@types:module_reader_err()}) ) -> list({deriv@types:deriv_field(), list(unify_field_override())}). build_field_overrides(Field_opts, Module_reader) -> _pipe = Field_opts, _pipe@2 = gleam@dict:map_values(_pipe, fun(Field, Opts) -> _pipe@1 = Opts, gleam@list:map( _pipe@1, fun(_capture) -> build_field_override(_capture, Field, Module_reader) end ) end), maps:to_list(_pipe@2). -file("src/deriv/unify.gleam", 269). -spec build_ident(binary(), glance:custom_type()) -> binary(). build_ident(Module_name, Type_) -> <<<>/binary, (erlang:element(2, Type_))/binary>>. -file("src/deriv/unify.gleam", 363). -spec fields(glance:variant()) -> list({binary(), binary()}). fields(Variant) -> _pipe = erlang:element(3, Variant), gleam@list:map(_pipe, fun(Field) -> case Field of {labelled_variant_field, {named_type, Name, _, _}, Label} -> {Label, Name}; _ -> gleam@io:debug(Variant), gleam@io:debug(Field), erlang:error(#{gleam_error => panic, message => <<"Only the following field type is supported: `LabelledVariantField(item: NamedType(name:, ..), label:)`"/utf8>>, module => <<"deriv/unify"/utf8>>, function => <<"fields"/utf8>>, line => 373}) end end). -file("src/deriv/unify.gleam", 276). -spec unify_func_fields( binary(), glance:custom_type(), glance:variant(), glance:custom_type(), glance:variant(), list({deriv@types:deriv_field(), list(unify_field_override())}) ) -> list(field()). unify_func_fields( Param_type_module, Param_type, Param_variant, Return_type, Return_variant, Overrides ) -> Param_fields = fields(Param_variant), Return_fields = fields(Return_variant), _pipe = Return_fields, gleam@list:map( _pipe, fun(R_field) -> {Return_field, Result_field_type} = R_field, Overrides@1 = begin _pipe@1 = Overrides, gleam@list:filter_map( _pipe@1, fun(X) -> {Df, Os} = X, case (erlang:element(2, Df) =:= erlang:element( 2, Return_type )) andalso (erlang:element(4, Df) =:= Return_field) of false -> {error, nil}; true -> {ok, {erlang:element(4, Df), Os}} end end ) end, Override = begin _pipe@2 = Overrides@1, gleam@list:find_map( _pipe@2, fun(X@1) -> {Param_field, Os@1} = X@1, gleam@list:find_map( Os@1, fun(O) -> Ident = build_ident( Param_type_module, Param_type ), case (erlang:element(2, O) =:= Ident) andalso (erlang:element( 3, O ) =:= Return_field) of false -> {error, nil}; true -> {ok, {Param_field, O}} end end ) end ) end, {Param_field@1, _} = case Override of {error, _} -> {Return_field, nil}; {ok, {_, O@1}} -> {erlang:element(4, O@1), nil} end, Param_field_type = gleam@list:find_map( Param_fields, fun(X@2) -> {Name, Type_} = X@2, case Param_field@1 =:= Name of false -> {error, nil}; true -> {ok, Type_} end end ), case Param_field_type of {error, _} -> gleam@io:debug(Param_type), gleam@io:debug(Param_variant), gleam@io:debug(Param_field@1), erlang:error(#{gleam_error => panic, message => <<"`unify` param field doesn't exist"/utf8>>, module => <<"deriv/unify"/utf8>>, function => <<"unify_func_fields"/utf8>>, line => 336}); {ok, Param_field_type@1} when Param_field_type@1 =:= Result_field_type -> Param_field_type@1; _ -> gleam_stdlib:println(<<"PARAM TYPE"/utf8>>), gleam@io:debug(Param_type), gleam@io:debug(Param_variant), gleam@io:debug(Param_field@1), gleam_stdlib:println(<<"RETURN TYPE"/utf8>>), gleam@io:debug(Return_type), gleam@io:debug(Return_variant), gleam@io:debug(Return_field), erlang:error(#{gleam_error => panic, message => <<"`unify` param & return field types don't match"/utf8>>, module => <<"deriv/unify"/utf8>>, function => <<"unify_func_fields"/utf8>>, line => 351}) end, {field, Param_field@1, Return_field} end ). -file("src/deriv/unify.gleam", 142). -spec unify_variant( binary(), glance:custom_type(), glance:variant(), glance:custom_type(), glance:variant(), list({deriv@types:deriv_field(), list(unify_field_override())}) ) -> unify_func(). unify_variant( Param_type_module, Param_type, Param_variant, Return_type, Return_variant, Overrides ) -> Fields = unify_func_fields( Param_type_module, Param_type, Param_variant, Return_type, Return_variant, Overrides ), Func_name = deriv@util:snake_case(erlang:element(2, Param_type)), Param_type@1 = erlang:element(2, Param_type), Return_type@1 = erlang:element(2, Return_type), Return_contr = erlang:element(2, Return_variant), {unify_func, Func_name, Param_type@1, Return_type@1, Return_contr, Fields}. -file("src/deriv/unify.gleam", 111). -spec unify( glance:custom_type(), list(binary()), list({deriv@types:deriv_field(), list(unify_field_override())}), fun((binary()) -> {ok, glance:module_()} | {error, deriv@types:module_reader_err()}) ) -> list(unify_func()). unify(Return_type, Idents, Overrides, Module_reader) -> case erlang:element(6, Return_type) of [Return_variant] -> _pipe = Idents, _pipe@1 = get_param_types_and_variants(_pipe, Module_reader), gleam@list:map( _pipe@1, fun(X) -> {Param_type_def, Param_variant, Param_type_module} = X, Param_type = erlang:element(3, Param_type_def), unify_variant( Param_type_module, Param_type, Param_variant, Return_type, Return_variant, Overrides ) end ); _ -> gleam@io:debug(Return_type), erlang:error(#{gleam_error => panic, message => <<"`unify` derivation currently only supports invariant types"/utf8>>, module => <<"deriv/unify"/utf8>>, function => <<"unify"/utf8>>, line => 137}) end. -file("src/deriv/unify.gleam", 379). -spec unify_func(unify_func()) -> glance:definition(glance:function_()). unify_func(Uf) -> {unify_func, Func_name, Param_type, Return_type, Return_contr, Fields} = Uf, Dummy_span = {span, -1, -1}, {definition, [], {function, Func_name, public, [{function_parameter, none, {named, <<"value"/utf8>>}, {some, {named_type, Param_type, none, []}}}], {some, {named_type, Return_type, none, []}}, [{expression, {call, {variable, Return_contr}, gleam@list:map( Fields, fun(Field) -> {labelled_field, erlang:element(3, Field), {field_access, {variable, <<"value"/utf8>>}, erlang:element(2, Field)}} end )}}], Dummy_span}}. -file("src/deriv/unify.gleam", 13). -spec gen( glance:custom_type(), deriv@types:derivation(), gleam@dict:dict(deriv@types:deriv_field(), list(deriv@types:deriv_field_opt())), deriv@types:file(), fun((binary()) -> {ok, glance:module_()} | {error, deriv@types:module_reader_err()}) ) -> deriv@types:gen(). gen(Type_, Deriv, Field_opts, File, Module_reader) -> Overrides = build_field_overrides(Field_opts, Module_reader), Idents = erlang:element(3, Deriv), Imports = [], Funcs = begin _pipe = unify(Type_, Idents, Overrides, Module_reader), gleam@list:map(_pipe, fun unify_func/1) end, Src = begin _pipe@1 = Funcs, _pipe@2 = gleam@list:map(_pipe@1, fun deriv@util:func_str/1), gleam@string:join(_pipe@2, <<"\n\n"/utf8>>) end, {gen, File, Deriv, Imports, Funcs, Src, maps:new()}.