aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src/erl_eval.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/src/erl_eval.erl')
-rw-r--r--lib/stdlib/src/erl_eval.erl72
1 files changed, 68 insertions, 4 deletions
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 18d8148b15..3cfedfee97 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -18,6 +18,9 @@
%%
-module(erl_eval).
+%% Guard is_map/1 is not yet supported in HiPE.
+-compile(no_native).
+
%% An evaluator for Erlang abstract syntax.
-export([exprs/2,exprs/3,exprs/4,expr/2,expr/3,expr/4,expr/5,
@@ -239,6 +242,28 @@ expr({record,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
erlang:raise(error, {undef_record,Name}, stacktrace());
expr({record,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
erlang:raise(error, {undef_record,Name}, stacktrace());
+
+%% map
+expr({map,_,Binding,Es}, Bs0, Lf, Ef, RBs) ->
+ {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, none),
+ case Map0 of
+ #{} ->
+ {Vs,Bs2} = eval_map_fields(Es, Bs0, Lf, Ef),
+ Map1 = lists:foldl(fun ({map_assoc,K,V}, Mi) ->
+ maps:put(K, V, Mi);
+ ({map_exact,K,V}, Mi) ->
+ maps:update(K, V, Mi)
+ end, Map0, Vs),
+ ret_expr(Map1, merge_bindings(Bs2, Bs1), RBs);
+ _ ->
+ erlang:raise(error, {badarg,Map0}, stacktrace())
+ end;
+expr({map,_,Es}, Bs0, Lf, Ef, RBs) ->
+ {Vs,Bs} = eval_map_fields(Es, Bs0, Lf, Ef),
+ ret_expr(lists:foldl(fun
+ ({map_assoc,K,V}, Mi) -> maps:put(K,V,Mi)
+ end, maps:new(), Vs), Bs, RBs);
+
expr({block,_,Es}, Bs, Lf, Ef, RBs) ->
exprs(Es, Bs, Lf, Ef, RBs);
expr({'if',_,Cs}, Bs, Lf, Ef, RBs) ->
@@ -726,6 +751,24 @@ eval_filter(F, Bs0, Lf, Ef, CompFun, Acc) ->
end
end.
+%% eval_map_fields([Field], Bindings, LocalFunctionHandler,
+%% ExternalFuncHandler) ->
+%% {[{map_assoc | map_exact,Key,Value}],Bindings}
+
+eval_map_fields(Fs, Bs, Lf, Ef) ->
+ eval_map_fields(Fs, Bs, Lf, Ef, []).
+
+eval_map_fields([{map_field_assoc,_,K0,V0}|Fs], Bs0, Lf, Ef, Acc) ->
+ {value,K1,Bs1} = expr(K0, Bs0, Lf, Ef, none),
+ {value,V1,Bs2} = expr(V0, Bs1, Lf, Ef, none),
+ eval_map_fields(Fs, Bs2, Lf, Ef, [{map_assoc,K1,V1}|Acc]);
+eval_map_fields([{map_field_exact,_,K0,V0}|Fs], Bs0, Lf, Ef, Acc) ->
+ {value,K1,Bs1} = expr(K0, Bs0, Lf, Ef, none),
+ {value,V1,Bs2} = expr(V0, Bs1, Lf, Ef, none),
+ eval_map_fields(Fs, Bs2, Lf, Ef, [{map_exact,K1,V1}|Acc]);
+eval_map_fields([], Bs, _Lf, _Ef, Acc) ->
+ {lists:reverse(Acc),Bs}.
+
%% RBs is the bindings to return when the evalution of a function
%% (fun) has finished. If RBs =:= none, then the evalution took place
@@ -973,12 +1016,16 @@ guard0([], _Bs, _Lf, _Ef) -> true.
guard_test({call,L,{atom,Ln,F},As0}, Bs0, Lf, Ef) ->
TT = type_test(F),
G = {call,L,{atom,Ln,TT},As0},
- try {value,true,_} = expr(G, Bs0, Lf, Ef, none)
- catch error:_ -> {value,false,Bs0} end;
-guard_test({call,L,{remote,_Lr,{atom,_Lm,erlang},{atom,_Lf,_F}=T},As0},
+ expr_guard_test(G, Bs0, Lf, Ef);
+guard_test({call,L,{remote,Lr,{atom,Lm,erlang},{atom,Lf,F}},As0},
Bs0, Lf, Ef) ->
- guard_test({call,L,T,As0}, Bs0, Lf, Ef);
+ TT = type_test(F),
+ G = {call,L,{remote,Lr,{atom,Lm,erlang},{atom,Lf,TT}},As0},
+ expr_guard_test(G, Bs0, Lf, Ef);
guard_test(G, Bs0, Lf, Ef) ->
+ expr_guard_test(G, Bs0, Lf, Ef).
+
+expr_guard_test(G, Bs0, Lf, Ef) ->
try {value,true,_} = expr(G, Bs0, Lf, Ef, none)
catch error:_ -> {value,false,Bs0} end.
@@ -994,6 +1041,7 @@ type_test(port) -> is_port;
type_test(function) -> is_function;
type_test(binary) -> is_binary;
type_test(record) -> is_record;
+type_test(map) -> is_map;
type_test(Test) -> Test.
@@ -1075,6 +1123,10 @@ match1({tuple,_,Elts}, Tuple, Bs, BBs)
match_tuple(Elts, Tuple, 1, Bs, BBs);
match1({tuple,_,_}, _, _Bs, _BBs) ->
throw(nomatch);
+match1({map,_,Fs}, #{}=Map, Bs, BBs) ->
+ match_map(Fs, Map, Bs, BBs);
+match1({map,_,_}, _, _Bs, _BBs) ->
+ throw(nomatch);
match1({bin, _, Fs}, <<_/bitstring>>=B, Bs0, BBs) ->
eval_bits:match_bits(Fs, B, Bs0, BBs,
match_fun(BBs),
@@ -1118,6 +1170,18 @@ match_tuple([E|Es], Tuple, I, Bs0, BBs) ->
match_tuple([], _, _, Bs, _BBs) ->
{match,Bs}.
+match_map([{map_field_exact, _, K, V}|Fs], Map, Bs0, BBs) ->
+ Vm = try
+ {value, Ke, _} = expr(K, new_bindings()),
+ maps:get(Ke,Map)
+ catch error:_ ->
+ throw(nomatch)
+ end,
+ {match, Bs} = match1(V, Vm, Bs0, BBs),
+ match_map(Fs, Map, Bs, BBs);
+match_map([], _, Bs, _) ->
+ {match, Bs}.
+
%% match_list(PatternList, TermList, Bindings) ->
%% {match,NewBindings} | nomatch
%% Try to match a list of patterns against a list of terms with the