uw-switch-semantics #53
48
src/gmser_dyn_types.erl
Normal file
48
src/gmser_dyn_types.erl
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
-module(gmser_dyn_types).
|
||||||
|
|
||||||
|
-export([ from_list/2 ]).
|
||||||
|
-export([ next_code/1 ]).
|
||||||
|
|
||||||
|
next_code(#{codes := Codes}) ->
|
||||||
|
lists:max(maps:keys(Codes)) + 1.
|
||||||
|
|
||||||
|
add_type(Tag, Code, Template, Types) ->
|
||||||
|
elem_to_type({Tag, Code, Template}, Types).
|
||||||
|
|
||||||
|
from_list(L, Types) ->
|
||||||
|
lists:foldl(fun elem_to_type/2, Types, L).
|
||||||
|
|
||||||
|
elem_to_type({Tag, Code, Template}, Acc) when is_atom(Tag), is_integer(Code) ->
|
||||||
|
#{codes := Codes, rev := Rev, templates := Temps} = Acc,
|
||||||
|
case {is_map_key(Tag, Rev), is_map_key(Code, Codes)} of
|
||||||
|
{false, false} ->
|
||||||
|
Acc#{ codes := Codes#{Code => Tag}
|
||||||
|
, rev := Rev#{Tag => Code}
|
||||||
|
, templates => Temps#{Tag => Template}
|
||||||
|
};
|
||||||
|
{true, _} -> error({duplicate_tag, Tag});
|
||||||
|
{_, true} -> error({duplicate_code, Code})
|
||||||
|
end;
|
||||||
|
elem_to_type({modify, {Tag, Template}}, Acc) ->
|
||||||
|
#{codes := _, rev := Rev, templates := Templates} = Acc,
|
||||||
|
_ = maps:get(Tag, Rev),
|
||||||
|
Templates1 = Templates#{Tag := Template},
|
||||||
|
Acc#{templates := Templates1};
|
||||||
|
elem_to_type({labels, Lbls}, Acc) ->
|
||||||
|
lists:foldl(fun add_label/2, Acc, Lbls);
|
||||||
|
elem_to_type({vsn, V}, Acc) ->
|
||||||
|
Acc#{vsn => V};
|
||||||
|
elem_to_type(Elem, _) ->
|
||||||
|
error({invalid_type, Elem}).
|
||||||
|
|
||||||
|
add_label({L, Code}, #{labels := Lbls, rev_labels := RevLbls} = Acc)
|
||||||
|
when is_atom(L), is_integer(Code), Code > 0 ->
|
||||||
|
case {is_map_key(L, Lbls), is_map_key(Code, RevLbls)} of
|
||||||
|
{false, false} ->
|
||||||
|
Acc#{labels := Lbls#{L => Code},
|
||||||
|
rev_labels := RevLbls#{Code => L}};
|
||||||
|
{true, _} -> error({duplicate_label, L});
|
||||||
|
{_, true} -> error({duplicate_label_code, Code})
|
||||||
|
end;
|
||||||
|
add_label(Elem, _) ->
|
||||||
|
error({invalid_label, Elem}).
|
Loading…
x
Reference in New Issue
Block a user