From 723fa9efadf7f841e7b835393ce801aa0a03e1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 15 Apr 2013 18:28:15 +0200 Subject: Teach erl_scan to recognize '=>' --- lib/stdlib/src/erl_scan.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl index 4ba6dd01fa..52376a8f3a 100644 --- a/lib/stdlib/src/erl_scan.erl +++ b/lib/stdlib/src/erl_scan.erl @@ -569,7 +569,7 @@ scan1("++"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "++", '++', 2); scan1("+"=Cs, _St, Line, Col, Toks) -> {more,{Cs,Col,Toks,Line,[],fun scan/6}}; -%% =:= =/= =< == +%% =:= =/= =< == => scan1("=:="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "=:=", '=:=', 3); scan1("=:"=Cs, _St, Line, Col, Toks) -> @@ -580,6 +580,8 @@ scan1("=/"=Cs, _St, Line, Col, Toks) -> {more,{Cs,Col,Toks,Line,[],fun scan/6}}; scan1("=<"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "=<", '=<', 2); +scan1("=>"++Cs, St, Line, Col, Toks) -> + tok2(Cs, St, Line, Col, Toks, "=>", '=>', 2); scan1("=="++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "==", '==', 2); scan1("="=Cs, _St, Line, Col, Toks) -> -- cgit v1.2.3 From 703a9aa47168f7f8c11bf835502281bd59ba77f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 15 Apr 2013 18:09:50 +0200 Subject: Extend erl_parse with the new map syntax Example how to match or construct: #{ K1 => V1, K2 => V2 } How to update: M#{ K => V } --- lib/stdlib/src/erl_parse.yrl | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 59a05a48ee..5a846266c5 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -34,6 +34,7 @@ binary_comprehension tuple %struct record_expr record_tuple record_field record_fields +map_expr map_tuple map_field map_fields map_key if_expr if_clause if_clauses case_expr cr_clause cr_clauses receive_expr fun_expr fun_clause fun_clauses atom_or_var integer_or_var try_expr try_catch try_clause try_clauses @@ -59,7 +60,7 @@ char integer float atom string var '*' '/' 'div' 'rem' 'band' 'and' '+' '-' 'bor' 'bxor' 'bsl' 'bsr' 'or' 'xor' '++' '--' -'==' '/=' '=<' '<' '>=' '>' '=:=' '=/=' '<=' +'==' '/=' '=<' '<' '>=' '>' '=:=' '=/=' '<=' '=>' '<<' '>>' '!' '=' '::' '..' '...' 'spec' 'callback' % helper @@ -247,6 +248,7 @@ expr_500 -> expr_600 : '$1'. expr_600 -> prefix_op expr_700 : ?mkop1('$1', '$2'). +expr_600 -> map_expr : '$1'. expr_600 -> expr_700 : '$1'. expr_700 -> function_call : '$1'. @@ -327,6 +329,26 @@ tuple -> '{' exprs '}' : {tuple,?line('$1'),'$2'}. %%struct -> atom tuple : %% {struct,?line('$1'),element(3, '$1'),element(3, '$2')}. +map_expr -> '#' map_tuple : + {map, ?line('$1'),'$2'}. +map_expr -> expr_max '#' map_tuple : + {map, ?line('$2'),'$1','$3'}. +map_expr -> map_expr '#' map_tuple : + {map, ?line('$2'),'$1','$3'}. +map_expr -> map_expr '.' atom : + {map_field, ?line('$2'),'$1','$3'}. + +map_tuple -> '{' '}' : []. +map_tuple -> '{' map_fields '}' : '$2'. + +map_fields -> map_field : ['$1']. +map_fields -> map_field ',' map_fields : ['$1' | '$3']. + +map_field -> map_key '=>' expr : + {map_field,?line('$1'),'$1','$3'}. + +map_key -> expr : '$1'. + %% N.B. This is called from expr_700. %% N.B. Field names are returned as the complete object, even if they are @@ -1060,3 +1082,5 @@ get_attribute(L, Name) -> get_attributes(L) -> erl_scan:attributes_info(L). + +%% vim: ft=erlang -- cgit v1.2.3 From 860171895f5858314abd85f8461568f34e76c427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 16 May 2012 10:47:58 +0200 Subject: Update erl_lint, erl_expand_records, sys_pre_expand for maps --- lib/stdlib/src/erl_expand_records.erl | 14 ++++++++++++++ lib/stdlib/src/erl_lint.erl | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl index 776b433613..7fc4cc7887 100644 --- a/lib/stdlib/src/erl_expand_records.erl +++ b/lib/stdlib/src/erl_expand_records.erl @@ -132,6 +132,12 @@ pattern({cons,Line,H,T}, St0) -> pattern({tuple,Line,Ps}, St0) -> {TPs,St1} = pattern_list(Ps, St0), {{tuple,Line,TPs},St1}; +pattern({map,Line,Ps}, St0) -> + {TPs,St1} = pattern_list(Ps, St0), + {{map,Line,TPs},St1}; +pattern({map_field,Line,Key,V0}, St0) -> + {V,St1} = pattern(V0, St0), + {{map_field,Line,Key,V},St1}; %%pattern({struct,Line,Tag,Ps}, St0) -> %% {TPs,TPsvs,St1} = pattern_list(Ps, St0), %% {{struct,Line,Tag,TPs},TPsvs,St1}; @@ -301,6 +307,14 @@ expr({bc,Line,E0,Qs0}, St0) -> expr({tuple,Line,Es0}, St0) -> {Es1,St1} = expr_list(Es0, St0), {{tuple,Line,Es1},St1}; +expr({map,Line,Es0}, St0) -> + {Es1,St1} = expr_list(Es0, St0), + {{map,Line,Es1},St1}; +expr({map,Line,Var,Es0}, St0) -> + {Es1,St1} = expr_list(Es0, St0), + {{map,Line,Var,Es1},St1}; +expr({map_field,_Line,_,_}=M, St0) -> + {M,St0}; %%expr({struct,Line,Tag,Es0}, Vs, St0) -> %% {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0), %% {{struct,Line,Tag,Es1},Esvs,Esus,St1}; diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index f0d50df4c7..b74a3ed924 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -1366,6 +1366,11 @@ pattern({cons,_Line,H,T}, Vt, Old, Bvt, St0) -> {vtmerge_pat(Hvt, Tvt),vtmerge_pat(Bvt1,Bvt2),St2}; pattern({tuple,_Line,Ps}, Vt, Old, Bvt, St) -> pattern_list(Ps, Vt, Old, Bvt, St); +pattern({map,_Line,Ps}, Vt, Old, Bvt, St) -> + pattern_list(Ps, Vt, Old, Bvt, St); +pattern({map_field,_Line,_,P}, Vt, Old, Bvt0, St0) -> + {Pvt,Bvt,St1} = pattern(P, Vt, Old, Bvt0, St0), + {Pvt,Bvt,St1}; %%pattern({struct,_Line,_Tag,Ps}, Vt, Old, Bvt, St) -> %% pattern_list(Ps, Vt, Old, Bvt, St); pattern({record_index,Line,Name,Field}, _Vt, _Old, _Bvt, St) -> @@ -1753,6 +1758,12 @@ gexpr({cons,_Line,H,T}, Vt, St) -> gexpr_list([H,T], Vt, St); gexpr({tuple,_Line,Es}, Vt, St) -> gexpr_list(Es, Vt, St); +gexpr({map,_Line,Es}, Vt, St) -> + gexpr_list(Es, Vt, St); +gexpr({map,_Line,Src,Es}, Vt, St) -> + gexpr_list([Src|Es], Vt, St); +gexpr({map_field,_Line,K,V}, Vt, St) -> + gexpr_list([K,V], Vt, St); gexpr({record_index,Line,Name,Field}, _Vt, St) -> check_record(Line, Name, St, fun (Dfs, St1) -> record_field(Field, Name, Dfs, St1) end ); @@ -1970,6 +1981,12 @@ expr({bc,_Line,E,Qs}, Vt, St) -> handle_comprehension(E, Qs, Vt, St); expr({tuple,_Line,Es}, Vt, St) -> expr_list(Es, Vt, St); +expr({map,_Line,Es}, Vt, St) -> + expr_list(Es, Vt, St); +expr({map,_Line,Src,Es}, Vt, St) -> + expr_list([Src|Es], Vt, St); +expr({map_field,_Line,K,V}, Vt, St) -> + expr_list([K,V], Vt, St); expr({record_index,Line,Name,Field}, _Vt, St) -> check_record(Line, Name, St, fun (Dfs, St1) -> record_field(Field, Name, Dfs, St1) end); -- cgit v1.2.3 From 63ef0bbfdfb70673fe7f3ce2fc6fa4f0f801747d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 19 Sep 2013 17:48:28 +0200 Subject: erts: Add the size-testing guard BIF map_size/1 --- lib/stdlib/src/erl_internal.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl index 28de7205ea..480675554a 100644 --- a/lib/stdlib/src/erl_internal.erl +++ b/lib/stdlib/src/erl_internal.erl @@ -70,6 +70,7 @@ guard_bif(bit_size, 1) -> true; guard_bif(byte_size, 1) -> true; guard_bif(element, 2) -> true; guard_bif(self, 0) -> true; +guard_bif(map_size, 1) -> true; guard_bif(node, 0) -> true; guard_bif(node, 1) -> true; guard_bif(tuple_size, 1) -> true; @@ -335,6 +336,7 @@ bif(list_to_pid, 1) -> true; bif(list_to_tuple, 1) -> true; bif(load_module, 2) -> true; bif(make_ref, 0) -> true; +bif(map_size,1) -> true; bif(max,2) -> true; bif(min,2) -> true; bif(module_loaded, 1) -> true; -- cgit v1.2.3 From 43ed0cc716039c3b2f65a5395f00424169639309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 21 May 2013 18:11:39 +0200 Subject: erts: Add the type-testing guard BIF is_map/1 To add a type-testing guard BIF, the following steps are needed: * The BIF itself is added to bif.tab (note that it should be declared using "ubif", not "bif"), and its implementation to erl_bif_op.c. * erl_internal must be modified in 3 places: The type test must be recognized as guard BIF, as a type test, and it must be auto-imported. * There must be an instruction that implements the same type test as the BIF (it will be used in guards). beam_utils:bif_to_test/3 must be updated to recognize the new guard BIF. --- lib/stdlib/src/erl_internal.erl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl index 480675554a..edfb097de0 100644 --- a/lib/stdlib/src/erl_internal.erl +++ b/lib/stdlib/src/erl_internal.erl @@ -83,6 +83,7 @@ guard_bif(is_function, 1) -> true; guard_bif(is_function, 2) -> true; guard_bif(is_integer, 1) -> true; guard_bif(is_list, 1) -> true; +guard_bif(is_map, 1) -> true; guard_bif(is_number, 1) -> true; guard_bif(is_pid, 1) -> true; guard_bif(is_port, 1) -> true; @@ -114,6 +115,7 @@ new_type_test(is_function, 1) -> true; new_type_test(is_function, 2) -> true; new_type_test(is_integer, 1) -> true; new_type_test(is_list, 1) -> true; +new_type_test(is_map, 1) -> true; new_type_test(is_number, 1) -> true; new_type_test(is_pid, 1) -> true; new_type_test(is_port, 1) -> true; @@ -316,6 +318,7 @@ bif(is_function, 1) -> true; bif(is_function, 2) -> true; bif(is_integer, 1) -> true; bif(is_list, 1) -> true; +bif(is_map, 1) -> true; bif(is_number, 1) -> true; bif(is_pid, 1) -> true; bif(is_port, 1) -> true; -- cgit v1.2.3 From d6b62db709a9e8e80689416bd7a5e5444ac3d3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 17 May 2013 11:49:48 +0200 Subject: stdlib: Update printing to handle Maps --- lib/stdlib/src/io_lib.erl | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl index 375d05f359..886939761c 100644 --- a/lib/stdlib/src/io_lib.erl +++ b/lib/stdlib/src/io_lib.erl @@ -257,7 +257,9 @@ write(T, D) when is_tuple(T) -> [write(element(1, T), D-1)| write_tail(tl(tuple_to_list(T)), D-1, $,)], $}] - end. + end; +%write(Term, D) when is_map(Term) -> write_map(Term, D); +write(Term, D) -> write_map(Term, D). %% write_tail(List, Depth, CharacterBeforeDots) %% Test the terminating case first as this looks better with depth. @@ -275,6 +277,18 @@ write_port(Port) -> write_ref(Ref) -> erlang:ref_to_list(Ref). +write_map(Map, D) when is_integer(D) -> + [$#,${,write_map_body(map:to_list(Map), D),$}]. + +write_map_body(_, 0) -> "..."; +write_map_body([],_) -> []; +write_map_body([{K,V}],D) -> write_map_assoc(K,V,D); +write_map_body([{K,V}|KVs], D) -> + [write_map_assoc(K,V,D),$, | write_map_body(KVs,D-1)]. + +write_map_assoc(K,V,D) -> + [write(K,D - 1),"=>",write(V,D-1)]. + write_binary(B, D) when is_integer(D) -> [$<,$<,write_binary_body(B, D),$>,$>]. -- cgit v1.2.3 From 542c79e9685adbdab398856af99aaf9137966ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 4 Jun 2012 00:36:11 +0200 Subject: erl_eval: Add functions to interpreter for maps --- lib/stdlib/src/erl_eval.erl | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index 18d8148b15..335134d1f0 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -239,6 +239,21 @@ 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_field,_,EK, EV}, Bs0, Lf, Ef, RBs) -> + {value,K,Bs1} = expr(EK, Bs0, Lf, Ef, none), + {value,V,Bs2} = expr(EV, Bs0, Lf, Ef, none), + ret_expr({K,V}, merge_bindings(Bs1,Bs2), RBs); +expr({map,_, Binding,Es}, Bs0, Lf, Ef, RBs) -> + {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, RBs), + {Vs,Bs} = expr_list(Es, Bs1, Lf, Ef), + ret_expr(lists:foldl(fun({K,V}, Mi) -> map:put(K,V,Mi) end, Map0, Vs), Bs, RBs); +expr({map,_,Es}, Bs0, Lf, Ef, RBs) -> + {Vs,Bs} = expr_list(Es, Bs0, Lf, Ef), + ret_expr(lists:foldl(fun({K,V}, Mi) -> map:put(K,V,Mi) end, map:new(), Vs), Bs, RBs); + + expr({block,_,Es}, Bs, Lf, Ef, RBs) -> exprs(Es, Bs, Lf, Ef, RBs); expr({'if',_,Cs}, Bs, Lf, Ef, RBs) -> @@ -994,6 +1009,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 +1091,9 @@ 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({bin, _, Fs}, <<_/bitstring>>=B, Bs0, BBs) -> eval_bits:match_bits(Fs, B, Bs0, BBs, match_fun(BBs), @@ -1118,6 +1137,15 @@ match_tuple([E|Es], Tuple, I, Bs0, BBs) -> match_tuple([], _, _, Bs, _BBs) -> {match,Bs}. +match_map([{map_field, _, K, V}|Fs], Map, Bs0, BBs) -> + Vm = try map:get(element(3,K),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 -- cgit v1.2.3 From 226e1e5898058aa3459c4d562df13132c9bc0899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 1 Oct 2013 22:08:14 +0200 Subject: Teach erl_scan to recognize ':=' --- lib/stdlib/src/erl_scan.erl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl index 52376a8f3a..ae59d5f44f 100644 --- a/lib/stdlib/src/erl_scan.erl +++ b/lib/stdlib/src/erl_scan.erl @@ -596,6 +596,9 @@ scan1("||"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, "||", '||', 2); scan1("|"=Cs, _St, Line, Col, Toks) -> {more,{Cs,Col,Toks,Line,[],fun scan/6}}; +%% := +scan1(":="++Cs, St, Line, Col, Toks) -> + tok2(Cs, St, Line, Col, Toks, ":=", ':=', 2); %% :- scan1(":-"++Cs, St, Line, Col, Toks) -> tok2(Cs, St, Line, Col, Toks, ":-", ':-', 2); -- cgit v1.2.3 From b15b2098627f702958771c3497949c62623a415d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 1 Oct 2013 22:29:29 +0200 Subject: Extend erl_parse with two Op Map syntax Example how to construct: #{ K1 => V1, K2 => V2 } How to update: M#{ K1 => V1, K2 := V2 } How to match: #{ K1 := V1, K2 := V2 } = M --- lib/stdlib/src/erl_parse.yrl | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 5a846266c5..35c33c7796 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -34,7 +34,7 @@ binary_comprehension tuple %struct record_expr record_tuple record_field record_fields -map_expr map_tuple map_field map_fields map_key +map_expr map_tuple map_field map_field_assoc map_field_exact map_fields map_key if_expr if_clause if_clauses case_expr cr_clause cr_clauses receive_expr fun_expr fun_clause fun_clauses atom_or_var integer_or_var try_expr try_catch try_clause try_clauses @@ -60,7 +60,7 @@ char integer float atom string var '*' '/' 'div' 'rem' 'band' 'and' '+' '-' 'bor' 'bxor' 'bsl' 'bsr' 'or' 'xor' '++' '--' -'==' '/=' '=<' '<' '>=' '>' '=:=' '=/=' '<=' '=>' +'==' '/=' '=<' '<' '>=' '>' '=:=' '=/=' '<=' '=>' ':=' '<<' '>>' '!' '=' '::' '..' '...' 'spec' 'callback' % helper @@ -344,8 +344,14 @@ map_tuple -> '{' map_fields '}' : '$2'. map_fields -> map_field : ['$1']. map_fields -> map_field ',' map_fields : ['$1' | '$3']. -map_field -> map_key '=>' expr : - {map_field,?line('$1'),'$1','$3'}. +map_field -> map_field_assoc : '$1'. +map_field -> map_field_exact : '$1'. + +map_field_assoc -> map_key '=>' expr : + {map_field_assoc,?line('$1'),'$1','$3'}. + +map_field_exact -> map_key ':=' expr : + {map_field_exact,?line('$1'),'$1','$3'}. map_key -> expr : '$1'. -- cgit v1.2.3 From a0133aa75da3756918a5b9fd427ae75a75ae1dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Sat, 26 Oct 2013 01:21:23 +0200 Subject: stdlib: Fix erl_parse:parse_term/1 Did not handle Maps. --- lib/stdlib/src/erl_parse.yrl | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 35c33c7796..e9a813e098 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -888,6 +888,12 @@ normalise({cons,_,Head,Tail}) -> [normalise(Head)|normalise(Tail)]; normalise({tuple,_,Args}) -> list_to_tuple(normalise_list(Args)); +normalise({map,_,Pairs}=M) -> + map:from_list(lists:map(fun + %% only allow '=>' + ({map_field_assoc,_,K,V}) -> {normalise(K),normalise(V)}; + (_) -> erlang:error({badarg,M}) + end, Pairs)); %% Special case for unary +/-. normalise({op,_,'+',{char,_,I}}) -> I; normalise({op,_,'+',{integer,_,I}}) -> I; -- cgit v1.2.3 From 758702e24f0780130c6b3058426062a3761b7a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 1 Oct 2013 22:42:18 +0200 Subject: Update erl_lint, erl_expand_records, sys_pre_expand for Maps Update erlang lint and syntax expand for #{ K := V } --- lib/stdlib/src/erl_expand_records.erl | 14 ++++++++++---- lib/stdlib/src/erl_lint.erl | 12 +++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl index 7fc4cc7887..4741bef6b9 100644 --- a/lib/stdlib/src/erl_expand_records.erl +++ b/lib/stdlib/src/erl_expand_records.erl @@ -135,9 +135,9 @@ pattern({tuple,Line,Ps}, St0) -> pattern({map,Line,Ps}, St0) -> {TPs,St1} = pattern_list(Ps, St0), {{map,Line,TPs},St1}; -pattern({map_field,Line,Key,V0}, St0) -> +pattern({map_field_exact,Line,Key,V0}, St0) -> {V,St1} = pattern(V0, St0), - {{map_field,Line,Key,V},St1}; + {{map_field_exact,Line,Key,V},St1}; %%pattern({struct,Line,Tag,Ps}, St0) -> %% {TPs,TPsvs,St1} = pattern_list(Ps, St0), %% {{struct,Line,Tag,TPs},TPsvs,St1}; @@ -313,8 +313,14 @@ expr({map,Line,Es0}, St0) -> expr({map,Line,Var,Es0}, St0) -> {Es1,St1} = expr_list(Es0, St0), {{map,Line,Var,Es1},St1}; -expr({map_field,_Line,_,_}=M, St0) -> - {M,St0}; +expr({map_field_assoc,Line,K0,V0}, St0) -> + {K,St1} = expr(K0, St0), + {V,St2} = expr(V0, St1), + {{map_field_assoc,Line,K,V},St2}; +expr({map_field_exact,Line,K0,V0}, St0) -> + {K,St1} = expr(K0, St0), + {V,St2} = expr(V0, St1), + {{map_field_exact,Line,K,V},St2}; %%expr({struct,Line,Tag,Es0}, Vs, St0) -> %% {Es1,Esvs,Esus,St1} = expr_list(Es0, Vs, St0), %% {{struct,Line,Tag,Es1},Esvs,Esus,St1}; diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index b74a3ed924..86ebe82acc 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -1368,7 +1368,9 @@ pattern({tuple,_Line,Ps}, Vt, Old, Bvt, St) -> pattern_list(Ps, Vt, Old, Bvt, St); pattern({map,_Line,Ps}, Vt, Old, Bvt, St) -> pattern_list(Ps, Vt, Old, Bvt, St); -pattern({map_field,_Line,_,P}, Vt, Old, Bvt0, St0) -> +pattern({map_field_assoc,_Line,_,_}=Pat, _, _, _, St) -> + {[],[],add_error(element(2, Pat), illegal_pattern, St)}; +pattern({map_field_exact,_Line,_,P}, Vt, Old, Bvt0, St0) -> {Pvt,Bvt,St1} = pattern(P, Vt, Old, Bvt0, St0), {Pvt,Bvt,St1}; %%pattern({struct,_Line,_Tag,Ps}, Vt, Old, Bvt, St) -> @@ -1762,7 +1764,9 @@ gexpr({map,_Line,Es}, Vt, St) -> gexpr_list(Es, Vt, St); gexpr({map,_Line,Src,Es}, Vt, St) -> gexpr_list([Src|Es], Vt, St); -gexpr({map_field,_Line,K,V}, Vt, St) -> +gexpr({map_field_assoc,_Line,K,V}, Vt, St) -> + gexpr_list([K,V], Vt, St); +gexpr({map_field_exact,_Line,K,V}, Vt, St) -> gexpr_list([K,V], Vt, St); gexpr({record_index,Line,Name,Field}, _Vt, St) -> check_record(Line, Name, St, @@ -1985,7 +1989,9 @@ expr({map,_Line,Es}, Vt, St) -> expr_list(Es, Vt, St); expr({map,_Line,Src,Es}, Vt, St) -> expr_list([Src|Es], Vt, St); -expr({map_field,_Line,K,V}, Vt, St) -> +expr({map_field_assoc,_Line,K,V}, Vt, St) -> + expr_list([K,V], Vt, St); +expr({map_field_exact,_Line,K,V}, Vt, St) -> expr_list([K,V], Vt, St); expr({record_index,Line,Name,Field}, _Vt, St) -> check_record(Line, Name, St, -- cgit v1.2.3 From e9a3d0b6533b72cba3d4e7ea129f835e80bd2647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 2 Oct 2013 16:40:33 +0200 Subject: stdlib: Teach erl_eval Maps ':=' exact operator --- lib/stdlib/src/erl_eval.erl | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index 335134d1f0..fcd1945c63 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -241,18 +241,26 @@ expr({record,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) -> erlang:raise(error, {undef_record,Name}, stacktrace()); %% map -expr({map_field,_,EK, EV}, Bs0, Lf, Ef, RBs) -> +expr({map_field_assoc,_,EK, EV}, Bs0, Lf, Ef, RBs) -> {value,K,Bs1} = expr(EK, Bs0, Lf, Ef, none), {value,V,Bs2} = expr(EV, Bs0, Lf, Ef, none), - ret_expr({K,V}, merge_bindings(Bs1,Bs2), RBs); + ret_expr({map_assoc,K,V}, merge_bindings(Bs1,Bs2), RBs); +expr({map_field_exact,_,EK, EV}, Bs0, Lf, Ef, RBs) -> + {value,K,Bs1} = expr(EK, Bs0, Lf, Ef, none), + {value,V,Bs2} = expr(EV, Bs0, Lf, Ef, none), + ret_expr({map_exact,K,V}, merge_bindings(Bs1,Bs2), RBs); expr({map,_, Binding,Es}, Bs0, Lf, Ef, RBs) -> {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, RBs), {Vs,Bs} = expr_list(Es, Bs1, Lf, Ef), - ret_expr(lists:foldl(fun({K,V}, Mi) -> map:put(K,V,Mi) end, Map0, Vs), Bs, RBs); + ret_expr(lists:foldl(fun + ({map_assoc,K,V}, Mi) -> map:put(K,V,Mi); + ({map_exact,K,V}, Mi) -> map:update(K,V,Mi) + end, Map0, Vs), Bs, RBs); expr({map,_,Es}, Bs0, Lf, Ef, RBs) -> {Vs,Bs} = expr_list(Es, Bs0, Lf, Ef), - ret_expr(lists:foldl(fun({K,V}, Mi) -> map:put(K,V,Mi) end, map:new(), Vs), Bs, RBs); - + ret_expr(lists:foldl(fun + ({map_assoc,K,V}, Mi) -> map:put(K,V,Mi) + end, map:new(), Vs), Bs, RBs); expr({block,_,Es}, Bs, Lf, Ef, RBs) -> exprs(Es, Bs, Lf, Ef, RBs); @@ -1137,9 +1145,12 @@ match_tuple([E|Es], Tuple, I, Bs0, BBs) -> match_tuple([], _, _, Bs, _BBs) -> {match,Bs}. -match_map([{map_field, _, K, V}|Fs], Map, Bs0, BBs) -> - Vm = try map:get(element(3,K),Map) - catch error:_ -> throw(nomatch) +match_map([{map_field_exact, _, K, V}|Fs], Map, Bs0, BBs) -> + Vm = try + {value, Ke, _} = expr(K, new_bindings()), + map:get(Ke,Map) + catch error:_ -> + throw(nomatch) end, {match, Bs} = match1(V, Vm, Bs0, BBs), match_map(Fs, Map, Bs, BBs); -- cgit v1.2.3 From f00675d3c682f53824e23f1599cbb09ff2d57daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 9 Oct 2013 16:37:58 +0200 Subject: stdlib: Deny variables as keys and disallow ':=' in map construction In the current iteration of Maps we should deny *any* variables in Map keys. --- lib/stdlib/src/erl_lint.erl | 57 +++++++++++++++++++++++++++++++++++--------- lib/stdlib/src/erl_parse.yrl | 2 -- 2 files changed, 46 insertions(+), 13 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 86ebe82acc..a41bcb91cc 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -225,6 +225,8 @@ format_error({too_many_arguments,Arity}) -> "maximum allowed is ~w", [Arity,?MAX_ARGUMENTS]); %% --- patterns and guards --- format_error(illegal_pattern) -> "illegal pattern"; +format_error({illegal_map_key_variable,K}) -> + io_lib:format("illegal use of variable ~w in map",[K]); format_error(illegal_bin_pattern) -> "binary patterns cannot be matched in parallel using '='"; format_error(illegal_expr) -> "illegal expression"; @@ -232,6 +234,9 @@ format_error({illegal_guard_local_call, {F,A}}) -> io_lib:format("call to local/imported function ~w/~w is illegal in guard", [F,A]); format_error(illegal_guard_expr) -> "illegal guard expression"; +%% --- maps --- +format_error(illegal_map_construction) -> + "only association operators '=>' are allowed in map construction"; %% --- records --- format_error({undefined_record,T}) -> io_lib:format("record ~w undefined", [T]); @@ -1368,11 +1373,17 @@ pattern({tuple,_Line,Ps}, Vt, Old, Bvt, St) -> pattern_list(Ps, Vt, Old, Bvt, St); pattern({map,_Line,Ps}, Vt, Old, Bvt, St) -> pattern_list(Ps, Vt, Old, Bvt, St); -pattern({map_field_assoc,_Line,_,_}=Pat, _, _, _, St) -> - {[],[],add_error(element(2, Pat), illegal_pattern, St)}; -pattern({map_field_exact,_Line,_,P}, Vt, Old, Bvt0, St0) -> - {Pvt,Bvt,St1} = pattern(P, Vt, Old, Bvt0, St0), - {Pvt,Bvt,St1}; +pattern({map_field_assoc,Line,_,_}, _, _, _, St) -> + {[],[],add_error(Line, illegal_pattern, St)}; +pattern({map_field_exact,Line,KP,VP}, Vt, Old, Bvt0, St0) -> + %% if the key pattern has variables we should fail + case expr(KP,[],St0) of + {[],_} -> + pattern(VP, Vt, Old, Bvt0, St0); + {[Var|_],_} -> + %% found variables in key expression + {Vt,Old,add_error(Line,{illegal_map_key_variable,element(1,Var)},St0)} + end; %%pattern({struct,_Line,_Tag,Ps}, Vt, Old, Bvt, St) -> %% pattern_list(Ps, Vt, Old, Bvt, St); pattern({record_index,Line,Name,Field}, _Vt, _Old, _Bvt, St) -> @@ -1985,14 +1996,24 @@ expr({bc,_Line,E,Qs}, Vt, St) -> handle_comprehension(E, Qs, Vt, St); expr({tuple,_Line,Es}, Vt, St) -> expr_list(Es, Vt, St); -expr({map,_Line,Es}, Vt, St) -> - expr_list(Es, Vt, St); +expr({map,Line,Es}, Vt, St) -> + {Rvt,St1} = expr_list(Es,Vt,St), + case is_valid_map_construction(Es) of + true -> {Rvt,St1}; + false -> {[],add_error(Line,illegal_map_construction,St1)} + end; expr({map,_Line,Src,Es}, Vt, St) -> expr_list([Src|Es], Vt, St); -expr({map_field_assoc,_Line,K,V}, Vt, St) -> - expr_list([K,V], Vt, St); -expr({map_field_exact,_Line,K,V}, Vt, St) -> - expr_list([K,V], Vt, St); +expr({map_field_assoc,Line,K,V}, Vt, St) -> + case is_valid_map_key(K,St) of + true -> expr_list([K,V], Vt, St); + {false,Var} -> {[],add_error(Line,{illegal_map_key_variable,Var},St)} + end; +expr({map_field_exact,Line,K,V}, Vt, St) -> + case is_valid_map_key(K,St) of + true -> expr_list([K,V], Vt, St); + {false,Var} -> {[],add_error(Line,{illegal_map_key_variable,Var},St)} + end; expr({record_index,Line,Name,Field}, _Vt, St) -> check_record(Line, Name, St, fun (Dfs, St1) -> record_field(Field, Name, Dfs, St1) end); @@ -2252,6 +2273,20 @@ is_valid_call(Call) -> _ -> true end. +%% check_map_construction +%% Only #{ K => V }, i.e. assoc is a valid construction +is_valid_map_construction([{map_field_assoc,_,_,_}|Es]) -> + is_valid_map_construction(Es); +is_valid_map_construction([]) -> true; +is_valid_map_construction(_) -> false. + +is_valid_map_key(K,St) -> + case expr(K,[],St) of + {[],_} -> true; + {[Var|_],_} -> + {false,element(1,Var)} + end. + %% record_def(Line, RecordName, [RecField], State) -> State. %% Add a record definition if it does not already exist. Normalise %% so that all fields have explicit initial value. diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index e9a813e098..c04a1aeb89 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -335,8 +335,6 @@ map_expr -> expr_max '#' map_tuple : {map, ?line('$2'),'$1','$3'}. map_expr -> map_expr '#' map_tuple : {map, ?line('$2'),'$1','$3'}. -map_expr -> map_expr '.' atom : - {map_field, ?line('$2'),'$1','$3'}. map_tuple -> '{' '}' : []. map_tuple -> '{' map_fields '}' : '$2'. -- cgit v1.2.3 From 34b043379ee6952136db98c782f69e670c93f9fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 17 Oct 2013 15:01:52 +0200 Subject: stdlib: Update erl_scan_SUITE for ':=' and '=>' tokens --- lib/stdlib/test/erl_scan_SUITE.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl index e628f7248d..447e159cd4 100644 --- a/lib/stdlib/test/erl_scan_SUITE.erl +++ b/lib/stdlib/test/erl_scan_SUITE.erl @@ -224,8 +224,8 @@ atoms() -> punctuations() -> L = ["<<", "<-", "<=", "<", ">>", ">=", ">", "->", "--", - "-", "++", "+", "=:=", "=/=", "=<", "==", "=", "/=", - "/", "||", "|", ":-", "::", ":"], + "-", "++", "+", "=:=", "=/=", "=<", "=>", "==", "=", "/=", + "/", "||", "|", ":=", ":-", "::", ":"], %% One token at a time: [begin W = list_to_atom(S), -- cgit v1.2.3 From c3a45ed9ae4f84018a63df18666d0752beb8458a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 10 Oct 2013 20:13:49 +0200 Subject: stdlib: Add Map module The map type is set to term. --- lib/stdlib/src/Makefile | 1 + lib/stdlib/src/map.erl | 215 ++++++++++++++++++++++++++++++++++++++++++ lib/stdlib/src/stdlib.app.src | 1 + 3 files changed, 217 insertions(+) create mode 100644 lib/stdlib/src/map.erl (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile index f3387d669b..376083c7d6 100644 --- a/lib/stdlib/src/Makefile +++ b/lib/stdlib/src/Makefile @@ -91,6 +91,7 @@ MODULES= \ lib \ lists \ log_mf_h \ + map \ math \ ms_transform \ otp_internal \ diff --git a/lib/stdlib/src/map.erl b/lib/stdlib/src/map.erl new file mode 100644 index 0000000000..6257a90180 --- /dev/null +++ b/lib/stdlib/src/map.erl @@ -0,0 +1,215 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(map). + +-export([ + foldl/3, + foldr/3, + map/2, + size/1, + without/2 + ]). + + +%%% BIFs +-export([ + get/2, + find/2, + from_list/1, + is_key/2, + keys/1, + merge/2, + new/0, + put/3, + remove/2, + to_list/1, + update/3, + values/1 + ]). + +-type map() :: term(). %% FIXME: remove when erl_bif_types knows map(). + +%% Shadowed by erl_bif_types: map:get/3 +-spec get(Key,Map) -> Value when + Key :: term(), + Map :: map(), + Value :: term(). + +get(_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:find/3 +-spec find(Key,Map) -> {ok, Value} | error when + Key :: term(), + Map :: map(), + Value :: term(). + +find(_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:from_list/1 +-spec from_list([{Key,Value}]) -> Map when + Key :: term(), + Value :: term(), + Map :: map(). + +from_list(_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:is_key/2 +-spec is_key(Key,Map) -> boolean() when + Key :: term(), + Map :: map(). + +is_key(_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:keys/1 +-spec keys(Map) -> Keys when + Map :: map(), + Keys :: [Key], + Key :: term(). + +keys(_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:merge/2 +-spec merge(Map1,Map2) -> Map3 when + Map1 :: map(), + Map2 :: map(), + Map3 :: map(). + +merge(_,_) -> erlang:nif_error(undef). + + + +%% Shadowed by erl_bif_types: map:new/0 +-spec new() -> Map when + Map :: map(). + +new() -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:put/3 +-spec put(Key,Value,Map1) -> Map2 when + Key :: term(), + Value :: term(), + Map1 :: map(), + Map2 :: map(). + +put(_,_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:put/3 +-spec remove(Key,Map1) -> Map2 when + Key :: term(), + Map1 :: map(), + Map2 :: map(). + +remove(_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:to_list/1 +-spec to_list(Map) -> [{Key,Value}] when + Map :: map(), + Key :: term(), + Value :: term(). + +to_list(_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:update/3 +-spec update(Key,Value,Map1) -> Map2 when + Key :: term(), + Value :: term(), + Map1 :: map(), + Map2 :: map(). + +update(_,_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: map:values/1 +-spec values(Map) -> Keys when + Map :: map(), + Keys :: [Key], + Key :: term(). + +values(_) -> erlang:nif_error(undef). + + +%%% End of BIFs + +-spec foldl(Fun,Init,Map) -> Acc when + Fun :: fun((K, V, AccIn) -> AccOut), + Init :: term(), + Acc :: term(), + AccIn :: term(), + AccOut :: term(), + Map :: map(), + K :: term(), + V :: term(). + +foldl(Fun, Init, Map) -> + lists:foldl(fun({K,V},A) -> Fun(K,V,A) end,Init,map:to_list(Map)). + +-spec foldr(Fun,Init,Map) -> Acc when + Fun :: fun((K,V,AccIn) -> AccOut), + Init :: term(), + Acc :: term(), + AccIn :: term(), + AccOut :: term(), + Map :: map(), + K :: term(), + V :: term(). + + +foldr(Fun, Init, Map) -> + lists:foldr(fun({K,V},A) -> Fun(K,V,A) end,Init,map:to_list(Map)). + + +-spec map(Fun,Map1) -> Map2 when + Fun :: fun((K, V1) -> V2), + Map1 :: map(), + Map2 :: map(), + K :: term(), + V1 :: term(), + V2 :: term(). + + +map(Fun, Map) -> + map:from_list(lists:map(fun + ({K,V}) -> + {K,Fun(K,V)} + end,map:to_list(Map))). + +-spec size(Map) -> non_neg_integer() when + Map :: map(). + +size(Map) -> + erlang:map_size(Map). + +-spec without(Ks,Map1) -> Map2 when + Ks :: [K], + Map1 :: map(), + Map2 :: map(), + K :: term(). + +without(Ks, M) -> + map:from_list([{K,V}||{K,V} <- map:to_list(M), not lists:member(K, Ks)]). diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src index a30685e830..9a77ae9d66 100644 --- a/lib/stdlib/src/stdlib.app.src +++ b/lib/stdlib/src/stdlib.app.src @@ -71,6 +71,7 @@ lib, lists, log_mf_h, + map, math, ms_transform, orddict, -- cgit v1.2.3 From 351987be44e11e6eb9e5841adb197ec8e49bc49d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 6 Nov 2013 09:01:30 +0100 Subject: dialyzer,hipe,stdlib: Add Maps understanding to Dialyzer --- lib/stdlib/src/erl_lint.erl | 8 ++++++++ lib/stdlib/src/erl_parse.yrl | 9 +++++++++ 2 files changed, 17 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index a41bcb91cc..f630db6032 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -2607,6 +2607,13 @@ check_type({type, L, range, [From, To]}, SeenVars, St) -> _ -> add_error(L, {type_syntax, range}, St) end, {SeenVars, St1}; +check_type({type, _L, map, any}, SeenVars, St) -> {SeenVars, St}; +check_type({type, _L, map, Pairs}, SeenVars, St) -> + lists:foldl(fun(Pair, {AccSeenVars, AccSt}) -> + check_type(Pair, AccSeenVars, AccSt) + end, {SeenVars, St}, Pairs); +check_type({type, _L, map_field_assoc, Dom, Range}, SeenVars, St) -> + check_type({type, -1, product, [Dom, Range]}, SeenVars, St); check_type({type, _L, tuple, any}, SeenVars, St) -> {SeenVars, St}; check_type({type, _L, any}, SeenVars, St) -> {SeenVars, St}; check_type({type, L, binary, [Base, Unit]}, SeenVars, St) -> @@ -2712,6 +2719,7 @@ is_default_type({iodata, 0}) -> true; is_default_type({iolist, 0}) -> true; is_default_type({list, 0}) -> true; is_default_type({list, 1}) -> true; +is_default_type({map, 0}) -> true; is_default_type({maybe_improper_list, 0}) -> true; is_default_type({maybe_improper_list, 2}) -> true; is_default_type({mfa, 0}) -> true; diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index c04a1aeb89..6d9aafa980 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -48,6 +48,7 @@ opt_bit_size_expr bit_size_expr opt_bit_type_list bit_type_list bit_type top_type top_type_100 top_types type typed_expr typed_attr_val type_sig type_sigs type_guard type_guards fun_type fun_type_100 binary_type type_spec spec_fun typed_exprs typed_record_fields field_types field_type +map_pair_types map_pair_type bin_base_type bin_unit_type type_200 type_300 type_400 type_500. Terminals @@ -155,6 +156,8 @@ type -> '[' ']' : {type, ?line('$1'), nil, []}. type -> '[' top_type ']' : {type, ?line('$1'), list, ['$2']}. type -> '[' top_type ',' '...' ']' : {type, ?line('$1'), nonempty_list, ['$2']}. +type -> '#' '{' '}' : {type, ?line('$1'), map, []}. +type -> '#' '{' map_pair_types '}' : {type, ?line('$1'), map, '$3'}. type -> '{' '}' : {type, ?line('$1'), tuple, []}. type -> '{' top_types '}' : {type, ?line('$1'), tuple, '$2'}. type -> '#' atom '{' '}' : {type, ?line('$1'), record, ['$2']}. @@ -176,6 +179,10 @@ fun_type -> '(' top_types ')' '->' top_type : {type, ?line('$1'), 'fun', [{type, ?line('$1'), product, '$2'},'$5']}. +map_pair_types -> map_pair_type : ['$1']. +map_pair_types -> map_pair_type ',' map_pair_types : ['$1'|'$3']. +map_pair_type -> top_type '=>' top_type : {type, ?line('$2'), map_field_assoc,'$1','$3'}. + field_types -> field_type : ['$1']. field_types -> field_type ',' field_types : ['$1'|'$3']. @@ -674,6 +681,8 @@ skip_paren(Type) -> build_gen_type({atom, La, tuple}) -> {type, La, tuple, any}; +build_gen_type({atom, La, map}) -> + {type, La, map, any}; build_gen_type({atom, La, Name}) -> {type, La, Name, []}. -- cgit v1.2.3 From 6868557c0244140ea7709822e8f7a0ba26029b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 25 Oct 2013 03:57:38 +0200 Subject: stdlib: Fixup id_transform_SUITE --- lib/stdlib/examples/erl_id_trans.erl | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl index 2c842fafc7..5fcb74310e 100644 --- a/lib/stdlib/examples/erl_id_trans.erl +++ b/lib/stdlib/examples/erl_id_trans.erl @@ -144,6 +144,13 @@ pattern({cons,Line,H0,T0}) -> pattern({tuple,Line,Ps0}) -> Ps1 = pattern_list(Ps0), {tuple,Line,Ps1}; +pattern({map,Line,Ps0}) -> + Ps1 = pattern_list(Ps0), + {map,Line,Ps1}; +pattern({map_field_exact,Line,K,V}) -> + Ke = pattern(K), + Ve = pattern(V), + {map_field_exact,Line,Ke,Ve}; %%pattern({struct,Line,Tag,Ps0}) -> %% Ps1 = pattern_list(Ps0), %% {struct,Line,Tag,Ps1}; @@ -251,6 +258,20 @@ gexpr({float,Line,F}) -> {float,Line,F}; gexpr({atom,Line,A}) -> {atom,Line,A}; gexpr({string,Line,S}) -> {string,Line,S}; gexpr({nil,Line}) -> {nil,Line}; +gexpr({map,Line,Map0,Es0}) -> + [Map1|Es1] = gexpr_list([Map0|Es0]), + {map,Line,Map1,Es1}; +gexpr({map,Line,Es0}) -> + Es1 = gexpr_list(Es0), + {map,Line,Es1}; +gexpr({map_field_assoc,Line,K,V}) -> + Ke = gexpr(K), + Ve = gexpr(V), + {map_field_assoc,Line,Ke,Ve}; +gexpr({map_field_exact,Line,K,V}) -> + Ke = gexpr(K), + Ve = gexpr(V), + {map_field_exact,Line,Ke,Ve}; gexpr({cons,Line,H0,T0}) -> H1 = gexpr(H0), T1 = gexpr(T0), %They see the same variables @@ -356,6 +377,20 @@ expr({bc,Line,E0,Qs0}) -> expr({tuple,Line,Es0}) -> Es1 = expr_list(Es0), {tuple,Line,Es1}; +expr({map,Line,Map0,Es0}) -> + [Map1|Es1] = exprs([Map0|Es0]), + {map,Line,Map1,Es1}; +expr({map,Line,Es0}) -> + Es1 = exprs(Es0), + {map,Line,Es1}; +expr({map_field_assoc,Line,K,V}) -> + Ke = expr(K), + Ve = expr(V), + {map_field_assoc,Line,Ke,Ve}; +expr({map_field_exact,Line,K,V}) -> + Ke = expr(K), + Ve = expr(V), + {map_field_exact,Line,Ke,Ve}; %%expr({struct,Line,Tag,Es0}) -> %% Es1 = pattern_list(Es0), %% {struct,Line,Tag,Es1}; -- cgit v1.2.3 From 457b29c9ddd2b338e80916a5e7bad8dfe4b36ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Fri, 25 Oct 2013 16:28:50 +0200 Subject: erts,stdlib: Teach matchspec compiler map guards --- lib/stdlib/src/ms_transform.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index 25b04fe45e..27dfcf52e1 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -910,6 +910,7 @@ bool_test(is_pid,1) -> true; bool_test(is_port,1) -> true; bool_test(is_reference,1) -> true; bool_test(is_tuple,1) -> true; +bool_test(is_map,1) -> true; bool_test(is_binary,1) -> true; bool_test(is_function,1) -> true; bool_test(is_record,2) -> true; @@ -924,6 +925,7 @@ real_guard_function(node,0) -> true; real_guard_function(node,1) -> true; real_guard_function(round,1) -> true; real_guard_function(size,1) -> true; +real_guard_function(map_size,1) -> true; real_guard_function(tl,1) -> true; real_guard_function(trunc,1) -> true; real_guard_function(self,0) -> true; -- cgit v1.2.3 From 6fdad74f41803089a0f9026c98f319daecda9a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 24 Oct 2013 19:06:34 +0200 Subject: erts,stdlib: Change map module name to maps Name conforms to EEP. --- lib/stdlib/src/Makefile | 2 +- lib/stdlib/src/erl_eval.erl | 10 +- lib/stdlib/src/erl_parse.yrl | 2 +- lib/stdlib/src/io_lib.erl | 2 +- lib/stdlib/src/map.erl | 215 ------------------------------------------ lib/stdlib/src/maps.erl | 214 +++++++++++++++++++++++++++++++++++++++++ lib/stdlib/src/stdlib.app.src | 2 +- 7 files changed, 223 insertions(+), 224 deletions(-) delete mode 100644 lib/stdlib/src/map.erl create mode 100644 lib/stdlib/src/maps.erl (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile index 376083c7d6..9ab2cd4134 100644 --- a/lib/stdlib/src/Makefile +++ b/lib/stdlib/src/Makefile @@ -91,7 +91,7 @@ MODULES= \ lib \ lists \ log_mf_h \ - map \ + maps \ math \ ms_transform \ otp_internal \ diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index fcd1945c63..5f96795d92 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -253,14 +253,14 @@ expr({map,_, Binding,Es}, Bs0, Lf, Ef, RBs) -> {value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, RBs), {Vs,Bs} = expr_list(Es, Bs1, Lf, Ef), ret_expr(lists:foldl(fun - ({map_assoc,K,V}, Mi) -> map:put(K,V,Mi); - ({map_exact,K,V}, Mi) -> map:update(K,V,Mi) + ({map_assoc,K,V}, Mi) -> maps:put(K,V,Mi); + ({map_exact,K,V}, Mi) -> maps:update(K,V,Mi) end, Map0, Vs), Bs, RBs); expr({map,_,Es}, Bs0, Lf, Ef, RBs) -> {Vs,Bs} = expr_list(Es, Bs0, Lf, Ef), ret_expr(lists:foldl(fun - ({map_assoc,K,V}, Mi) -> map:put(K,V,Mi) - end, map:new(), Vs), Bs, RBs); + ({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); @@ -1148,7 +1148,7 @@ match_tuple([], _, _, Bs, _BBs) -> match_map([{map_field_exact, _, K, V}|Fs], Map, Bs0, BBs) -> Vm = try {value, Ke, _} = expr(K, new_bindings()), - map:get(Ke,Map) + maps:get(Ke,Map) catch error:_ -> throw(nomatch) end, diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index 6d9aafa980..6316db7054 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -896,7 +896,7 @@ normalise({cons,_,Head,Tail}) -> normalise({tuple,_,Args}) -> list_to_tuple(normalise_list(Args)); normalise({map,_,Pairs}=M) -> - map:from_list(lists:map(fun + maps:from_list(lists:map(fun %% only allow '=>' ({map_field_assoc,_,K,V}) -> {normalise(K),normalise(V)}; (_) -> erlang:error({badarg,M}) diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl index 886939761c..adc9a0cf5f 100644 --- a/lib/stdlib/src/io_lib.erl +++ b/lib/stdlib/src/io_lib.erl @@ -278,7 +278,7 @@ write_ref(Ref) -> erlang:ref_to_list(Ref). write_map(Map, D) when is_integer(D) -> - [$#,${,write_map_body(map:to_list(Map), D),$}]. + [$#,${,write_map_body(maps:to_list(Map), D),$}]. write_map_body(_, 0) -> "..."; write_map_body([],_) -> []; diff --git a/lib/stdlib/src/map.erl b/lib/stdlib/src/map.erl deleted file mode 100644 index 6257a90180..0000000000 --- a/lib/stdlib/src/map.erl +++ /dev/null @@ -1,215 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2013. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - --module(map). - --export([ - foldl/3, - foldr/3, - map/2, - size/1, - without/2 - ]). - - -%%% BIFs --export([ - get/2, - find/2, - from_list/1, - is_key/2, - keys/1, - merge/2, - new/0, - put/3, - remove/2, - to_list/1, - update/3, - values/1 - ]). - --type map() :: term(). %% FIXME: remove when erl_bif_types knows map(). - -%% Shadowed by erl_bif_types: map:get/3 --spec get(Key,Map) -> Value when - Key :: term(), - Map :: map(), - Value :: term(). - -get(_,_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:find/3 --spec find(Key,Map) -> {ok, Value} | error when - Key :: term(), - Map :: map(), - Value :: term(). - -find(_,_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:from_list/1 --spec from_list([{Key,Value}]) -> Map when - Key :: term(), - Value :: term(), - Map :: map(). - -from_list(_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:is_key/2 --spec is_key(Key,Map) -> boolean() when - Key :: term(), - Map :: map(). - -is_key(_,_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:keys/1 --spec keys(Map) -> Keys when - Map :: map(), - Keys :: [Key], - Key :: term(). - -keys(_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:merge/2 --spec merge(Map1,Map2) -> Map3 when - Map1 :: map(), - Map2 :: map(), - Map3 :: map(). - -merge(_,_) -> erlang:nif_error(undef). - - - -%% Shadowed by erl_bif_types: map:new/0 --spec new() -> Map when - Map :: map(). - -new() -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:put/3 --spec put(Key,Value,Map1) -> Map2 when - Key :: term(), - Value :: term(), - Map1 :: map(), - Map2 :: map(). - -put(_,_,_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:put/3 --spec remove(Key,Map1) -> Map2 when - Key :: term(), - Map1 :: map(), - Map2 :: map(). - -remove(_,_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:to_list/1 --spec to_list(Map) -> [{Key,Value}] when - Map :: map(), - Key :: term(), - Value :: term(). - -to_list(_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:update/3 --spec update(Key,Value,Map1) -> Map2 when - Key :: term(), - Value :: term(), - Map1 :: map(), - Map2 :: map(). - -update(_,_,_) -> erlang:nif_error(undef). - - -%% Shadowed by erl_bif_types: map:values/1 --spec values(Map) -> Keys when - Map :: map(), - Keys :: [Key], - Key :: term(). - -values(_) -> erlang:nif_error(undef). - - -%%% End of BIFs - --spec foldl(Fun,Init,Map) -> Acc when - Fun :: fun((K, V, AccIn) -> AccOut), - Init :: term(), - Acc :: term(), - AccIn :: term(), - AccOut :: term(), - Map :: map(), - K :: term(), - V :: term(). - -foldl(Fun, Init, Map) -> - lists:foldl(fun({K,V},A) -> Fun(K,V,A) end,Init,map:to_list(Map)). - --spec foldr(Fun,Init,Map) -> Acc when - Fun :: fun((K,V,AccIn) -> AccOut), - Init :: term(), - Acc :: term(), - AccIn :: term(), - AccOut :: term(), - Map :: map(), - K :: term(), - V :: term(). - - -foldr(Fun, Init, Map) -> - lists:foldr(fun({K,V},A) -> Fun(K,V,A) end,Init,map:to_list(Map)). - - --spec map(Fun,Map1) -> Map2 when - Fun :: fun((K, V1) -> V2), - Map1 :: map(), - Map2 :: map(), - K :: term(), - V1 :: term(), - V2 :: term(). - - -map(Fun, Map) -> - map:from_list(lists:map(fun - ({K,V}) -> - {K,Fun(K,V)} - end,map:to_list(Map))). - --spec size(Map) -> non_neg_integer() when - Map :: map(). - -size(Map) -> - erlang:map_size(Map). - --spec without(Ks,Map1) -> Map2 when - Ks :: [K], - Map1 :: map(), - Map2 :: map(), - K :: term(). - -without(Ks, M) -> - map:from_list([{K,V}||{K,V} <- map:to_list(M), not lists:member(K, Ks)]). diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl new file mode 100644 index 0000000000..218dc28bec --- /dev/null +++ b/lib/stdlib/src/maps.erl @@ -0,0 +1,214 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(maps). + +-export([ + foldl/3, + foldr/3, + map/2, + size/1, + without/2 + ]). + + +%%% BIFs +-export([ + get/2, + find/2, + from_list/1, + is_key/2, + keys/1, + merge/2, + new/0, + put/3, + remove/2, + to_list/1, + update/3, + values/1 + ]). + +-type map() :: term(). %% FIXME: remove when erl_bif_types knows map(). + +%% Shadowed by erl_bif_types: maps:get/3 +-spec get(Key,Map) -> Value when + Key :: term(), + Map :: map(), + Value :: term(). + +get(_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:find/3 +-spec find(Key,Map) -> {ok, Value} | error when + Key :: term(), + Map :: map(), + Value :: term(). + +find(_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:from_list/1 +-spec from_list([{Key,Value}]) -> Map when + Key :: term(), + Value :: term(), + Map :: map(). + +from_list(_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:is_key/2 +-spec is_key(Key,Map) -> boolean() when + Key :: term(), + Map :: map(). + +is_key(_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:keys/1 +-spec keys(Map) -> Keys when + Map :: map(), + Keys :: [Key], + Key :: term(). + +keys(_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:merge/2 +-spec merge(Map1,Map2) -> Map3 when + Map1 :: map(), + Map2 :: map(), + Map3 :: map(). + +merge(_,_) -> erlang:nif_error(undef). + + + +%% Shadowed by erl_bif_types: maps:new/0 +-spec new() -> Map when + Map :: map(). + +new() -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:put/3 +-spec put(Key,Value,Map1) -> Map2 when + Key :: term(), + Value :: term(), + Map1 :: map(), + Map2 :: map(). + +put(_,_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:put/3 +-spec remove(Key,Map1) -> Map2 when + Key :: term(), + Map1 :: map(), + Map2 :: map(). + +remove(_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:to_list/1 +-spec to_list(Map) -> [{Key,Value}] when + Map :: map(), + Key :: term(), + Value :: term(). + +to_list(_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:update/3 +-spec update(Key,Value,Map1) -> Map2 when + Key :: term(), + Value :: term(), + Map1 :: map(), + Map2 :: map(). + +update(_,_,_) -> erlang:nif_error(undef). + + +%% Shadowed by erl_bif_types: maps:values/1 +-spec values(Map) -> Keys when + Map :: map(), + Keys :: [Key], + Key :: term(). + +values(_) -> erlang:nif_error(undef). + + +%%% End of BIFs + +-spec foldl(Fun,Init,Map) -> Acc when + Fun :: fun((K, V, AccIn) -> AccOut), + Init :: term(), + Acc :: term(), + AccIn :: term(), + AccOut :: term(), + Map :: map(), + K :: term(), + V :: term(). + +foldl(Fun, Init, Map) -> + lists:foldl(fun({K,V},A) -> Fun(K,V,A) end,Init,maps:to_list(Map)). + +-spec foldr(Fun,Init,Map) -> Acc when + Fun :: fun((K,V,AccIn) -> AccOut), + Init :: term(), + Acc :: term(), + AccIn :: term(), + AccOut :: term(), + Map :: map(), + K :: term(), + V :: term(). + +foldr(Fun, Init, Map) -> + lists:foldr(fun({K,V},A) -> Fun(K,V,A) end,Init,maps:to_list(Map)). + + +-spec map(Fun,Map1) -> Map2 when + Fun :: fun((K, V1) -> V2), + Map1 :: map(), + Map2 :: map(), + K :: term(), + V1 :: term(), + V2 :: term(). + +map(Fun, Map) -> + maps:from_list(lists:map(fun + ({K,V}) -> + {K,Fun(K,V)} + end,maps:to_list(Map))). + + +-spec size(Map) -> non_neg_integer() when + Map :: map(). + +size(Map) -> + erlang:map_size(Map). + +-spec without(Ks,Map1) -> Map2 when + Ks :: [K], + Map1 :: map(), + Map2 :: map(), + K :: term(). + +without(Ks, M) -> + maps:from_list([{K,V}||{K,V} <- maps:to_list(M), not lists:member(K, Ks)]). diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src index 9a77ae9d66..a64b8e13c0 100644 --- a/lib/stdlib/src/stdlib.app.src +++ b/lib/stdlib/src/stdlib.app.src @@ -71,7 +71,7 @@ lib, lists, log_mf_h, - map, + maps, math, ms_transform, orddict, -- cgit v1.2.3 From 94963032a2bb7bd5bfe5ea05d99ca507e67e7ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 6 Nov 2013 11:56:58 +0100 Subject: stdlib: Remove bogus map() type --- lib/stdlib/src/maps.erl | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl index 218dc28bec..59ac80b46c 100644 --- a/lib/stdlib/src/maps.erl +++ b/lib/stdlib/src/maps.erl @@ -44,8 +44,6 @@ values/1 ]). --type map() :: term(). %% FIXME: remove when erl_bif_types knows map(). - %% Shadowed by erl_bif_types: maps:get/3 -spec get(Key,Map) -> Value when Key :: term(), -- cgit v1.2.3 From 5dda9e038891500a0849a3bf4d1079a355cdd30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 24 Oct 2013 18:00:57 +0200 Subject: stdlib: Pretty print maps Pretty printing behaviour mimic records. This commit requires Map enabled bootstrap compiler. --- lib/stdlib/src/io_lib_pretty.erl | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl index 7637ad7a3d..f02a7921f8 100644 --- a/lib/stdlib/src/io_lib_pretty.erl +++ b/lib/stdlib/src/io_lib_pretty.erl @@ -101,6 +101,7 @@ print(Term, Col, Ll, D, M, RecDefFun, Enc, Str) when Col =< 0 -> print(Term, 1, Ll, D, M, RecDefFun, Enc, Str); print(Term, Col, Ll, D, M0, RecDefFun, Enc, Str) when is_tuple(Term); is_list(Term); + is_map(Term); is_bitstring(Term) -> If = {_S, Len} = print_length(Term, D, RecDefFun, Enc, Str), M = max_cs(M0, Len), @@ -137,6 +138,10 @@ pp({{tuple,true,L}, _Len}, Col, Ll, M, TInd, Ind, LD, W) -> [${, pp_tag_tuple(L, Col, Ll, M, TInd, Ind, LD, W + 1), $}]; pp({{tuple,false,L}, _Len}, Col, Ll, M, TInd, Ind, LD, W) -> [${, pp_list(L, Col + 1, Ll, M, TInd, indent(1, Ind), LD, $,, W + 1), $}]; +pp({{map,Pairs},_Len}, Col, Ll, M, TInd, Ind, LD, W) -> + [$#,${, pp_list(Pairs, Col + 2, Ll, M, TInd, indent(2, Ind), LD, $,, W + 1), $}]; +pp({{map_pair,K,V},_Len}, Col, Ll, M, TInd, Ind, LD, W) -> + [pp(K, Col, Ll, M, TInd, Ind, LD, W), " => ", pp(V, Col, Ll, M, TInd, Ind, LD, W)]; pp({{record,[{Name,NLen} | L]}, _Len}, Col, Ll, M, TInd, Ind, LD, W) -> [Name, ${, pp_record(L, NLen, Col, Ll, M, TInd, Ind, LD, W + NLen+1), $}]; pp({{bin,S}, _Len}, Col, Ll, M, _TInd, Ind, LD, W) -> @@ -283,6 +288,10 @@ write({{tuple, _IsTagged, L}, _}) -> [${, write_list(L, $,), $}]; write({{list, L}, _}) -> [$[, write_list(L, $|), $]]; +write({{map, Pairs}, _}) -> + [$#,${, write_list(Pairs, $,), $}]; +write({{map_pair, K, V}, _}) -> + [write(K)," => ",write(V)]; write({{record, [{Name,_} | L]}, _}) -> [Name, ${, write_fields(L), $}]; write({{bin, S}, _}) -> @@ -331,6 +340,8 @@ print_length([], _D, _RF, _Enc, _Str) -> {"[]", 2}; print_length({}, _D, _RF, _Enc, _Str) -> {"{}", 2}; +print_length(#{}=M, _D, _RF, _Enc, _Str) when map_size(M) =:= 0 -> + {"#{}", 3}; print_length(List, D, RF, Enc, Str) when is_list(List) -> case Str andalso printable_list(List, D, Enc) of true -> @@ -356,6 +367,8 @@ print_length(R, D, RF, Enc, Str) when is_atom(element(1, R)), end; print_length(Tuple, D, RF, Enc, Str) when is_tuple(Tuple) -> print_length_tuple(Tuple, D, RF, Enc, Str); +print_length(Map, D, RF, Enc, Str) when is_map(Map) -> + print_length_map(Map, D, RF, Enc, Str); print_length(<<>>, _D, _RF, _Enc, _Str) -> {"<<>>", 4}; print_length(<<_/bitstring>>, 1, _RF, _Enc, _Str) -> @@ -389,6 +402,25 @@ print_length(Term, _D, _RF, _Enc, _Str) -> S = io_lib:write(Term), {S, lists:flatlength(S)}. +print_length_map(_Map, 1, _RF, _Enc, _Str) -> + {"#{...}", 6}; +print_length_map(Map, D, RF, Enc, Str) when is_map(Map) -> + Pairs = print_length_map_pairs(maps:to_list(Map), D, RF, Enc, Str), + {{map, Pairs}, list_length(Pairs, 3)}. + +print_length_map_pairs([], _D, _RF, _Enc, _Str) -> + []; +print_length_map_pairs(_Pairs, 1, _RF, _Enc, _Str) -> + {dots, 3}; +print_length_map_pairs([{K,V}|Pairs], D, RF, Enc, Str) -> + [print_length_map_pair(K,V,D-1,RF,Enc,Str) | + print_length_map_pairs(Pairs,D-1,RF,Enc,Str)]. + +print_length_map_pair(K, V, D, RF, Enc, Str) -> + {KS, KL} = print_length(K, D, RF, Enc, Str), + {VS, VL} = print_length(V, D, RF, Enc, Str), + {{map_pair, {KS,KL}, {VS,VL}}, KL + VL}. + print_length_tuple(_Tuple, 1, _RF, _Enc, _Str) -> {"{...}", 5}; print_length_tuple(Tuple, D, RF, Enc, Str) -> -- cgit v1.2.3 From 1a234c9eba8ac2c78f97e5f3e33521b8cc5d3748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 24 Oct 2013 18:13:31 +0200 Subject: stdlib: Strengthen Map module with guards This commit requires Map enabled bootstrap compiler. --- lib/stdlib/src/maps.erl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl index 59ac80b46c..0e6a1ddb1a 100644 --- a/lib/stdlib/src/maps.erl +++ b/lib/stdlib/src/maps.erl @@ -164,7 +164,7 @@ values(_) -> erlang:nif_error(undef). K :: term(), V :: term(). -foldl(Fun, Init, Map) -> +foldl(Fun, Init, Map) when is_function(Fun,3), is_map(Map) -> lists:foldl(fun({K,V},A) -> Fun(K,V,A) end,Init,maps:to_list(Map)). -spec foldr(Fun,Init,Map) -> Acc when @@ -177,7 +177,7 @@ foldl(Fun, Init, Map) -> K :: term(), V :: term(). -foldr(Fun, Init, Map) -> +foldr(Fun, Init, Map) when is_function(Fun,3), is_map(Map) -> lists:foldr(fun({K,V},A) -> Fun(K,V,A) end,Init,maps:to_list(Map)). @@ -189,7 +189,7 @@ foldr(Fun, Init, Map) -> V1 :: term(), V2 :: term(). -map(Fun, Map) -> +map(Fun, Map) when is_function(Fun, 2), is_map(Map) -> maps:from_list(lists:map(fun ({K,V}) -> {K,Fun(K,V)} @@ -199,14 +199,15 @@ map(Fun, Map) -> -spec size(Map) -> non_neg_integer() when Map :: map(). -size(Map) -> +size(Map) when is_map(Map) -> erlang:map_size(Map). + -spec without(Ks,Map1) -> Map2 when Ks :: [K], Map1 :: map(), Map2 :: map(), K :: term(). -without(Ks, M) -> +without(Ks, M) when is_list(Ks), is_map(M) -> maps:from_list([{K,V}||{K,V} <- maps:to_list(M), not lists:member(K, Ks)]). -- cgit v1.2.3 From 335e6bf3e4987e5f549136c1f692c628b1dfc360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Mon, 27 Jan 2014 16:00:34 +0100 Subject: stdlib: Make maps:fold/3 order-independent This means replacing maps:foldl/3 and maps:foldr/3 with maps:fold/3. --- lib/stdlib/src/maps.erl | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) (limited to 'lib/stdlib') diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl index 0e6a1ddb1a..41de174e7d 100644 --- a/lib/stdlib/src/maps.erl +++ b/lib/stdlib/src/maps.erl @@ -20,8 +20,7 @@ -module(maps). -export([ - foldl/3, - foldr/3, + fold/3, map/2, size/1, without/2 @@ -154,7 +153,7 @@ values(_) -> erlang:nif_error(undef). %%% End of BIFs --spec foldl(Fun,Init,Map) -> Acc when +-spec fold(Fun,Init,Map) -> Acc when Fun :: fun((K, V, AccIn) -> AccOut), Init :: term(), Acc :: term(), @@ -164,23 +163,9 @@ values(_) -> erlang:nif_error(undef). K :: term(), V :: term(). -foldl(Fun, Init, Map) when is_function(Fun,3), is_map(Map) -> +fold(Fun, Init, Map) when is_function(Fun,3), is_map(Map) -> lists:foldl(fun({K,V},A) -> Fun(K,V,A) end,Init,maps:to_list(Map)). --spec foldr(Fun,Init,Map) -> Acc when - Fun :: fun((K,V,AccIn) -> AccOut), - Init :: term(), - Acc :: term(), - AccIn :: term(), - AccOut :: term(), - Map :: map(), - K :: term(), - V :: term(). - -foldr(Fun, Init, Map) when is_function(Fun,3), is_map(Map) -> - lists:foldr(fun({K,V},A) -> Fun(K,V,A) end,Init,maps:to_list(Map)). - - -spec map(Fun,Map1) -> Map2 when Fun :: fun((K, V1) -> V2), Map1 :: map(), -- cgit v1.2.3