From f1e687312daa91591a2cee5038a2d9434e7db209 Mon Sep 17 00:00:00 2001
From: Hans Bolinder Examples where Notice that when calling a local function, there is a difference
between using the implicitly or fully qualified function name.
@@ -1004,7 +1004,7 @@ M4 = M3#{a := 2, b := 3}. % 'a' and 'b' was added in `M1` and `M2`.
A This is if it is used in the context of the matching operator
+ This is if it is used in the context of the match operator
as in the example. Or resulting in the next clause being tested in function heads and
@@ -1085,7 +1085,7 @@ Ei = Value |
Used in a bit string construction,
-Fun1 = fun(X) -> X+1 end
-Fun1(3)
-=> 4
-
-fun lists:append/2([1,2], [3,4])
-=> [1,2,3,4]
+
+1> Fun1 = fun(X) -> X+1 end,
+Fun1(3).
+4
+2> fun lists:append/2([1,2], [3,4]).
+[1,2,3,4]
+3>
Used in a bit string matching,
Notice that
3> A = catch 1+2. ** 1: syntax error before: 'catch' ** -- cgit v1.2.3 From 3bd648f66080d1074533ba18fece0ea7de568d45 Mon Sep 17 00:00:00 2001 From: Hans BolinderDate: Thu, 17 Dec 2015 12:09:24 +0100 Subject: dialyzer: Improve a type --- lib/dialyzer/src/dialyzer_utils.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl index 7fe982a992..557e10eed7 100644 --- a/lib/dialyzer/src/dialyzer_utils.erl +++ b/lib/dialyzer/src/dialyzer_utils.erl @@ -83,7 +83,7 @@ print_types1([{record, _Name} = Key|T], RecDict) -> %% ---------------------------------------------------------------------------- --type abstract_code() :: [tuple()]. %% XXX: import from somewhere +-type abstract_code() :: [erl_parse:abstract_form()]. -type comp_options() :: [compile:option()]. -type mod_or_fname() :: module() | file:filename(). -type fa() :: {atom(), arity()}. -- cgit v1.2.3 From 034e28c340d38a34c0e00590321380c407ff5faf Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 17 Dec 2015 12:29:51 +0100 Subject: hipe: Improve types --- lib/hipe/cerl/erl_types.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 67cdcd35e3..69654088d5 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -316,7 +316,7 @@ %% Auxiliary types and convenient macros %% --type parse_form() :: {atom(), _, _} | {atom(), _, _, _} | {'op', _, _, _, _}. %% XXX: Temporarily +-type parse_form() :: erl_parse:abstract_expr(). -type rng_elem() :: 'pos_inf' | 'neg_inf' | integer(). -record(int_set, {set :: [integer()]}). @@ -365,8 +365,8 @@ -type type_key() :: {'type' | 'opaque', atom(), arity()}. -type record_value() :: [{atom(), erl_parse:abstract_expr(), erl_type()}]. -type type_value() :: {module(), erl_type(), atom()}. --type type_table() :: dict:dict(record_key(), record_value()) - | dict:dict(type_key(), type_value()). +-type type_table() :: dict:dict(record_key() | type_key(), + record_value() | type_value()). -type var_table() :: dict:dict(atom(), erl_type()). -- cgit v1.2.3 From 130eb1e9f3af384f13c38e93365c5917f25fd798 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 17 Dec 2015 15:49:33 +0100 Subject: compiler: Improve type and specs --- lib/compiler/src/compile.erl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index b61c104b3c..72f1a767ed 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -40,6 +40,8 @@ %%---------------------------------------------------------------------- +-type abstract_code() :: [erl_parse:abstract_form()]. + -type option() :: atom() | {atom(), term()} | {'d', atom(), term()}. -type err_info() :: {erl_anno:line() | 'none', @@ -48,6 +50,9 @@ -type warnings() :: [{file:filename(), [err_info()]}]. -type mod_ret() :: {'ok', module()} | {'ok', module(), cerl:c_module()} %% with option 'to_core' + | {'ok', %% with option 'to_pp' + module() | [], %% module() if 'to_exp' + abstract_code()} | {'ok', module(), warnings()}. -type bin_ret() :: {'ok', module(), binary()} | {'ok', module(), binary(), warnings()}. @@ -78,7 +83,11 @@ file(File, Opts) when is_list(Opts) -> file(File, Opt) -> file(File, [Opt|?DEFAULT_OPTIONS]). -forms(File) -> forms(File, ?DEFAULT_OPTIONS). +-spec forms(abstract_code()) -> comp_ret(). + +forms(Forms) -> forms(Forms, ?DEFAULT_OPTIONS). + +-spec forms(abstract_code(), [option()] | option()) -> comp_ret(). forms(Forms, Opts) when is_list(Opts) -> do_compile({forms,Forms}, [binary|Opts++env_default_opts()]); @@ -106,6 +115,8 @@ noenv_file(File, Opts) when is_list(Opts) -> noenv_file(File, Opt) -> noenv_file(File, [Opt|?DEFAULT_OPTIONS]). +-spec noenv_forms(abstract_code(), [option()] | option()) -> comp_ret(). + noenv_forms(Forms, Opts) when is_list(Opts) -> do_compile({forms,Forms}, [binary|Opts]); noenv_forms(Forms, Opt) when is_atom(Opt) -> -- cgit v1.2.3 From c92ec9ea35209d443c2fb6393a1610f94ffccc1c Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 17 Dec 2015 12:40:43 +0100 Subject: stdlib: Refine the types of the abstract format --- lib/stdlib/src/erl_parse.yrl | 414 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 410 insertions(+), 4 deletions(-) diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index e07ab2efc2..a525c2ae82 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -527,12 +527,418 @@ Erlang code. -compile([{hipe,[{regalloc,linear_scan}]}]). -export_type([abstract_clause/0, abstract_expr/0, abstract_form/0, - error_info/0]). + abstract_type/0, error_info/0]). + +%% Start of Abstract Format + +-type anno() :: erl_anno:anno(). + +-type abstract_form() :: af_module() + | af_behavior() + | af_behaviour() + | af_export() + | af_import() + | af_export_type() + | af_optional_callbacks() + | af_compile() + | af_file() + | af_record_decl() + | af_type_decl() + | af_function_spec() + | af_wild_attribute() + | af_function_decl(). + +-type af_module() :: {'attribute', anno(), 'module', module()}. + +-type af_behavior() :: {'attribute', anno(), 'behavior', behaviour()}. + +-type af_behaviour() :: {'attribute', anno(), 'behaviour', behaviour()}. + +-type behaviour() :: atom(). + +-type af_export() :: {'attribute', anno(), 'export', af_fa_list()}. + +-type af_import() :: {'attribute', anno(), 'import', af_fa_list()}. + +-type af_fa_list() :: [{function_name(), arity()}]. + +-type af_export_type() :: {'attribute', anno(), 'export_type', af_ta_list()}. + +-type af_ta_list() :: [{type_name(), arity()}]. + +-type af_optional_callbacks() :: + {'attribute', anno(), 'optional_callbacks', af_fa_list()}. + +-type af_compile() :: {'attribute', anno(), 'compile', any()}. + +-type af_file() :: {'attribute', anno(), 'file', {string(), anno()}}. + +-type af_record_decl() :: + {'attribute', anno(), 'record', {record_name(), [af_field_decl()]}}. + +-type af_field_decl() :: af_typed_field() | af_field(). + +-type af_typed_field() :: + {'typed_record_field', af_field(), abstract_type()}. + +-type af_field() :: {'record_field', anno(), af_field_name()} + | {'record_field', anno(), af_field_name(), abstract_expr()}. + +-type af_type_decl() :: {'attribute', anno(), type_attr(), + {type_name(), abstract_type(), [af_variable()]}}. + +-type type_attr() :: 'opaque' | 'type'. + +-type af_function_spec() :: {'attribute', anno(), spec_attr(), + {{function_name(), arity()}, + af_function_type_list()}} + | {'attribute', anno(), 'spec', + {{module(), function_name(), arity()}, + af_function_type_list()}}. + +-type spec_attr() :: 'callback' | 'spec'. + +-type af_wild_attribute() :: {'attribute', anno(), atom(), any()}. + +-type af_function_decl() :: + {'function', anno(), function_name(), arity(), af_clause_seq()}. + +-type abstract_expr() :: af_literal() + | af_match(abstract_expr()) + | af_variable() + | af_tuple(abstract_expr()) + | af_nil() + | af_cons(abstract_expr()) + | af_bin(abstract_expr()) + | af_binary_op(abstract_expr()) + | af_unary_op(abstract_expr()) + | af_record_access(abstract_expr()) + | af_record_update(abstract_expr()) + | af_record_index() + | af_record_field_access(abstract_expr()) + | af_map_access(abstract_expr()) + | af_map_update(abstract_expr()) + | af_catch() + | af_local_call() + | af_remote_call() + | af_list_comprehension() + | af_binary_comprehension() + | af_block() + | af_if() + | af_case() + | af_try() + | af_receive() + | af_local_fun() + | af_remote_fun() + | af_fun() + | af_named_fun(). + +-type af_record_update(T) :: {'record', + anno(), + abstract_expr(), + record_name(), + [af_record_field(T)]}. + +-type af_catch() :: {'catch', anno(), abstract_expr()}. + +-type af_local_call() :: {'call', anno(), af_local_function(), af_args()}. + +-type af_remote_call() :: {'call', anno(), af_remote_function(), af_args()}. + +-type af_args() :: [abstract_expr()]. + +-type af_local_function() :: abstract_expr(). + +-type af_remote_function() :: + {'remote', anno(), abstract_expr(), abstract_expr()}. + +-type af_list_comprehension() :: + {'lc', anno(), af_template(), af_qualifier_seq()}. + +-type af_binary_comprehension() :: + {'bc', anno(), af_template(), af_qualifier_seq()}. + +-type af_template() :: abstract_expr(). + +-type af_qualifier_seq() :: [af_qualifier()]. + +-type af_qualifier() :: af_generator() | af_filter(). + +-type af_generator() :: {'generate', anno(), af_pattern(), abstract_expr()} + | {'b_generate', anno(), af_pattern(), abstract_expr()}. + +-type af_filter() :: abstract_expr(). + +-type af_block() :: {'block', anno(), af_body()}. + +-type af_if() :: {'if', anno(), af_clause_seq()}. + +-type af_case() :: {'case', anno(), abstract_expr(), af_clause_seq()}. + +-type af_try() :: {'try', + anno(), + af_body() | [], + af_clause_seq() | [], + af_clause_seq() | [], + af_body() | []}. + +-type af_clause_seq() :: [af_clause(), ...]. + +-type af_receive() :: + {'receive', anno(), af_clause_seq()} + | {'receive', anno(), af_clause_seq(), abstract_expr(), af_body()}. + +-type af_local_fun() :: + {'fun', anno(), {'function', function_name(), arity()}}. + +-type af_remote_fun() :: + {'fun', anno(), {'function', module(), function_name(), arity()}} + | {'fun', anno(), {'function', af_atom(), af_atom(), af_integer()}}. + +-type af_fun() :: {'fun', anno(), {'clauses', af_clause_seq()}}. + +-type af_named_fun() :: {'named_fun', anno(), fun_name(), af_clause_seq()}. + +-type fun_name() :: atom(). + +-type abstract_clause() :: af_clause(). + +-type af_clause() :: + {'clause', anno(), [af_pattern()], af_guard_seq(), af_body()}. + +-type af_body() :: [abstract_expr(), ...]. + +-type af_guard_seq() :: [af_guard()]. + +-type af_guard() :: [af_guard_test(), ...]. + +-type af_guard_test() :: af_literal() + | af_variable() + | af_tuple(af_guard_test()) + | af_nil() + | af_cons(af_guard_test()) + | af_bin(af_guard_test()) + | af_binary_op(af_guard_test()) + | af_unary_op(af_guard_test()) + | af_record_access(af_guard_test()) + | af_record_index() + | af_record_field_access(af_guard_test()) + | af_map_access(abstract_expr()) % FIXME + | af_map_update(abstract_expr()) % FIXME + | af_guard_call() + | af_remote_guard_call(). + +-type af_record_field_access(T) :: + {'record_field', anno(), T, record_name(), af_field_name()}. + +-type af_map_access(T) :: {'map', anno(), [af_map_field(T)]}. + +-type af_map_update(T) :: {'map', anno(), T, [af_map_field(T)]}. + +-type af_map_field(T) :: af_map_field_assoc(T) | af_map_field_exact(T). + +-type af_map_field_assoc(T) :: {'map_field_assoc', anno(), T, T}. + +-type af_map_field_exact(T) :: {'map_field_exact', anno(), T, T}. + +-type af_guard_call() :: {'call', anno(), function_name(), [af_guard_test()]}. + +-type af_remote_guard_call() :: + {'call', anno(), + {'remote', anno(), af_lit_atom('erlang'), af_atom()}, + [af_guard_test()]}. + +-type af_pattern() :: af_literal() + | af_match(af_pattern()) + | af_variable() + | af_tuple(af_pattern()) + | af_nil() + | af_cons(af_pattern()) + | af_bin(af_pattern()) + | af_binary_op(af_pattern()) + | af_unary_op(af_pattern()) + | af_record_access(af_pattern()) + | af_record_index() + | af_map_pattern(). + +-type af_record_index() :: + {'record_index', anno(), record_name(), af_field_name()}. + +-type af_record_access(T) :: + {'record', anno(), record_name(), [af_record_field(T)]}. + +-type af_record_field(T) :: {'record_field', anno(), af_field_name(), T}. + +-type af_map_pattern() :: + {'map', anno(), [af_map_field_exact(abstract_expr)]}. % FIXME? + +-type abstract_type() :: af_annotated_type() + | af_atom() + | af_bitstring_type() + | af_empty_list_type() + | af_fun_type() + | af_integer_range_type() + | af_map_type() + | af_predefined_type() + | af_record_type() + | af_remote_type() + | af_singleton_integer_type() + | af_tuple_type() + | af_type_union() + | af_type_variable() + | af_user_defined_type(). + +-type af_annotated_type() :: + {'ann_type', anno(), [af_anno() | abstract_type()]}. % [Var, Type] + +-type af_anno() :: af_variable(). + +-type af_bitstring_type() :: + {'type', anno(), 'binary', [af_singleton_integer_type()]}. + +-type af_empty_list_type() :: {'type', anno(), 'nil', []}. + +-type af_fun_type() :: {'type', anno(), 'fun', []} + | {'type', anno(), 'fun', [{'type', anno(), 'any'} | + abstract_type()]} + | {'type', anno(), 'fun', af_function_type()}. + +-type af_integer_range_type() :: + {'type', anno(), 'range', [af_singleton_integer_type()]}. + +-type af_map_type() :: {'type', anno(), 'map', 'any'} + | {'type', anno(), 'map', [af_map_pair_type()]}. + +-type af_map_pair_type() :: + {'type', anno(), 'map_field_assoc', [abstract_type()]}. + +-type af_predefined_type() :: + {'type', anno(), type_name(), [abstract_type()]}. + +-type af_record_type() :: + {'type', anno(), 'record', [(Name :: af_atom()) % [Name, T1, ... Tk] + | af_record_field_type()]}. + +-type af_record_field_type() :: + {'type', anno(), 'field_type', [(Name :: af_atom()) | + abstract_type()]}. % [Name, Type] + +-type af_remote_type() :: + {'remote_type', anno(), [(Module :: af_atom()) | + (TypeName :: af_atom()) | + [abstract_type()]]}. % [Module, Name, [T]] + +-type af_tuple_type() :: {'type', anno(), 'tuple', 'any'} + | {'type', anno(), 'tuple', [abstract_type()]}. + +-type af_type_union() :: {'type', anno(), 'union', [abstract_type()]}. + +-type af_type_variable() :: {'var', anno(), atom()}. % except '_' + +-type af_user_defined_type() :: + {'user_type', anno(), type_name(), [abstract_type()]}. + +-type af_function_type_list() :: [af_constrained_function_type() | + af_function_type()]. + +-type af_constrained_function_type() :: + {'type', anno(), 'bounded_fun', [af_function_type() | % [Ft, Fc] + af_function_constraint()]}. + +-type af_function_type() :: + {'type', anno(), 'fun', + [{'type', anno(), 'product', [abstract_type()]} | abstract_type()]}. + +-type af_function_constraint() :: [af_constraint()]. + +-type af_constraint() :: {'type', anno(), 'constraint', + af_lit_atom('is_subtype'), + [af_type_variable() | abstract_type()]}. % [V, T] + +-type af_singleton_integer_type() :: af_integer() + | af_unary_op(af_singleton_integer_type()) + | af_binary_op(af_singleton_integer_type()). + +-type af_literal() :: af_atom() | af_integer() | af_float() | af_string(). + +-type af_atom() :: af_lit_atom(atom()). + +-type af_lit_atom(A) :: {'atom', anno(), A}. + +-type af_integer() :: {'integer', anno(), non_neg_integer()}. + +-type af_float() :: {'float', anno(), float()}. + +-type af_string() :: {'string', anno(), string()}. + +-type af_match(T) :: {'match', anno(), af_pattern(), T}. + +-type af_variable() :: {'var', anno(), atom()}. % | af_anon_variable() + +%-type af_anon_variable() :: {'var', anno(), '_'}. + +-type af_tuple(T) :: {'tuple', anno(), [T]}. + +-type af_nil() :: {'nil', anno()}. + +-type af_cons(T) :: {'cons', anno(), T, T}. + +-type af_bin(T) :: {'bin', anno(), [af_binelement(T)]}. + +-type af_binelement(T) :: {'bin_element', + anno(), + T, + af_binelement_size(), + type_specifier_list()}. + +-type af_binelement_size() :: 'default' | abstract_expr(). + +-type af_binary_op(T) :: {'op', anno(), binary_op(), T, T}. + +-type binary_op() :: '/' | '*' | 'div' | 'rem' | 'band' | 'and' | '+' | '-' + | 'bor' | 'bxor' | 'bsl' | 'bsr' | 'or' | 'xor' | '++' + | '--' | '==' | '/=' | '=<' | '<' | '>=' | '>' | '=:=' + | '=/='. + +-type af_unary_op(T) :: {'op', anno(), unary_op(), T}. + +-type unary_op() :: '+' | '*' | 'bnot' | 'not'. + +%% See also lib/stdlib/{src/erl_bits.erl,include/erl_bits.hrl}. +-type type_specifier_list() :: 'default' | [type_specifier(), ...]. + +-type type_specifier() :: type() + | signedness() + | endianness() + | unit(). + +-type type() :: 'integer' + | 'float' + | 'binary' + | 'bytes' + | 'bitstring' + | 'bits' + | 'utf8' + | 'utf16' + | 'utf32'. + +-type signedness() :: 'signed' | 'unsigned'. + +-type endianness() :: 'big' | 'little' | 'native'. + +-type unit() :: {'unit', 1..256}. + +-type record_name() :: atom(). + +-type af_field_name() :: af_atom(). + +-type function_name() :: atom(). + +-type type_name() :: atom(). + +%% End of Abstract Format %% XXX. To be refined. --type abstract_clause() :: term(). --type abstract_expr() :: term(). --type abstract_form() :: term(). -type error_description() :: term(). -type error_info() :: {erl_anno:line(), module(), error_description()}. -type token() :: erl_scan:token(). -- cgit v1.2.3 From b21f71c1bb79d3979505ad6ad1e496472b38c6b9 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 17 Dec 2015 12:41:44 +0100 Subject: stdlib: Update erl_parse(3) Calls to map_anno(), fold_anno(), and mapfold_anno() with lists of erl_parse trees have been replaced. Those functions accept lists of erl_parse trees, but it was not the intention when the functions were introduced, and it is not documented. --- lib/stdlib/doc/src/erl_parse.xml | 120 ++++++++++++++++++++++++--------------- lib/stdlib/src/erl_lint.erl | 5 ++ lib/stdlib/src/erl_parse.yrl | 25 ++++---- lib/stdlib/src/qlc_pt.erl | 34 ++++++----- 4 files changed, 114 insertions(+), 70 deletions(-) diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml index 0938b5dec3..13be488c33 100644 --- a/lib/stdlib/doc/src/erl_parse.xml +++ b/lib/stdlib/doc/src/erl_parse.xml @@ -4,7 +4,7 @@ - 1996 2015 +1996 2016 Ericsson AB. All Rights Reserved. @@ -44,20 +44,32 @@ - - Parse tree for Erlang clause.
+abstract_clause() +
+ Abstract form of an Erlang clause. - - Parse tree for Erlang expression.
+abstract_expr() +
+ Abstract form of an Erlang expression. - +- Parse tree for Erlang form.
+abstract_form() +
+ Abstract form of an Erlang form. + +abstract_type() ++ +
+ Abstract form of an Erlang type. + + @@ -180,7 +192,7 @@ Converts the Erlang data structure
into an abstract form of type Data . AbsTerm The
+ be assigned to each node ofoption is the line that will - be assigned to each node of the abstract form. Line . AbsTerm The
option is used for selecting which integer lists will be considered as strings. The default is to use the encoding returned by @@ -196,47 +208,53 @@ Encoding - Map a function over the annotations of an abstract form + Map a function over the annotations of a erl_parse tree- Modifies the abstract form
Abstr by applying -Fun on every collection of annotations of the - abstract form. The abstract form is traversed in a - depth-first, left-to-right, fashion. +Modifies the
erl_parse tree+ by applying Abstr on each collection of + annotations of the nodes of the Fun erl_parse tree. The +erl_parse tree is traversed in a depth-first, + left-to-right, fashion.- Fold a function over the annotations of an abstract form + Fold a function over the annotations of a erl_parse tree- Updates an accumulator by applying
Fun on - every collection of annotations of the abstract form -Abstr . The first call toFun has -AccIn as argument, and the returned accumulator -AccOut is passed to the next call, and so on. - The final value of the accumulator is returned. The abstract - form is traversed in a depth-first, left-to-right, fashion. +Updates an accumulator by applying
on + each collection of annotations of the Fun erl_parse tree +. The first call to + Abstr has Fun as + argument, and the returned accumulator + AccIn is passed to the next call, and + so on. The final value of the accumulator is returned. The + AccOut erl_parse tree is traversed in a depth-first, left-to-right, + fashion.@@ -246,12 +264,15 @@ Create new annotations - Map and fold a function over the annotations of an abstract form + Map and fold a function over the annotations of a + erl_parse tree- Modifies the abstract form
Abstr by applying -Fun on every collection of annotations of the - abstract form, while at the same time updating an - accumulator. The first call toFun has -AccIn as second argument, and the returned - accumulatorAccOut is passed to the next call, - and so on. The modified abstract form as well as the the - final value of the accumulator is returned. The abstract - form is traversed in a depth-first, left-to-right, fashion. +Modifies the
erl_parse tree+ by applying Abstr on each collection of + annotations of the nodes of the Fun erl_parse tree, while + at the same time updating an accumulator. The first call to +has Fun as + second argument, and the returned accumulator + AccIn is passed to the next call, and + so on. The modified AccOut erl_parse tree as well as the the + final value of the accumulator are returned. The +erl_parse tree is traversed in a depth-first, + left-to-right, fashion.- @@ -261,12 +282,14 @@ Return annotations as termsCreates an abstract form from a term which has the same - structure as an abstract form, but
locations where the - abstract form has annotations. For each location,is - called, and the annotations replace the location. + erl_anno:new/1 Assumes that
is a term with the same + structure as a Term erl_parse tree, but withlocations where a +erl_parse tree has collections of annotations. + Returns aerl_parse tree where each locationL + has been replaced by the value returned by. + The term erl_anno:new(L) is traversed in a + depth-first, left-to-right, fashion. Term - @@ -277,10 +300,13 @@ Return the representation of annotationsAssumes that
Term is a term with the same - structure as an abstract form, but with terms, T say, on - those places where an abstract form has annotations. Returns - an abstract form where every term T has been replaced by the - value returned by callingerl_anno:from_term(T) . The - termTerm is traversed in a depth-first, +Assumes that
is a term with the same + structure as a Term erl_parse tree, but with terms, +T say, where aerl_parse tree has collections + of annotations. Returns aerl_parse tree where each + termT has been replaced by the value returned by ++ . The term +erl_anno:from_term(T) is traversed in a depth-first, left-to-right, fashion. Term - diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 4a42754d92..9ef4acdf5f 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -696,7 +696,12 @@ set_form_file({function,L,N,A,C}, File) -> set_form_file(Form, _File) -> Form. +set_file(Ts, File) when is_list(Ts) -> + [anno_set_file(T, File) || T <- Ts]; set_file(T, File) -> + anno_set_file(T, File). + +anno_set_file(T, File) -> F = fun(Anno) -> erl_anno:set_file(File, Anno) end, erl_parse:map_anno(F, T). diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl index a525c2ae82..b1c574ea60 100644 --- a/lib/stdlib/src/erl_parse.yrl +++ b/lib/stdlib/src/erl_parse.yrl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2015. All Rights Reserved. +%% Copyright Ericsson AB 1996-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -1489,11 +1489,16 @@ type_preop_prec('-') -> {600,700}; type_preop_prec('bnot') -> {600,700}; type_preop_prec('#') -> {700,800}. +-type erl_parse_tree() :: abstract_clause() + | abstract_expr() + | abstract_form() + | abstract_type(). + -spec map_anno(Fun, Abstr) -> NewAbstr when Fun :: fun((Anno) -> Anno), Anno :: erl_anno:anno(), - Abstr :: abstract_form() | abstract_expr(), - NewAbstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(), + NewAbstr :: erl_parse_tree(). map_anno(F0, Abstr) -> F = fun(A, Acc) -> {F0(A), Acc} end, @@ -1506,8 +1511,8 @@ map_anno(F0, Abstr) -> Acc0 :: term(), AccIn :: term(), AccOut :: term(), - Abstr :: abstract_form() | abstract_expr(), - NewAbstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(), + NewAbstr :: erl_parse_tree(). fold_anno(F0, Acc0, Abstr) -> F = fun(A, Acc) -> {A, F0(A, Acc)} end, @@ -1521,26 +1526,26 @@ fold_anno(F0, Acc0, Abstr) -> Acc1 :: term(), AccIn :: term(), AccOut :: term(), - Abstr :: abstract_form() | abstract_expr(), - NewAbstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(), + NewAbstr :: erl_parse_tree(). mapfold_anno(F, Acc0, Abstr) -> modify_anno1(Abstr, Acc0, F). -spec new_anno(Term) -> Abstr when Term :: term(), - Abstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(). new_anno(Term) -> map_anno(fun erl_anno:new/1, Term). -spec anno_to_term(Abstr) -> term() when - Abstr :: abstract_form() | abstract_expr(). + Abstr :: erl_parse_tree(). anno_to_term(Abstract) -> map_anno(fun erl_anno:to_term/1, Abstract). --spec anno_from_term(Term) -> abstract_form() | abstract_expr() when +-spec anno_from_term(Term) -> erl_parse_tree() when Term :: term(). anno_from_term(Term) -> diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index 9577d17a85..9f69cd5003 100644 --- a/lib/stdlib/src/qlc_pt.erl +++ b/lib/stdlib/src/qlc_pt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2015. All Rights Reserved. +%% Copyright Ericsson AB 2004-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -200,7 +200,7 @@ exclude_integers_from_unique_line_numbers(Forms, NodeInfo) -> find_integers(Forms) -> F = fun(A) -> - Fs1 = erl_parse:map_anno(fun(_) -> A end, Forms), + Fs1 = map_anno(fun(_) -> A end, Forms), ordsets:from_list(integers(Fs1, [])) end, ordsets:to_list(ordsets:intersection(F(anno0()), F(anno1()))). @@ -319,13 +319,13 @@ badarg(Forms, State) -> E0. lc_nodes(E, NodeInfo) -> - erl_parse:map_anno(fun(Anno) -> - N = erl_anno:line(Anno), - [{N, Data}] = ets:lookup(NodeInfo, N), - NData = Data#{inside_lc => true}, - true = ets:insert(NodeInfo, {N, NData}), - Anno - end, E). + map_anno(fun(Anno) -> + N = erl_anno:line(Anno), + [{N, Data}] = ets:lookup(NodeInfo, N), + NData = Data#{inside_lc => true}, + true = ets:insert(NodeInfo, {N, NData}), + Anno + end, E). used_genvar_messages(MsL, S) -> [{File,[{Loc,?APIMOD,{used_generator_variable,V}}]} @@ -416,7 +416,7 @@ intro_anno(LC, Where, QId, NodeInfo) -> true = ets:insert(NodeInfo, {Location,Data}), Anno end, - erl_parse:map_anno(Fun, save_anno(LC, NodeInfo)). + map_anno(Fun, save_anno(LC, NodeInfo)). compile_errors(FormsNoShadows) -> case compile_forms(FormsNoShadows, []) of @@ -1650,7 +1650,7 @@ reset_anno(T) -> set_anno(T, anno0()). set_anno(T, A) -> - erl_parse:map_anno(fun(_L) -> A end, T). + map_anno(fun(_L) -> A end, T). -record(fstate, {state, bind_fun, imported}). @@ -2609,7 +2609,7 @@ save_anno(Abstr, NodeInfo) -> true = ets:insert(NodeInfo, Data), erl_anno:new(N) end, - erl_parse:map_anno(F, Abstr). + map_anno(F, Abstr). next_slot(T) -> I = ets:update_counter(T, var_n, 1), @@ -2633,7 +2633,7 @@ restore_anno(Abstr, NodeInfo) -> Anno end end, - erl_parse:map_anno(F, Abstr). + map_anno(F, Abstr). restore_loc(Location, #state{node_info = NodeInfo}) -> case ets:lookup(NodeInfo, Location) of @@ -2872,6 +2872,14 @@ var_mapfold(F, A0, [E0 | Es0]) -> var_mapfold(_F, A, E) -> {E, A}. +map_anno(F, AbstrList) when is_list(AbstrList) -> + [map_anno1(F, Abstr) || Abstr <- AbstrList]; +map_anno(F, Abstr) -> + map_anno1(F, Abstr). + +map_anno1(F, Abstr) -> + erl_parse:map_anno(F, Abstr). + family_list(L) -> sofs:to_external(family(L)). -- cgit v1.2.3 From 34e02fed50bbaa2af7b1828968b6ec02a54e98c8 Mon Sep 17 00:00:00 2001 From: Hans BolinderReturns a term where every collection of annotations Anno of -
Abstr has been replaced by the term returned by - callingerl_anno:to_term(Anno) . The abstract form is - traversed in a depth-first, left-to-right, fashion. +Returns a term where each collection of annotations +
Anno of the nodes of theerl_parse tree +has been replaced by the term + returned by Abstr + . The +erl_anno:to_term(Anno) erl_parse tree is traversed in a depth-first, + left-to-right, fashion.Date: Wed, 20 Jan 2016 09:54:00 +0100 Subject: erts: Improve the documentation of the abstract format --- erts/doc/src/absform.xml | 240 ++++++++++++++++++++++++++--------------------- 1 file changed, 131 insertions(+), 109 deletions(-) diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 1c0c3e1319..3f47b3061b 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -4,7 +4,7 @@ - 2001 2015 +2001 2016 Ericsson AB. All Rights Reserved. @@ -80,12 +80,15 @@ Rep(F) = {attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}} .- If F is an attribute
+-export_type([Type_1/A_1, ..., Type_k/A_k]) , then Rep(F) ={attribute,LINE,export_type,[{Type_1,A_1}, ..., {Type_k,A_k}]} .- If F is an attribute
-optional_callbacks([Fun_1/A_1, ..., Fun_k/A_k]) , then + Rep(F) ={attribute,LINE,optional_callbacks,[{Fun_1,A_1}, ..., {Fun_k,A_k}]} .- If F is an attribute
-compile(Options) , then Rep(F) ={attribute,LINE,compile,Options} .- If F is an attribute
-file(File,Line) , then Rep(F) ={attribute,LINE,file,{File,Line}} .- If F is a record declaration -
-record(Name,{V_1, ..., V_k}) , then Rep(F) = +-record(Name,{V_1, ..., V_k}) , + where eachV_i is a record field, then Rep(F) ={attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}} . For Rep(V), see below.- If F is a type declaration @@ -173,12 +176,12 @@
Patterns -If
Ps is a sequence of patternsP_1, ..., P_k , then +If Ps is a sequence of patterns
P_1, ..., P_k , then Rep(Ps) =[Rep(P_1), ..., Rep(P_k)] . Such sequences occur as the list of arguments to a function or fun.Individual patterns are represented as follows:
-
- If P is an atomic literal L, then Rep(P) = Rep(L).
+- If P is an atomic literal
L , then Rep(P) = Rep(L).- If P is a compound pattern
P_1 = P_2 , then Rep(P) ={match,LINE,Rep(P_1),Rep(P_2)} .- If P is a variable pattern
V , then @@ -211,6 +214,10 @@{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(P_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(P_k)}]} .- If P is
+#Name.Field , then Rep(P) ={record_index,LINE,Name,Rep(Field)} .- If P is a map pattern
#{A_1, ..., A_k} , where each +A_i is an associationP_i_1 := P_i_2 , then Rep(P) = +{map,LINE,[Rep(A_1), ..., Rep(A_k)]} . For Rep(A), see + below.- If P is
@@ -221,11 +228,11 @@( P_0 ) , then Rep(P) =Rep(P_0) , that is, patterns cannot be distinguished from their bodies.Expressions -A body B is a sequence of expressions
+E_1, ..., E_k , and - Rep(B) =[Rep(E_1), ..., Rep(E_k)] .A body B is a nonempty sequence of expressions
E_1, ..., E_k , + and Rep(B) =[Rep(E_1), ..., Rep(E_k)] .An expression E is one of the following alternatives:
-
- If P is an atomic literal
+L , then Rep(P) = Rep(L).- If E is an atomic literal
L , then Rep(E) = Rep(L).- If E is
P = E_0 , then Rep(E) ={match,LINE,Rep(P),Rep(E_0)} .- If E is a variable
V , then Rep(E) ={var,LINE,A} , @@ -256,14 +263,16 @@ Rep(E) ={record_index,LINE,Name,Rep(Field)} .- If E is
-E_0#Name.Field , then Rep(E) ={record_field,LINE,Rep(E_0),Name,Rep(Field)} .- If E is
#{W_1, ..., W_k} where each -W_i is a map assoc or exact field, then Rep(E) = -{map,LINE,[Rep(W_1), ..., Rep(W_k)]} . For Rep(W), see +- If E is a map creation
-#{A_1, ..., A_k} , + where eachA_i is an associationE_i_1 => E_i_2 + orE_i_1 := E_i_2 , then Rep(E) = +{map,LINE,[Rep(A_1), ..., Rep(A_k)]} . For Rep(A), see below.- If E is
+E_0#{W_1, ..., W_k} where -W_i is a map assoc or exact field, then Rep(E) = -{map,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]} . - For Rep(W), see below.- If E is a map update
E_0#{A_1, ..., A_k} , + where eachA_i is an associationE_i_1 => E_i_2 + orE_i_1 := E_i_2 , then Rep(E) = +{map,LINE,Rep(E_0),[Rep(A_1), ..., Rep(A_k)]} . + For Rep(A), see below.- If E is
catch E_0 , then Rep(E) ={'catch',LINE,Rep(E_0)} .- If E is
-E_0(E_1, ..., E_k) , then @@ -271,15 +280,15 @@- If E is
-E_m:E_0(E_1, ..., E_k) , then Rep(E) ={call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]} .- If E is a list comprehension
[E_0 || W_1, ..., W_k] , - where eachW_i is a generator or a filter, then Rep(E) = -{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]} . For Rep(W), see +- If E is a list comprehension
[E_0 || Q_1, ..., Q_k] , + where eachQ_i is a qualifier, then Rep(E) = +{lc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]} . For Rep(Q), see below.- If E is a binary comprehension -
+<<E_0 || W_1, ..., W_k>> , - where eachW_i is a generator or a filter, then - Rep(E) ={bc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]} . - For Rep(W), see below.<<E_0 || Q_1, ..., Q_k>> , + where eachQ_i is a qualifier, then + Rep(E) ={bc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]} . + For Rep(Q), see below.- If E is
begin B end , whereB is a body, then Rep(E) ={block,LINE,Rep(B)} .- If E is
if Ic_1 ; ... ; Ic_k end , @@ -311,7 +320,7 @@{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],Rep(A)} .- If E is
@@ -328,10 +337,10 @@try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end , whereB andA are a bodies, - eachCc_i is a case clause and + eachCc_i is a case clause, and eachTc_j is a catch clause then Rep(E) ={'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],Rep(A)} .{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}} . (Before the R15 release: Rep(E) ={'fun',LINE,{function,Module,Name,Arity}} .)- If E is
fun Fc_1 ; ... ; Fc_k end +- If E is
-fun Fc_1 ; ... ; Fc_k end , where eachFc_i is a function clause then Rep(E) ={'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}} .- If E is
fun Name Fc_1 ; ... ; Name Fc_k end +- If E is
fun Name Fc_1 ; ... ; Name Fc_k end , whereName is a variable and eachFc_i is a function clause then Rep(E) ={named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]} . @@ -342,46 +351,43 @@- Generators and Filters -When W is a generator or a filter (in the body of a list or - binary comprehension), then:
+Qualifiers +A qualifier Q is one of the following alternatives:
-
- If W is a generator
+P <- E , whereP is +- If Q is a generator
-P <- E , whereP is a pattern andE is an expression, then - Rep(W) ={generate,LINE,Rep(P),Rep(E)} .- If W is a generator
+P <= E , whereP is + Rep(Q) ={generate,LINE,Rep(P),Rep(E)} .- If Q is a generator
-P <= E , whereP is a pattern andE is an expression, then - Rep(W) ={b_generate,LINE,Rep(P),Rep(E)} .- If W is a filter
+ Rep(Q) =E , which is an expression, then - Rep(W) =Rep(E) .{b_generate,LINE,Rep(P),Rep(E)} .- If Q is a filter
E , whereE is an expression, then + Rep(Q) =Rep(E) .Binary Element Type Specifiers A type specifier list TSL for a binary element is a sequence of type - specifiers
-TS_1 - ... - TS_k . + specifiersTS_1 - ... - TS_k , and Rep(TSL) =[Rep(TS_1), ..., Rep(TS_k)] .When TS is a type specifier for a binary element, then:
-
- If TS is an atom
-A , then Rep(TS) =A .- If TS is a couple
+A:Value whereA is an atom - andValue is an integer, then Rep(TS) = -{A,Value} .- If TS is a type specifier
+A , whereA is an atom, + then Rep(TS) =A .- If TS is a type specifier
A:Value , + whereA is an atom andValue is an integer, + then Rep(TS) ={A,Value} .- @@ -393,37 +399,37 @@ and catch clauses.Map Assoc and Exact Fields -When W is an assoc or exact field (in the body of a map), then:
+Associations +An association A is one of the following alternatives:
-
- If W is an assoc field
K => V , where -K andV are both expressions, - then Rep(W) ={map_field_assoc,LINE,Rep(K),Rep(V)} . +- If A is an association
-K => V , + then Rep(A) ={map_field_assoc,LINE,Rep(K),Rep(V)} .- If W is an exact field
K := V , where -K andV are both expressions, - then Rep(W) ={map_field_exact,LINE,Rep(K),Rep(V)} . +- If A is an association
K := V , + then Rep(A) ={map_field_exact,LINE,Rep(K),Rep(V)} .A clause
C is one of the following alternatives:-
@@ -439,7 +445,7 @@- If C is a function clause
( Ps ) -> B +- If C is a function clause
-( Ps ) -> B , wherePs is a pattern sequence andB is a body, then Rep(C) ={clause,LINE,Rep(Ps),[],Rep(B)} .- If C is a function clause
( Ps ) when Gs -> B +- If C is a function clause
-( Ps ) when Gs -> B , wherePs is a pattern sequence,Gs is a guard sequence andB is a body, then Rep(C) ={clause,LINE,Rep(Ps),Rep(Gs),Rep(B)} .- If C is an if clause
Gs -> B +- If C is an if clause
-Gs -> B , whereGs is a guard sequence andB is a body, then Rep(C) ={clause,LINE,[],Rep(Gs),Rep(B)} .- If C is a case clause
P -> B +- If C is a case clause
-P -> B , whereP is a pattern andB is a body, then Rep(C) ={clause,LINE,[Rep(P)],[],Rep(B)} .- If C is a case clause
P when Gs -> B +- If C is a case clause
-P when Gs -> B , whereP is a pattern,Gs is a guard sequence andB is a body, then Rep(C) ={clause,LINE,[Rep(P)],Rep(Gs),Rep(B)} .- If C is a catch clause
P -> B +- If C is a catch clause
-P -> B , whereP is a pattern andB is a body, then Rep(C) ={clause,LINE,[Rep({throw,P,_})],[],Rep(B)} .- If C is a catch clause
X : P -> B +- If C is a catch clause
-X : P -> B , whereX is an atomic literal or a variable pattern, -P is a pattern andB is a body, then +P is a pattern, andB is a body, then Rep(C) ={clause,LINE,[Rep({X,P,_})],[],Rep(B)} .- If C is a catch clause
P when Gs -> B - whereP is a pattern,Gs is a guard sequence +- If C is a catch clause
-P when Gs -> B , + whereP is a pattern,Gs is a guard sequence, andB is a body, then Rep(C) ={clause,LINE,[Rep({throw,P,_})],Rep(Gs),Rep(B)} .- If C is a catch clause
X : P when Gs -> B +- If C is a catch clause
X : P when Gs -> B , whereX is an atomic literal or a variable pattern, -P is a pattern,Gs is a guard sequence +P is a pattern,Gs is a guard sequence, andB is a body, then Rep(C) ={clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)} .[Rep(Gt_1), ..., Rep(Gt_k)] .A guard test
Gt is one of the following alternatives:-
+ +- If Gt is an atomic literal L, then Rep(Gt) = Rep(L).
+- If Gt is an atomic literal
L , then Rep(Gt) = Rep(L).- If Gt is a variable pattern
@@ -467,15 +473,21 @@ Rep(Gt) =V , then Rep(Gt) ={var,LINE,A} , where A is an atom with a printname consisting of the same characters asV .{record_index,LINE,Name,Rep(Field)} .- If Gt is
+Gt_0#Name.Field , then Rep(Gt) ={record_field,LINE,Rep(Gt_0),Name,Rep(Field)} .- If Gt is a map creation
+#{A_1, ..., A_k} , + where eachA_i is an associationGt_i_1 => Gt_i_2 + orGt_i_1 := Gt_i_2 , then Rep(Gt) = +{map,LINE,[Rep(A_1), ..., Rep(A_k)]} . For Rep(A), see + above.- If Gt is a map update
Gt_0#{A_1, ..., A_k} , where each +A_i is an associationGt_i_1 => Gt_i_2 + orGt_i_1 := Gt_i_2 , then Rep(Gt) = +{map,LINE,Rep(Gt_0),[Rep(A_1), ..., Rep(A_k)]} . + For Rep(A), see above.- If Gt is
A(Gt_1, ..., Gt_k) , whereA is an atom, then Rep(Gt) ={call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]} .- If Gt is
-A_m:A(Gt_1, ..., Gt_k) , whereA_m is the atomerlang andA is an atom or an operator, then Rep(Gt) ={call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]} .- If Gt is
{A_m,A}(Gt_1, ..., Gt_k) , whereA_m is - the atomerlang andA is an atom or an operator, then - Rep(Gt) ={call,LINE,Rep({A_m,A}),[Rep(Gt_1), ..., Rep(Gt_k)]} . -- If Gt is
@@ -487,21 +499,20 @@( Gt_0 ) , then Rep(Gt) =Rep(Gt_0) , that is, parenthesized guard tests cannot be distinguished from their bodies.@@ -587,6 +591,24 @@ Types -
- If T is an annotated type
+Anno :: Type , - whereAnno is a variable and -Type is a type, then Rep(T) = -{ann_type,LINE,[Rep(Anno),Rep(Type)]} .- If T is an annotated type
A :: T_0 , + whereA is a variable, then Rep(T) = +{ann_type,LINE,[Rep(A),Rep(T_0)]} .- If T is an atom or integer literal L, then Rep(T) = Rep(L).
-- If T is
-L Op R , - whereOp is a binary operator andL andR - are types (this is an occurrence of an expression that can be - evaluated to an integer at compile time), then - Rep(T) ={op,LINE,Op,Rep(L),Rep(R)} .- If T is
Op A , whereOp is a - unary operator andA is a type (this is an occurrence of +- If T is an operator type
+T_1 Op T_2 , + whereOp is a binary operator (this is an occurrence of + an expression that can be evaluated to an integer at compile + time), then + Rep(T) ={op,LINE,Op,Rep(T_1),Rep(T_2)} .- If T is an operator type
+ then Rep(T) =Op T_0 , whereOp is a + unary operator (this is an occurrence of an expression that can be evaluated to an integer at compile time), - then Rep(T) ={op,LINE,Op,Rep(A)} .{op,LINE,Op,Rep(T_0)} .- If T is a bitstring type
@@ -509,53 +520,44 @@<<_:M,_:_*N>> , whereM andN are singleton integer types, then Rep(T) ={type,LINE,binary,[Rep(M),Rep(N)]} .{type,Line,nil,[]} .- If T is a fun type
-fun() , then Rep(T) ={type,LINE,'fun',[]} .- If T is a fun type
fun((...) -> B) , - whereB is a type, then - Rep(T) ={type,LINE,'fun',[{type,LINE,any},Rep(B)]} . +- If T is a fun type
fun((...) -> T_0) , then + Rep(T) ={type,LINE,'fun',[{type,LINE,any},Rep(T_0)]} .- If T is a fun type
+ then Rep(T) =fun(Ft) , whereFt is a function type, - then Rep(T) =Rep(Ft) .Rep(Ft) . For Rep(Ft), see below.- If T is an integer range type
L .. H , whereL andH are singleton integer types, then Rep(T) ={type,LINE,range,[Rep(L),Rep(H)]} .- If T is a map type
-map() , then Rep(T) ={type,LINE,map,any} .- If T is a map type
-#{P_1, ..., P_k} , where each -P_i is a map pair type, then Rep(T) = -{type,LINE,map,[Rep(P_1), ..., Rep(P_k)]} .- If T is a map pair type
-K => V , where -K andV are types, then Rep(T) = -{type,LINE,map_field_assoc,[Rep(K),Rep(V)]} .- If T is a predefined (or built-in) type
+N(A_1, ..., A_k) , - where eachA_i is a type, then Rep(T) = -{type,LINE,N,[Rep(A_1), ..., Rep(A_k)]} .- If T is a map type
+#{A_1, ..., A_k} , where each +A_i is an association type, then Rep(T) = +{type,LINE,map,[Rep(A_1), ..., Rep(A_k)]} . + For Rep(A), see below.- If T is a predefined (or built-in) type
N(T_1, ..., T_k) , + then Rep(T) = +{type,LINE,N,[Rep(T_1), ..., Rep(T_k)]} .- If T is a record type
-#Name{F_1, ..., F_k} , where eachF_i is a record field type, then Rep(T) ={type,LINE,record,[Rep(Name),Rep(F_1), ..., Rep(F_k)]} . -- If T is a record field type
-Name :: Type , - whereType is a type, then Rep(T) = -{type,LINE,field_type,[Rep(Name),Rep(Type)]} .- If T is a remote type
+M:N(A_1, ..., A_k) , where - eachA_i is a type, then Rep(T) = -{remote_type,LINE,[Rep(M),Rep(N),[Rep(A_1), ..., Rep(A_k)]]} . + For Rep(F), see below.- If T is a remote type
M:N(T_1, ..., T_k) , then Rep(T) = +{remote_type,LINE,[Rep(M),Rep(N),[Rep(T_1), ..., Rep(T_k)]]} .- If T is a tuple type
-tuple() , then Rep(T) ={type,LINE,tuple,any} .- If T is a tuple type
-{A_1, ..., A_k} , where - eachA_i is a type, then Rep(T) = -{type,LINE,tuple,[Rep(A_1), ..., Rep(A_k)]} .- If T is a type union
+T_1 | ... | T_k , - where eachT_i is a type, then Rep(T) = +- If T is a tuple type
+{T_1, ..., T_k} , then Rep(T) = +{type,LINE,tuple,[Rep(T_1), ..., Rep(T_k)]} .- If T is a type union
T_1 | ... | T_k , then Rep(T) ={type,LINE,union,[Rep(T_1), ..., Rep(T_k)]} .- If T is a type variable
-V , then Rep(T) ={var,LINE,A} , whereA is an atom with a printname consisting of the same characters asV . A type variable is any variable except underscore (_ ).- If T is a user-defined type
+N(A_1, ..., A_k) , - where eachA_i is a type, then Rep(T) = -{user_type,LINE,N,[Rep(A_1), ..., Rep(A_k)]} .- If T is a user-defined type
N(T_1, ..., T_k) , + then Rep(T) = +{user_type,LINE,N,[Rep(T_1), ..., Rep(T_k)]} .- If T is
@@ -563,15 +565,17 @@( T_0 ) , then Rep(T) =Rep(T_0) , that is, parenthesized types cannot be distinguished from their bodies.Function Types +A function type Ft is one of the following alternatives:
- If Ft is a constrained function type
-Ft_1 when Fc , whereFt_1 is a function type andFc is a function constraint, then Rep(T) = -{type,LINE,bounded_fun,[Rep(Ft_1),Rep(Fc)]} .- If Ft is a function type
+(A_1, ..., A_n) -> B , - where eachA_i andB are types, then - Rep(Ft) ={type,LINE,'fun',[{type,LINE,product,[Rep(A_1), - ..., Rep(A_n)]},Rep(B)]} .{type,LINE,bounded_fun,[Rep(Ft_1),Rep(Fc)]} . + For Rep(Fc), see below.- If Ft is a function type
(T_1, ..., T_n) -> T_0 , + where eachT_i is a type, then + Rep(Ft) ={type,LINE,'fun',[{type,LINE,product,[Rep(T_1), + ..., Rep(T_n)]},Rep(T_0)]} .+ + +Association Types ++
+- If A is an association type
+K => V , where +K andV are types, then Rep(A) = +{type,LINE,map_field_assoc,[Rep(K),Rep(V)]} .+ Record Field Types ++
+- If F is a record field type
+Name :: Type , + whereType is a type, then Rep(F) = +{type,LINE,field_type,[Rep(Name),Rep(Type)]} .-- cgit v1.2.3 From 6e2d941bf278191c11f6d1cebdfab5e51419d734 Mon Sep 17 00:00:00 2001 From: Hans Bolinder @@ -446,33 +473,23 @@Date: Wed, 20 Jan 2016 09:55:21 +0100 Subject: erts: Improve readability of The Abstract Format More verbose, but hopefully more readable than before. --- erts/doc/src/absform.xml | 420 +++++++++++++++++++++++++---------------------- 1 file changed, 228 insertions(+), 192 deletions(-) diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 3f47b3061b..ccdecf44ec 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -68,34 +68,29 @@ - If D is a module declaration consisting of the forms
-F_1 , ...,F_k , then Rep(D) =[Rep(F_1), ..., Rep(F_k)] .- If F is an attribute
-module(Mod) , then - Rep(F) ={attribute,LINE,module,Mod} .- If F is an attribute
-behavior(Behavior) , then Rep(F) ={attribute,LINE,behavior,Behavior} .- If F is an attribute
+-behaviour(Behaviour) , then Rep(F) ={attribute,LINE,behaviour,Behaviour} .- If F is an attribute
-compile(Options) , then + Rep(F) ={attribute,LINE,compile,Options} .- If F is an attribute
--export([Fun_1/A_1, ..., Fun_k/A_k]) , then Rep(F) ={attribute,LINE,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]} .- If F is an attribute
-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k]) , then - Rep(F) ={attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}} .- If F is an attribute
+-export_type([Type_1/A_1, ..., Type_k/A_k]) , then Rep(F) ={attribute,LINE,export_type,[{Type_1,A_1}, ..., {Type_k,A_k}]} .- If F is an attribute
+-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k]) , then + Rep(F) ={attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}} .- If F is an attribute
-module(Mod) , then + Rep(F) ={attribute,LINE,module,Mod} .- If F is an attribute
--optional_callbacks([Fun_1/A_1, ..., Fun_k/A_k]) , then Rep(F) ={attribute,LINE,optional_callbacks,[{Fun_1,A_1}, ..., {Fun_k,A_k}]} .- If F is an attribute
-compile(Options) , then - Rep(F) ={attribute,LINE,compile,Options} .- If F is an attribute
--file(File,Line) , then Rep(F) ={attribute,LINE,file,{File,Line}} .- If F is a record declaration -
--record(Name,{V_1, ..., V_k}) , - where eachV_i is a record field, then Rep(F) = -{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}} . - For Rep(V), see below.- If F is a type declaration -
+-Type Name(V_1, ..., V_k) :: T , where -Type is either the atomtype or the atomopaque , - eachV_i is a variable, andT is a type, then Rep(F) = -{attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}} . +- If F is a function declaration +
Name Fc_1 ; ... ; Name Fc_k , + where eachFc_i is a function clause with a + pattern sequence of the same lengthArity , then + Rep(F) ={function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]} .- If F is a function specification
+-Spec Name Ft_1; ...; Ft_k , @@ -112,15 +107,20 @@Arity , then Rep(F) ={attribute,Line,spec,{{Mod,Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}} .- If F is a record declaration +
+-record(Name,{V_1, ..., V_k}) , + where eachV_i is a record field, then Rep(F) = +{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}} . + For Rep(V), see below.- If F is a type declaration +
-Type Name(V_1, ..., V_k) :: T , where +Type is either the atomtype or the atomopaque , + eachV_i is a variable, andT is a type, then Rep(F) = +{attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}} . +- If F is a wild attribute
--A(T) , then Rep(F) ={attribute,LINE,A,T} .- If F is a function declaration -
Name Fc_1 ; ... ; Name Fc_k , - where eachFc_i is a function clause with a - pattern sequence of the same lengthArity , then - Rep(F) ={function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]} . -@@ -160,15 +160,15 @@ There are five kinds of atomic literals, which are represented in the same way in patterns, expressions and guards:
-
- If L is an integer or character literal, then - Rep(L) =
+{integer,LINE,L} .- If L is an atom literal, then + Rep(L) =
{atom,LINE,L} .- If L is a float literal, then Rep(L) =
+{float,LINE,L} .- If L is an integer or character literal, then + Rep(L) =
{integer,LINE,L} .- If L is a string literal consisting of the characters
-C_1 , ...,C_k , then Rep(L) ={string,LINE,[C_1, ..., C_k]} .- If L is an atom literal, then - Rep(L) =
{atom,LINE,L} .Note that negative integer and float literals do not occur as such; they are parsed as an application of the unary negation operator.
@@ -182,45 +182,53 @@Individual patterns are represented as follows:
- If P is an atomic literal
+L , then Rep(P) = Rep(L).- If P is a binary pattern +
<<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>> , where each +Size_i is an expression that can be evaluated to an integer + and eachTSL_i is a type specificer list, then + Rep(P) ={bin,LINE,[{bin_element,LINE,Rep(P_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(P_k),Rep(Size_k),Rep(TSL_k)}]} . + For Rep(TSL), see below. + An omittedSize_i is represented bydefault . + An omittedTSL_i is represented bydefault .- If P is a compound pattern
-P_1 = P_2 , then Rep(P) ={match,LINE,Rep(P_1),Rep(P_2)} .- If P is a variable pattern
-V , then - Rep(P) ={var,LINE,A} , - where A is an atom with a printname consisting of the same characters as -V .- If P is a universal pattern
-_ , then - Rep(P) ={var,LINE,'_'} .- If P is a tuple pattern
-{P_1, ..., P_k} , then - Rep(P) ={tuple,LINE,[Rep(P_1), ..., Rep(P_k)]} .- If P is a nil pattern
[] , then - Rep(P) ={nil,LINE} .- If P is a cons pattern
-[P_h | P_t] , then Rep(P) ={cons,LINE,Rep(P_h),Rep(P_t)} .- If E is a binary pattern
-<<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>> , then - Rep(E) ={bin,LINE,[{bin_element,LINE,Rep(P_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(P_k),Rep(Size_k),Rep(TSL_k)}]} . - For Rep(TSL), see below. - An omittedSize is represented bydefault . An omittedTSL - (type specifier list) is represented bydefault .- If P is
-P_1 Op P_2 , whereOp is a binary operator (this - is either an occurrence of++ applied to a literal string or character - list, or an occurrence of an expression that can be evaluated to a number - at compile time), - then Rep(P) ={op,LINE,Op,Rep(P_1),Rep(P_2)} .- If P is
-Op P_0 , whereOp is a unary operator (this is an - occurrence of an expression that can be evaluated to a number at compile - time), then Rep(P) ={op,LINE,Op,Rep(P_0)} .- If P is a record pattern
-#Name{Field_1=P_1, ..., Field_k=P_k} , - then Rep(P) = -{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(P_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(P_k)}]} .- If P is
#Name.Field , then - Rep(P) ={record_index,LINE,Name,Rep(Field)} .- If P is a map pattern
-#{A_1, ..., A_k} , where eachA_i is an associationP_i_1 := P_i_2 , then Rep(P) ={map,LINE,[Rep(A_1), ..., Rep(A_k)]} . For Rep(A), see below.- If P is
+( P_0 ) , then +- If P is a nil pattern
+[] , then + Rep(P) ={nil,LINE} .- If P is an operator pattern
+P_1 Op P_2 , + whereOp is a binary operator (this is either an occurrence + of++ applied to a literal string or character + list, or an occurrence of an expression that can be evaluated to a number + at compile time), + then Rep(P) ={op,LINE,Op,Rep(P_1),Rep(P_2)} .- If P is an operator pattern
+Op P_0 , + whereOp is a unary operator (this is an occurrence of + an expression that can be evaluated to a number at compile + time), then Rep(P) ={op,LINE,Op,Rep(P_0)} .- If P is a parenthesized pattern
+ that is, parenthesized patterns cannot be distinguished from their + bodies.( P_0 ) , then Rep(P) =Rep(P_0) , - that is, patterns cannot be distinguished from their bodies.- If P is a record field index pattern
+#Name.Field , + whereField is an atom, then + Rep(P) ={record_index,LINE,Name,Rep(Field)} .- If P is a record pattern +
+#Name{Field_1=P_1, ..., Field_k=P_k} , + where eachField_i is an atom or_ , then Rep(P) = +{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(P_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(P_k)}]} .- If P is a tuple pattern
+{P_1, ..., P_k} , then + Rep(P) ={tuple,LINE,[Rep(P_1), ..., Rep(P_k)]} .- If P is a universal pattern
+_ , then + Rep(P) ={var,LINE,'_'} .- If P is a variable pattern
V , then + Rep(P) ={var,LINE,A} , + where A is an atom with a printname consisting of the same characters as +V .Note that every pattern has the same source form as some expression, and is represented the same way as the corresponding expression.
@@ -233,36 +241,58 @@An expression E is one of the following alternatives:
- If E is an atomic literal
-L , then Rep(E) = Rep(L).- If E is
-P = E_0 , then - Rep(E) ={match,LINE,Rep(P),Rep(E_0)} .- If E is a variable
-V , then Rep(E) ={var,LINE,A} , - whereA is an atom with a printname consisting of the same - characters asV .- If E is a tuple skeleton
-{E_1, ..., E_k} , then - Rep(E) ={tuple,LINE,[Rep(E_1), ..., Rep(E_k)]} .- If E is
+[] , then - Rep(E) ={nil,LINE} .- If E is a binary comprehension +
+<<E_0 || Q_1, ..., Q_k>> , + where eachQ_i is a qualifier, then + Rep(E) ={bc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]} . + For Rep(Q), see below.- If E is a binary constructor
+<<E_1:Size_1/TSL_1, ..., E_k:Size_k/TSL_k>> , + where eachSize_i is an expression and each +TSL_i is a type specificer list, then Rep(E) = +{bin,LINE,[{bin_element,LINE,Rep(E_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(E_k),Rep(Size_k),Rep(TSL_k)}]} . + For Rep(TSL), see below. + An omittedSize_i is represented bydefault . + An omittedTSL_i is represented bydefault .- If E is a block expression
+begin B end , + whereB is a body, then + Rep(E) ={block,LINE,Rep(B)} .- If E is a case expression
+case E_0 of Cc_1 ; ... ; Cc_k end , + whereE_0 is an expression and eachCc_i is a + case clause then Rep(E) = +{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]} .- If E is a catch expression
catch E_0 , then + Rep(E) ={'catch',LINE,Rep(E_0)} .- If E is a cons skeleton
-[E_h | E_t] , then Rep(E) ={cons,LINE,Rep(E_h),Rep(E_t)} .- If E is a binary constructor
-<<V_1:Size_1/TSL_1, ..., V_k:Size_k/TSL_k>> , then Rep(E) = -{bin,LINE,[{bin_element,LINE,Rep(V_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(V_k),Rep(Size_k),Rep(TSL_k)}]} . - For Rep(TSL), see below. - An omittedSize is represented bydefault . An omittedTSL - (type specifier list) is represented bydefault .- If E is
-E_1 Op E_2 , whereOp is a binary operator, - then Rep(E) ={op,LINE,Op,Rep(E_1),Rep(E_2)} .- If E is
-Op E_0 , whereOp is a unary operator, then - Rep(E) ={op,LINE,Op,Rep(E_0)} .- If E is
+#Name{Field_1=E_1, ..., Field_k=E_k} , +- If E is a fun expression
+fun Name/Arity , then + Rep(E) ={'fun',LINE,{function,Name,Arity}} .- If E is a fun expression +
+fun Module:Name/Arity , then Rep(E) = +{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}} . + (Before the R15 release: Rep(E) = +{'fun',LINE,{function,Module,Name,Arity}} .)- If E is a fun expression
+fun Fc_1 ; ... ; Fc_k end , + where eachFc_i is a function clause then Rep(E) = +{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}} .- If E is a fun expression +
+fun Name Fc_1 ; ... ; Name Fc_k end , + whereName is a variable and each +Fc_i is a function clause then Rep(E) = +{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]} . +- If E is a function call
+E_0(E_1, ..., E_k) , then + Rep(E) ={call,LINE,Rep(E_0),[Rep(E_1), ..., Rep(E_k)]} .- If E is a function call
-E_m:E_0(E_1, ..., E_k) , then Rep(E) = -{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]} .- If E is
-E_0#Name{Field_1=E_1, ..., Field_k=E_k} , then - Rep(E) = -{record,LINE,Rep(E_0),Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]} .- If E is
-#Name.Field , then - Rep(E) ={record_index,LINE,Name,Rep(Field)} .- If E is
+E_0#Name.Field , then - Rep(E) ={record_field,LINE,Rep(E_0),Name,Rep(Field)} .{call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]} . +- If E is an if expression
+if Ic_1 ; ... ; Ic_k end , + where eachIc_i is an if clause then Rep(E) = +{'if',LINE,[Rep(Ic_1), ..., Rep(Ic_k)]} .- If E is a list comprehension
[E_0 || Q_1, ..., Q_k] , + where eachQ_i is a qualifier, then Rep(E) = +{lc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]} . For Rep(Q), see + below.- If E is a map creation
-#{A_1, ..., A_k} , where eachA_i is an associationE_i_1 => E_i_2 orE_i_1 := E_i_2 , then Rep(E) = @@ -273,95 +303,92 @@ orE_i_1 := E_i_2 , then Rep(E) ={map,LINE,Rep(E_0),[Rep(A_1), ..., Rep(A_k)]} . For Rep(A), see below.- If E is
-catch E_0 , then - Rep(E) ={'catch',LINE,Rep(E_0)} .- If E is
-E_0(E_1, ..., E_k) , then - Rep(E) ={call,LINE,Rep(E_0),[Rep(E_1), ..., Rep(E_k)]} .- If E is
-E_m:E_0(E_1, ..., E_k) , then Rep(E) = -{call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]} . -- If E is a list comprehension
-[E_0 || Q_1, ..., Q_k] , - where eachQ_i is a qualifier, then Rep(E) = -{lc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]} . For Rep(Q), see - below.- If E is a binary comprehension -
-<<E_0 || Q_1, ..., Q_k>> , - where eachQ_i is a qualifier, then - Rep(E) ={bc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]} . - For Rep(Q), see below.- If E is
-begin B end , whereB is a body, then - Rep(E) ={block,LINE,Rep(B)} .- If E is
-if Ic_1 ; ... ; Ic_k end , - where eachIc_i is an if clause then Rep(E) = -{'if',LINE,[Rep(Ic_1), ..., Rep(Ic_k)]} .- If E is
-case E_0 of Cc_1 ; ... ; Cc_k end , - whereE_0 is an expression and eachCc_i is a - case clause then Rep(E) = -{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]} .- If E is
try B catch Tc_1 ; ... ; Tc_k end , +- If E is a match operator expression
+P = E_0 , + whereP is a pattern, then + Rep(E) ={match,LINE,Rep(P),Rep(E_0)} .- If E is nil,
+[] , then + Rep(E) ={nil,LINE} .- If E is an operator expression
+E_1 Op E_2 , + whereOp is a binary operator other than the match + operator= , then + Rep(E) ={op,LINE,Op,Rep(E_1),Rep(E_2)} .- If E is an operator expression
+Op E_0 , + whereOp is a unary operator, then + Rep(E) ={op,LINE,Op,Rep(E_0)} .- If E is a parenthesized expression
+( E_0 ) , then + Rep(E) =Rep(E_0) , that is, parenthesized + expressions cannot be distinguished from their bodies.- If E is a receive expression
+receive Cc_1 ; ... ; Cc_k end , + where eachCc_i is a case clause then Rep(E) = +{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]} .- If E is a receive expression +
+receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end , + where eachCc_i is a case clause, +E_0 is an expression andB_t is a body, then Rep(E) = +{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)} .- If E is a record creation +
+#Name{Field_1=E_1, ..., Field_k=E_k} , + where eachField_i is an atom or_ , then Rep(E) = +{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]} .- If E is a record field access
+E_0#Name.Field , + whereField is an atom, then + Rep(E) ={record_field,LINE,Rep(E_0),Name,Rep(Field)} .- If E is a record field index
+#Name.Field , + whereField is an atom, then + Rep(E) ={record_index,LINE,Name,Rep(Field)} .- If E is a record update +
+E_0#Name{Field_1=E_1, ..., Field_k=E_k} , + where eachField_i is an atom, then Rep(E) = +{record,LINE,Rep(E_0),Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]} .- If E is a tuple skeleton
+{E_1, ..., E_k} , then + Rep(E) ={tuple,LINE,[Rep(E_1), ..., Rep(E_k)]} .- If E is a try expression
-try B catch Tc_1 ; ... ; Tc_k end , whereB is a body and eachTc_i is a catch clause then Rep(E) ={'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],[]} .- If E is
try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end , +- If E is a try expression +
-try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end , whereB is a body, eachCc_i is a case clause and eachTc_j is a catch clause then Rep(E) ={'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],[]} .- If E is
try B after A end , +- If E is a try expression
-try B after A end , whereB andA are bodies then Rep(E) ={'try',LINE,Rep(B),[],[],Rep(A)} .- If E is
try B of Cc_1 ; ... ; Cc_k after A end , +- If E is a try expression +
-try B of Cc_1 ; ... ; Cc_k after A end , whereB andA are a bodies and eachCc_i is a case clause then Rep(E) ={'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[],Rep(A)} .- If E is
try B catch Tc_1 ; ... ; Tc_k after A end , +- If E is a try expression +
-try B catch Tc_1 ; ... ; Tc_k after A end , whereB andA are bodies and eachTc_i is a catch clause then Rep(E) ={'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],Rep(A)} .- If E is
try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end , +- If E is a try expression +
-try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end , whereB andA are a bodies, eachCc_i is a case clause, and eachTc_j is a catch clause then Rep(E) ={'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],Rep(A)} .- If E is
-receive Cc_1 ; ... ; Cc_k end , - where eachCc_i is a case clause then Rep(E) = -{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]} .- If E is
-receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end , - where eachCc_i is a case clause, -E_0 is an expression andB_t is a body, then Rep(E) = -{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)} .- If E is
-fun Name / Arity , then - Rep(E) ={'fun',LINE,{function,Name,Arity}} .- If E is
-fun Module:Name/Arity , then Rep(E) = -{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}} . - (Before the R15 release: Rep(E) = -{'fun',LINE,{function,Module,Name,Arity}} .)- If E is
-fun Fc_1 ; ... ; Fc_k end , - where eachFc_i is a function clause then Rep(E) = -{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}} .- If E is
-fun Name Fc_1 ; ... ; Name Fc_k end , - whereName is a variable and each -Fc_i is a function clause then Rep(E) = -{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]} . -- If E is
+( E_0 ) , then - Rep(E) =Rep(E_0) , that is, parenthesized - expressions cannot be distinguished from their bodies.- If E is a variable
V , then Rep(E) ={var,LINE,A} , + whereA is an atom with a printname consisting of the same + characters asV .@@ -399,16 +426,6 @@ and catch clauses. Qualifiers A qualifier Q is one of the following alternatives:
+
- If Q is a filter
E , whereE is an expression, then + Rep(Q) =Rep(E) .- If Q is a generator
P <- E , whereP is a pattern andE is an expression, then Rep(Q) ={generate,LINE,Rep(P),Rep(E)} .- If Q is a generator
-P <= E , whereP is a pattern andE is an expression, then Rep(Q) ={b_generate,LINE,Rep(P),Rep(E)} .- If Q is a filter
E , whereE is an expression, then - Rep(Q) =Rep(E) .A clause
C is one of the following alternatives:-
- If C is a function clause
-( Ps ) -> B , - wherePs is a pattern sequence andB is a body, then - Rep(C) ={clause,LINE,Rep(Ps),[],Rep(B)} .- If C is a function clause
-( Ps ) when Gs -> B , - wherePs is a pattern sequence, -Gs is a guard sequence andB is a body, then - Rep(C) ={clause,LINE,Rep(Ps),Rep(Gs),Rep(B)} .- If C is an if clause
Gs -> B , - whereGs is a guard sequence andB is a body, then - Rep(C) ={clause,LINE,[],Rep(Gs),Rep(B)} .- If C is a case clause
@@ -432,6 +449,16 @@P -> B , whereP is a pattern andB is a body, then Rep(C) ={clause,LINE,[Rep(P)],[],Rep(B)} .P is a pattern,Gs is a guard sequence, andB is a body, then Rep(C) ={clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)} .- If C is a function clause
+( Ps ) -> B , + wherePs is a pattern sequence andB is a body, then + Rep(C) ={clause,LINE,Rep(Ps),[],Rep(B)} .- If C is a function clause
+( Ps ) when Gs -> B , + wherePs is a pattern sequence, +Gs is a guard sequence andB is a body, then + Rep(C) ={clause,LINE,Rep(Ps),Rep(Gs),Rep(B)} .- If C is an if clause
Gs -> B , + whereGs is a guard sequence andB is a body, then + Rep(C) ={clause,LINE,[],Rep(Gs),Rep(B)} .A guard test
Gt is one of the following alternatives:
- If Gt is an atomic literal
-L , then Rep(Gt) = Rep(L).- If Gt is a variable pattern
-V , then - Rep(Gt) ={var,LINE,A} , where A is an atom with - a printname consisting of the same characters asV .- If Gt is a tuple skeleton
-{Gt_1, ..., Gt_k} , then - Rep(Gt) ={tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]} .- If Gt is
-[] , then Rep(Gt) ={nil,LINE} .- If Gt is a cons skeleton
[Gt_h | Gt_t] , then - Rep(Gt) ={cons,LINE,Rep(Gt_h),Rep(Gt_t)} .- If Gt is a binary constructor -
-<<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>> , then +<<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>> , + where eachSize_i is a guard test and each +TSL_i is a type specificer list, then Rep(Gt) ={bin,LINE,[{bin_element,LINE,Rep(Gt_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(Gt_k),Rep(Size_k),Rep(TSL_k)}]} . For Rep(TSL), see above. - An omittedSize is represented bydefault . - An omittedTSL (type specifier list) is represented - bydefault .- If Gt is
-Gt_1 Op Gt_2 , whereOp - is a binary operator, then Rep(Gt) = -{op,LINE,Op,Rep(Gt_1),Rep(Gt_2)} .- If Gt is
-Op Gt_0 , whereOp is a unary operator, then - Rep(Gt) ={op,LINE,Op,Rep(Gt_0)} .- If Gt is
-#Name{Field_1=Gt_1, ..., Field_k=Gt_k} , then - Rep(E) = -{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(Gt_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(Gt_k)}]} .- If Gt is
-#Name.Field , then - Rep(Gt) ={record_index,LINE,Name,Rep(Field)} .- If Gt is
+ An omittedGt_0#Name.Field , then - Rep(Gt) ={record_field,LINE,Rep(Gt_0),Name,Rep(Field)} .Size_i is represented bydefault . + An omittedTSL_i is represented bydefault . +- If Gt is a cons skeleton
+[Gt_h | Gt_t] , then + Rep(Gt) ={cons,LINE,Rep(Gt_h),Rep(Gt_t)} .- If Gt is a function call
+A(Gt_1, ..., Gt_k) , + whereA is an atom, then Rep(Gt) = +{call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]} .- If Gt is a function call
A_m:A(Gt_1, ..., Gt_k) , + whereA_m is the atomerlang andA is + an atom or an operator, then Rep(Gt) = +{call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]} .- If Gt is a map creation
-#{A_1, ..., A_k} , where eachA_i is an associationGt_i_1 => Gt_i_2 orGt_i_1 := Gt_i_2 , then Rep(Gt) = @@ -483,14 +500,33 @@ orGt_i_1 := Gt_i_2 , then Rep(Gt) ={map,LINE,Rep(Gt_0),[Rep(A_1), ..., Rep(A_k)]} . For Rep(A), see above.- If Gt is
-A(Gt_1, ..., Gt_k) , whereA is an atom, then - Rep(Gt) ={call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]} .- If Gt is
-A_m:A(Gt_1, ..., Gt_k) , whereA_m is - the atomerlang andA is an atom or an operator, then - Rep(Gt) ={call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]} .- If Gt is
( Gt_0 ) , then +- If Gt is nil,
+[] , + then Rep(Gt) ={nil,LINE} .- If Gt is an operator guard test
+Gt_1 Op Gt_2 , + whereOp is a binary operator other than the match + operator= , then + Rep(Gt) ={op,LINE,Op,Rep(Gt_1),Rep(Gt_2)} .- If Gt is an operator guard test
+Op Gt_0 , + whereOp is a unary operator, then + Rep(Gt) ={op,LINE,Op,Rep(Gt_0)} .- If Gt is a parenthesized guard test
+( Gt_0 ) , then Rep(Gt) =Rep(Gt_0) , that is, parenthesized guard tests cannot be distinguished from their bodies.- If Gt is a record creation +
+#Name{Field_1=Gt_1, ..., Field_k=Gt_k} , + where eachField_i is an atom or_ , then Rep(Gt) = +{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(Gt_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(Gt_k)}]} .- If Gt is a record field access
+Gt_0#Name.Field , + whereField is an atom, then + Rep(Gt) ={record_field,LINE,Rep(Gt_0),Name,Rep(Field)} .- If Gt is a record field index
+#Name.Field , + whereField is an atom, then + Rep(Gt) ={record_index,LINE,Name,Rep(Field)} .- If Gt is a tuple skeleton
+{Gt_1, ..., Gt_k} , then + Rep(Gt) ={tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]} .- If Gt is a variable pattern
V , then + Rep(Gt) ={var,LINE,A} , where A is an atom with + a printname consisting of the same characters asV .Note that every guard test has the same source form as some expression, and is represented the same way as the corresponding expression.
@@ -504,15 +540,6 @@{ann_type,LINE,[Rep(A),Rep(T_0)]} .- If T is an atom or integer literal L, then Rep(T) = Rep(L).
-- If T is an operator type
-T_1 Op T_2 , - whereOp is a binary operator (this is an occurrence of - an expression that can be evaluated to an integer at compile - time), then - Rep(T) ={op,LINE,Op,Rep(T_1),Rep(T_2)} .- If T is an operator type
Op T_0 , whereOp is a - unary operator (this is an occurrence of - an expression that can be evaluated to an integer at compile time), - then Rep(T) ={op,LINE,Op,Rep(T_0)} .- If T is a bitstring type
@@ -535,6 +562,18 @@<<_:M,_:_*N>> , whereM andN are singleton integer types, then Rep(T) ={type,LINE,binary,[Rep(M),Rep(N)]} .A_i is an association type, then Rep(T) ={type,LINE,map,[Rep(A_1), ..., Rep(A_k)]} . For Rep(A), see below. +- If T is an operator type
+T_1 Op T_2 , + whereOp is a binary operator (this is an occurrence of + an expression that can be evaluated to an integer at compile + time), then + Rep(T) ={op,LINE,Op,Rep(T_1),Rep(T_2)} .- If T is an operator type
+Op T_0 , whereOp is a + unary operator (this is an occurrence of + an expression that can be evaluated to an integer at compile time), + then Rep(T) ={op,LINE,Op,Rep(T_0)} .- If T is
( T_0 ) , then Rep(T) =Rep(T_0) , + that is, parenthesized types cannot be distinguished from their + bodies.- If T is a predefined (or built-in) type
@@ -558,9 +597,6 @@N(T_1, ..., T_k) , then Rep(T) ={type,LINE,N,[Rep(T_1), ..., Rep(T_k)]} .- If T is a user-defined type
-N(T_1, ..., T_k) , then Rep(T) ={user_type,LINE,N,[Rep(T_1), ..., Rep(T_k)]} .- If T is
( T_0 ) , then Rep(T) =Rep(T_0) , - that is, parenthesized types cannot be distinguished from their - bodies.-- cgit v1.2.3