aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2016-01-20 12:13:42 +0100
committerHans Bolinder <[email protected]>2016-01-20 12:13:42 +0100
commitc45652ee1b43ba4501651182a6d3c9f4789c3429 (patch)
treeea6ea04c20aa2d9fd44fa783edb8bae654815d76
parentf9f2bfcc846f1711a712947c87eb5e690900483a (diff)
parent6e2d941bf278191c11f6d1cebdfab5e51419d734 (diff)
downloadotp-c45652ee1b43ba4501651182a6d3c9f4789c3429.tar.gz
otp-c45652ee1b43ba4501651182a6d3c9f4789c3429.tar.bz2
otp-c45652ee1b43ba4501651182a6d3c9f4789c3429.zip
Merge branch 'hb/stdlib/refine_abstr_types/OTP-10292'
* hb/stdlib/refine_abstr_types/OTP-10292: erts: Improve readability of The Abstract Format erts: Improve the documentation of the abstract format stdlib: Update erl_parse(3) stdlib: Refine the types of the abstract format compiler: Improve type and specs hipe: Improve types dialyzer: Improve a type doc: Update a refman example syntax_tools: Correct a type stdlib: Correct a type
-rw-r--r--erts/doc/src/absform.xml598
-rw-r--r--lib/compiler/src/compile.erl13
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl2
-rw-r--r--lib/hipe/cerl/erl_types.erl6
-rw-r--r--lib/stdlib/doc/src/erl_parse.xml120
-rw-r--r--lib/stdlib/src/erl_lint.erl5
-rw-r--r--lib/stdlib/src/erl_parse.yrl439
-rw-r--r--lib/stdlib/src/io.erl2
-rw-r--r--lib/stdlib/src/qlc_pt.erl34
-rw-r--r--lib/syntax_tools/src/erl_recomment.erl5
-rw-r--r--system/doc/reference_manual/expressions.xml20
11 files changed, 883 insertions, 361 deletions
diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml
index 1c0c3e1319..ccdecf44ec 100644
--- a/erts/doc/src/absform.xml
+++ b/erts/doc/src/absform.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2015</year>
+ <year>2001</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -68,31 +68,29 @@
<item>If D is a module declaration consisting of the forms
<c>F_1</c>, ..., <c>F_k</c>, then
Rep(D) = <c>[Rep(F_1), ..., Rep(F_k)]</c>.</item>
- <item>If F is an attribute <c>-module(Mod)</c>, then
- Rep(F) = <c>{attribute,LINE,module,Mod}</c>.</item>
<item>If F is an attribute <c>-behavior(Behavior)</c>, then
Rep(F) = <c>{attribute,LINE,behavior,Behavior}</c>.</item>
<item>If F is an attribute <c>-behaviour(Behaviour)</c>, then
Rep(F) = <c>{attribute,LINE,behaviour,Behaviour}</c>.</item>
+ <item>If F is an attribute <c>-compile(Options)</c>, then
+ Rep(F) = <c>{attribute,LINE,compile,Options}</c>.</item>
<item>If F is an attribute <c>-export([Fun_1/A_1, ..., Fun_k/A_k])</c>, then
Rep(F) = <c>{attribute,LINE,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}</c>.</item>
- <item>If F is an attribute <c>-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])</c>, then
- Rep(F) = <c>{attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}</c>.</item>
<item>If F is an attribute <c>-export_type([Type_1/A_1, ..., Type_k/A_k])</c>, then
Rep(F) = <c>{attribute,LINE,export_type,[{Type_1,A_1}, ..., {Type_k,A_k}]}</c>.</item>
- <item>If F is an attribute <c>-compile(Options)</c>, then
- Rep(F) = <c>{attribute,LINE,compile,Options}</c>.</item>
+ <item>If F is an attribute <c>-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])</c>, then
+ Rep(F) = <c>{attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}</c>.</item>
+ <item>If F is an attribute <c>-module(Mod)</c>, then
+ Rep(F) = <c>{attribute,LINE,module,Mod}</c>.</item>
+ <item>If F is an attribute <c>-optional_callbacks([Fun_1/A_1, ..., Fun_k/A_k])</c>, then
+ Rep(F) = <c>{attribute,LINE,optional_callbacks,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}</c>.</item>
<item>If F is an attribute <c>-file(File,Line)</c>, then
Rep(F) = <c>{attribute,LINE,file,{File,Line}}</c>.</item>
- <item>If F is a record declaration
- <c>-record(Name,{V_1, ..., V_k})</c>, then Rep(F) =
- <c>{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}</c>.
- For Rep(V), see below.</item>
- <item>If F is a type declaration
- <c>-Type Name(V_1, ..., V_k) :: T</c>, where
- <c>Type</c> is either the atom <c>type</c> or the atom <c>opaque</c>,
- each <c>V_i</c> is a variable, and <c>T</c> is a type, then Rep(F) =
- <c>{attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}}</c>.
+ <item>If F is a function declaration
+ <c>Name Fc_1 ; ... ; Name Fc_k</c>,
+ where each <c>Fc_i</c> is a function clause with a
+ pattern sequence of the same length <c>Arity</c>, then
+ Rep(F) = <c>{function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}</c>.
</item>
<item>If F is a function specification
<c>-Spec Name Ft_1; ...; Ft_k</c>,
@@ -109,15 +107,20 @@
<c>Arity</c>, then Rep(F) =
<c>{attribute,Line,spec,{{Mod,Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}</c>.
</item>
+ <item>If F is a record declaration
+ <c>-record(Name,{V_1, ..., V_k})</c>,
+ where each <c>V_i</c> is a record field, then Rep(F) =
+ <c>{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}</c>.
+ For Rep(V), see below.</item>
+ <item>If F is a type declaration
+ <c>-Type Name(V_1, ..., V_k) :: T</c>, where
+ <c>Type</c> is either the atom <c>type</c> or the atom <c>opaque</c>,
+ each <c>V_i</c> is a variable, and <c>T</c> is a type, then Rep(F) =
+ <c>{attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}}</c>.
+ </item>
<item>If F is a wild attribute <c>-A(T)</c>, then
Rep(F) = <c>{attribute,LINE,A,T}</c>.
<br></br></item>
- <item>If F is a function declaration
- <c>Name Fc_1 ; ... ; Name Fc_k</c>,
- where each <c>Fc_i</c> is a function clause with a
- pattern sequence of the same length <c>Arity</c>, then
- Rep(F) = <c>{function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}</c>.
- </item>
</list>
<section>
@@ -157,15 +160,15 @@
<p>There are five kinds of atomic literals, which are represented in the
same way in patterns, expressions and guards:</p>
<list type="bulleted">
- <item>If L is an integer or character literal, then
- Rep(L) = <c>{integer,LINE,L}</c>.</item>
+ <item>If L is an atom literal, then
+ Rep(L) = <c>{atom,LINE,L}</c>.</item>
<item>If L is a float literal, then
Rep(L) = <c>{float,LINE,L}</c>.</item>
+ <item>If L is an integer or character literal, then
+ Rep(L) = <c>{integer,LINE,L}</c>.</item>
<item>If L is a string literal consisting of the characters
<c>C_1</c>, ..., <c>C_k</c>, then
Rep(L) = <c>{string,LINE,[C_1, ..., C_k]}</c>.</item>
- <item>If L is an atom literal, then
- Rep(L) = <c>{atom,LINE,L}</c>.</item>
</list>
<p>Note that negative integer and float literals do not occur as such; they are
parsed as an application of the unary negation operator.</p>
@@ -173,47 +176,59 @@
<section>
<title>Patterns</title>
- <p>If <c>Ps</c> is a sequence of patterns <c>P_1, ..., P_k</c>, then
+ <p>If Ps is a sequence of patterns <c>P_1, ..., P_k</c>, then
Rep(Ps) = <c>[Rep(P_1), ..., Rep(P_k)]</c>. Such sequences occur as the
list of arguments to a function or fun.</p>
<p>Individual patterns are represented as follows:</p>
<list type="bulleted">
- <item>If P is an atomic literal L, then Rep(P) = Rep(L).</item>
+ <item>If P is an atomic literal <c>L</c>, then Rep(P) = Rep(L).</item>
+ <item>If P is a binary pattern
+ <c>&lt;&lt;P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>></c>, where each
+ <c>Size_i</c> is an expression that can be evaluated to an integer
+ and each <c>TSL_i</c> is a type specificer list, then
+ Rep(P) = <c>{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)}]}</c>.
+ For Rep(TSL), see below.
+ An omitted <c>Size_i</c> is represented by <c>default</c>.
+ An omitted <c>TSL_i</c> is represented by <c>default</c>.</item>
<item>If P is a compound pattern <c>P_1 = P_2</c>, then
Rep(P) = <c>{match,LINE,Rep(P_1),Rep(P_2)}</c>.</item>
- <item>If P is a variable pattern <c>V</c>, then
- Rep(P) = <c>{var,LINE,A}</c>,
- where A is an atom with a printname consisting of the same characters as
- <c>V</c>.</item>
- <item>If P is a universal pattern <c>_</c>, then
- Rep(P) = <c>{var,LINE,'_'}</c>.</item>
- <item>If P is a tuple pattern <c>{P_1, ..., P_k}</c>, then
- Rep(P) = <c>{tuple,LINE,[Rep(P_1), ..., Rep(P_k)]}</c>.</item>
- <item>If P is a nil pattern <c>[]</c>, then
- Rep(P) = <c>{nil,LINE}</c>.</item>
<item>If P is a cons pattern <c>[P_h | P_t]</c>, then
Rep(P) = <c>{cons,LINE,Rep(P_h),Rep(P_t)}</c>.</item>
- <item>If E is a binary pattern <c>&lt;&lt;P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>></c>, then
- Rep(E) = <c>{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)}]}</c>.
- For Rep(TSL), see below.
- An omitted <c>Size</c> is represented by <c>default</c>. An omitted <c>TSL</c>
- (type specifier list) is represented by <c>default</c>.</item>
- <item>If P is <c>P_1 Op P_2</c>, where <c>Op</c> is a binary operator (this
- is either an occurrence of <c>++</c> applied to a literal string or character
+ <item>If P is a map pattern <c>#{A_1, ..., A_k}</c>, where each
+ <c>A_i</c> is an association <c>P_i_1 := P_i_2</c>, then Rep(P) =
+ <c>{map,LINE,[Rep(A_1), ..., Rep(A_k)]}</c>. For Rep(A), see
+ below.</item>
+ <item>If P is a nil pattern <c>[]</c>, then
+ Rep(P) = <c>{nil,LINE}</c>.</item>
+ <item>If P is an operator pattern <c>P_1 Op P_2</c>,
+ where <c>Op</c> is a binary operator (this is either an occurrence
+ of <c>++</c> 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) = <c>{op,LINE,Op,Rep(P_1),Rep(P_2)}</c>.</item>
- <item>If P is <c>Op P_0</c>, where <c>Op</c> is a unary operator (this is an
- occurrence of an expression that can be evaluated to a number at compile
+ <item>If P is an operator pattern <c>Op P_0</c>,
+ where <c>Op</c> is a unary operator (this is an occurrence of
+ an expression that can be evaluated to a number at compile
time), then Rep(P) = <c>{op,LINE,Op,Rep(P_0)}</c>.</item>
- <item>If P is a record pattern <c>#Name{Field_1=P_1, ..., Field_k=P_k}</c>,
- then Rep(P) =
- <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(P_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(P_k)}]}</c>.</item>
- <item>If P is <c>#Name.Field</c>, then
- Rep(P) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item>
- <item>If P is <c>( P_0 )</c>, then
+ <item>If P is a parenthesized pattern <c>( P_0 )</c>, then
Rep(P) = <c>Rep(P_0)</c>,
- that is, patterns cannot be distinguished from their bodies.</item>
+ that is, parenthesized patterns cannot be distinguished from their
+ bodies.</item>
+ <item>If P is a record field index pattern <c>#Name.Field</c>,
+ where <c>Field</c> is an atom, then
+ Rep(P) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item>
+ <item>If P is a record pattern
+ <c>#Name{Field_1=P_1, ..., Field_k=P_k}</c>,
+ where each <c>Field_i</c> is an atom or <c>_</c>, then Rep(P) =
+ <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(P_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(P_k)}]}</c>.</item>
+ <item>If P is a tuple pattern <c>{P_1, ..., P_k}</c>, then
+ Rep(P) = <c>{tuple,LINE,[Rep(P_1), ..., Rep(P_k)]}</c>.</item>
+ <item>If P is a universal pattern <c>_</c>, then
+ Rep(P) = <c>{var,LINE,'_'}</c>.</item>
+ <item>If P is a variable pattern <c>V</c>, then
+ Rep(P) = <c>{var,LINE,A}</c>,
+ where A is an atom with a printname consisting of the same characters as
+ <c>V</c>.</item>
</list>
<p>Note that every pattern has the same source form as some expression, and is
represented the same way as the corresponding expression.</p>
@@ -221,167 +236,185 @@
<section>
<title>Expressions</title>
- <p>A body B is a sequence of expressions <c>E_1, ..., E_k</c>, and
- Rep(B) = <c>[Rep(E_1), ..., Rep(E_k)]</c>.</p>
+ <p>A body B is a nonempty sequence of expressions <c>E_1, ..., E_k</c>,
+ and Rep(B) = <c>[Rep(E_1), ..., Rep(E_k)]</c>.</p>
<p>An expression E is one of the following alternatives:</p>
<list type="bulleted">
- <item>If P is an atomic literal <c>L</c>, then Rep(P) = Rep(L).</item>
- <item>If E is <c>P = E_0</c>, then
- Rep(E) = <c>{match,LINE,Rep(P),Rep(E_0)}</c>.</item>
- <item>If E is a variable <c>V</c>, then Rep(E) = <c>{var,LINE,A}</c>,
- where <c>A</c> is an atom with a printname consisting of the same
- characters as <c>V</c>.</item>
- <item>If E is a tuple skeleton <c>{E_1, ..., E_k}</c>, then
- Rep(E) = <c>{tuple,LINE,[Rep(E_1), ..., Rep(E_k)]}</c>.</item>
- <item>If E is <c>[]</c>, then
- Rep(E) = <c>{nil,LINE}</c>.</item>
- <item>If E is a cons skeleton <c>[E_h | E_t]</c>, then
- Rep(E) = <c>{cons,LINE,Rep(E_h),Rep(E_t)}</c>.</item>
- <item>If E is a binary constructor <c>&lt;&lt;V_1:Size_1/TSL_1, ..., V_k:Size_k/TSL_k>></c>, then Rep(E) =
- <c>{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)}]}</c>.
+ <item>If E is an atomic literal <c>L</c>, then Rep(E) = Rep(L).</item>
+ <item>If E is a binary comprehension
+ <c>&lt;&lt;E_0 || Q_1, ..., Q_k>></c>,
+ where each <c>Q_i</c> is a qualifier, then
+ Rep(E) = <c>{bc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}</c>.
+ For Rep(Q), see below.</item>
+ <item>If E is a binary constructor <c>&lt;&lt;E_1:Size_1/TSL_1, ..., E_k:Size_k/TSL_k>></c>,
+ where each <c>Size_i</c> is an expression and each
+ <c>TSL_i</c> is a type specificer list, then Rep(E) =
+ <c>{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)}]}</c>.
For Rep(TSL), see below.
- An omitted <c>Size</c> is represented by <c>default</c>. An omitted <c>TSL</c>
- (type specifier list) is represented by <c>default</c>.</item>
- <item>If E is <c>E_1 Op E_2</c>, where <c>Op</c> is a binary operator,
- then Rep(E) = <c>{op,LINE,Op,Rep(E_1),Rep(E_2)}</c>.</item>
- <item>If E is <c>Op E_0</c>, where <c>Op</c> is a unary operator, then
- Rep(E) = <c>{op,LINE,Op,Rep(E_0)}</c>.</item>
- <item>If E is <c>#Name{Field_1=E_1, ..., Field_k=E_k}</c>,
- then Rep(E) =
- <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}</c>.</item>
- <item>If E is <c>E_0#Name{Field_1=E_1, ..., Field_k=E_k}</c>, then
- Rep(E) =
- <c>{record,LINE,Rep(E_0),Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}</c>.</item>
- <item>If E is <c>#Name.Field</c>, then
- Rep(E) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item>
- <item>If E is <c>E_0#Name.Field</c>, then
- Rep(E) = <c>{record_field,LINE,Rep(E_0),Name,Rep(Field)}</c>.</item>
- <item>If E is <c>#{W_1, ..., W_k}</c> where each
- <c>W_i</c> is a map assoc or exact field, then Rep(E) =
- <c>{map,LINE,[Rep(W_1), ..., Rep(W_k)]}</c>. For Rep(W), see
- below.</item>
- <item>If E is <c>E_0#{W_1, ..., W_k}</c> where
- <c>W_i</c> is a map assoc or exact field, then Rep(E) =
- <c>{map,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}</c>.
- For Rep(W), see below.</item>
- <item>If E is <c>catch E_0</c>, then
+ An omitted <c>Size_i</c> is represented by <c>default</c>.
+ An omitted <c>TSL_i</c> is represented by <c>default</c>.</item>
+ <item>If E is a block expression <c>begin B end</c>,
+ where <c>B</c> is a body, then
+ Rep(E) = <c>{block,LINE,Rep(B)}</c>.</item>
+ <item>If E is a case expression <c>case E_0 of Cc_1 ; ... ; Cc_k end</c>,
+ where <c>E_0</c> is an expression and each <c>Cc_i</c> is a
+ case clause then Rep(E) =
+ <c>{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item>
+ <item>If E is a catch expression <c>catch E_0</c>, then
Rep(E) = <c>{'catch',LINE,Rep(E_0)}</c>.</item>
- <item>If E is <c>E_0(E_1, ..., E_k)</c>, then
+ <item>If E is a cons skeleton <c>[E_h | E_t]</c>, then
+ Rep(E) = <c>{cons,LINE,Rep(E_h),Rep(E_t)}</c>.</item>
+ <item>If E is a fun expression <c>fun Name/Arity</c>, then
+ Rep(E) = <c>{'fun',LINE,{function,Name,Arity}}</c>.</item>
+ <item>If E is a fun expression
+ <c>fun Module:Name/Arity</c>, then Rep(E) =
+ <c>{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}}</c>.
+ (Before the R15 release: Rep(E) =
+ <c>{'fun',LINE,{function,Module,Name,Arity}}</c>.)</item>
+ <item>If E is a fun expression <c>fun Fc_1 ; ... ; Fc_k end</c>,
+ where each <c>Fc_i</c> is a function clause then Rep(E) =
+ <c>{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}</c>.</item>
+ <item>If E is a fun expression
+ <c>fun Name Fc_1 ; ... ; Name Fc_k end</c>,
+ where <c>Name</c> is a variable and each
+ <c>Fc_i</c> is a function clause then Rep(E) =
+ <c>{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]}</c>.
+ </item>
+ <item>If E is a function call <c>E_0(E_1, ..., E_k)</c>, then
Rep(E) = <c>{call,LINE,Rep(E_0),[Rep(E_1), ..., Rep(E_k)]}</c>.</item>
- <item>If E is <c>E_m:E_0(E_1, ..., E_k)</c>, then Rep(E) =
- <c>{call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]}</c>.
+ <item>If E is a function call <c>E_m:E_0(E_1, ..., E_k)</c>,
+ then Rep(E) =
+ <c>{call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]}</c>.
</item>
- <item>If E is a list comprehension <c>[E_0 || W_1, ..., W_k]</c>,
- where each <c>W_i</c> is a generator or a filter, then Rep(E) =
- <c>{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}</c>. For Rep(W), see
- below.</item>
- <item>If E is a binary comprehension
- <c>&lt;&lt;E_0 || W_1, ..., W_k>></c>,
- where each <c>W_i</c> is a generator or a filter, then
- Rep(E) = <c>{bc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}</c>.
- For Rep(W), see below.</item>
- <item>If E is <c>begin B end</c>, where <c>B</c> is a body, then
- Rep(E) = <c>{block,LINE,Rep(B)}</c>.</item>
- <item>If E is <c>if Ic_1 ; ... ; Ic_k end</c>,
+ <item>If E is an if expression <c>if Ic_1 ; ... ; Ic_k end</c>,
where each <c>Ic_i</c> is an if clause then Rep(E) =
<c>{'if',LINE,[Rep(Ic_1), ..., Rep(Ic_k)]}</c>.</item>
- <item>If E is <c>case E_0 of Cc_1 ; ... ; Cc_k end</c>,
- where <c>E_0</c> is an expression and each <c>Cc_i</c> is a
- case clause then Rep(E) =
- <c>{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item>
- <item>If E is <c>try B catch Tc_1 ; ... ; Tc_k end</c>,
+ <item>If E is a list comprehension <c>[E_0 || Q_1, ..., Q_k]</c>,
+ where each <c>Q_i</c> is a qualifier, then Rep(E) =
+ <c>{lc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}</c>. For Rep(Q), see
+ below.</item>
+ <item>If E is a map creation <c>#{A_1, ..., A_k}</c>,
+ where each <c>A_i</c> is an association <c>E_i_1 => E_i_2</c>
+ or <c>E_i_1 := E_i_2</c>, then Rep(E) =
+ <c>{map,LINE,[Rep(A_1), ..., Rep(A_k)]}</c>. For Rep(A), see
+ below.</item>
+ <item>If E is a map update <c>E_0#{A_1, ..., A_k}</c>,
+ where each <c>A_i</c> is an association <c>E_i_1 => E_i_2</c>
+ or <c>E_i_1 := E_i_2</c>, then Rep(E) =
+ <c>{map,LINE,Rep(E_0),[Rep(A_1), ..., Rep(A_k)]}</c>.
+ For Rep(A), see below.</item>
+ <item>If E is a match operator expression <c>P = E_0</c>,
+ where <c>P</c> is a pattern, then
+ Rep(E) = <c>{match,LINE,Rep(P),Rep(E_0)}</c>.</item>
+ <item>If E is nil, <c>[]</c>, then
+ Rep(E) = <c>{nil,LINE}</c>.</item>
+ <item>If E is an operator expression <c>E_1 Op E_2</c>,
+ where <c>Op</c> is a binary operator other than the match
+ operator <c>=</c>, then
+ Rep(E) = <c>{op,LINE,Op,Rep(E_1),Rep(E_2)}</c>.</item>
+ <item>If E is an operator expression <c>Op E_0</c>,
+ where <c>Op</c> is a unary operator, then
+ Rep(E) = <c>{op,LINE,Op,Rep(E_0)}</c>.</item>
+ <item>If E is a parenthesized expression <c>( E_0 )</c>, then
+ Rep(E) = <c>Rep(E_0)</c>, that is, parenthesized
+ expressions cannot be distinguished from their bodies.</item>
+ <item>If E is a receive expression <c>receive Cc_1 ; ... ; Cc_k end</c>,
+ where each <c>Cc_i</c> is a case clause then Rep(E) =
+ <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item>
+ <item>If E is a receive expression
+ <c>receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end</c>,
+ where each <c>Cc_i</c> is a case clause,
+ <c>E_0</c> is an expression and <c>B_t</c> is a body, then Rep(E) =
+ <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)}</c>.</item>
+ <item>If E is a record creation
+ <c>#Name{Field_1=E_1, ..., Field_k=E_k}</c>,
+ where each <c>Field_i</c> is an atom or <c>_</c>, then Rep(E) =
+ <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}</c>.</item>
+ <item>If E is a record field access <c>E_0#Name.Field</c>,
+ where <c>Field</c> is an atom, then
+ Rep(E) = <c>{record_field,LINE,Rep(E_0),Name,Rep(Field)}</c>.</item>
+ <item>If E is a record field index <c>#Name.Field</c>,
+ where <c>Field</c> is an atom, then
+ Rep(E) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item>
+ <item>If E is a record update
+ <c>E_0#Name{Field_1=E_1, ..., Field_k=E_k}</c>,
+ where each <c>Field_i</c> is an atom, then Rep(E) =
+ <c>{record,LINE,Rep(E_0),Name,[{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}</c>.</item>
+ <item>If E is a tuple skeleton <c>{E_1, ..., E_k}</c>, then
+ Rep(E) = <c>{tuple,LINE,[Rep(E_1), ..., Rep(E_k)]}</c>.</item>
+ <item>If E is a try expression <c>try B catch Tc_1 ; ... ; Tc_k end</c>,
where <c>B</c> is a body and each <c>Tc_i</c> is a catch clause then
Rep(E) =
<c>{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],[]}</c>.</item>
- <item>If E is <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end</c>,
+ <item>If E is a try expression
+ <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end</c>,
where <c>B</c> is a body,
each <c>Cc_i</c> is a case clause and
each <c>Tc_j</c> is a catch clause then Rep(E) =
<c>{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],[]}</c>.</item>
- <item>If E is <c>try B after A end</c>,
+ <item>If E is a try expression <c>try B after A end</c>,
where <c>B</c> and <c>A</c> are bodies then Rep(E) =
<c>{'try',LINE,Rep(B),[],[],Rep(A)}</c>.</item>
- <item>If E is <c>try B of Cc_1 ; ... ; Cc_k after A end</c>,
+ <item>If E is a try expression
+ <c>try B of Cc_1 ; ... ; Cc_k after A end</c>,
where <c>B</c> and <c>A</c> are a bodies and
each <c>Cc_i</c> is a case clause then Rep(E) =
<c>{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[],Rep(A)}</c>.</item>
- <item>If E is <c>try B catch Tc_1 ; ... ; Tc_k after A end</c>,
+ <item>If E is a try expression
+ <c>try B catch Tc_1 ; ... ; Tc_k after A end</c>,
where <c>B</c> and <c>A</c> are bodies and
each <c>Tc_i</c> is a catch clause then Rep(E) =
<c>{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],Rep(A)}</c>.</item>
- <item>If E is <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end</c>,
+ <item>If E is a try expression
+ <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end</c>,
where <c>B</c> and <c>A</c> are a bodies,
- each <c>Cc_i</c> is a case clause and
+ each <c>Cc_i</c> is a case clause, and
each <c>Tc_j</c> is a catch clause then
Rep(E) =
<c>{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],Rep(A)}</c>.</item>
- <item>If E is <c>receive Cc_1 ; ... ; Cc_k end</c>,
- where each <c>Cc_i</c> is a case clause then Rep(E) =
- <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item>
- <item>If E is <c>receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end</c>,
- where each <c>Cc_i</c> is a case clause,
- <c>E_0</c> is an expression and <c>B_t</c> is a body, then Rep(E) =
- <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)}</c>.</item>
- <item>If E is <c>fun Name / Arity</c>, then
- Rep(E) = <c>{'fun',LINE,{function,Name,Arity}}</c>.</item>
- <item>If E is <c>fun Module:Name/Arity</c>, then Rep(E) =
- <c>{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}}</c>.
- (Before the R15 release: Rep(E) =
- <c>{'fun',LINE,{function,Module,Name,Arity}}</c>.)</item>
- <item>If E is <c>fun Fc_1 ; ... ; Fc_k end</c>
- where each <c>Fc_i</c> is a function clause then Rep(E) =
- <c>{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}</c>.</item>
- <item>If E is <c>fun Name Fc_1 ; ... ; Name Fc_k end</c>
- where <c>Name</c> is a variable and each
- <c>Fc_i</c> is a function clause then Rep(E) =
- <c>{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]}</c>.
- </item>
- <item>If E is <c>( E_0 )</c>, then
- Rep(E) = <c>Rep(E_0)</c>, that is, parenthesized
- expressions cannot be distinguished from their bodies.</item>
+ <item>If E is a variable <c>V</c>, then Rep(E) = <c>{var,LINE,A}</c>,
+ where <c>A</c> is an atom with a printname consisting of the same
+ characters as <c>V</c>.</item>
</list>
<section>
- <title>Generators and Filters</title>
- <p>When W is a generator or a filter (in the body of a list or
- binary comprehension), then:</p>
+ <title>Qualifiers</title>
+ <p>A qualifier Q is one of the following alternatives:</p>
<list type="bulleted">
- <item>If W is a generator <c>P &lt;- E</c>, where <c>P</c> is
+ <item>If Q is a filter <c>E</c>, where <c>E</c> is an expression, then
+ Rep(Q) = <c>Rep(E)</c>.</item>
+ <item>If Q is a generator <c>P &lt;- E</c>, where <c>P</c> is
a pattern and <c>E</c> is an expression, then
- Rep(W) = <c>{generate,LINE,Rep(P),Rep(E)}</c>.</item>
- <item>If W is a generator <c>P &lt;= E</c>, where <c>P</c> is
+ Rep(Q) = <c>{generate,LINE,Rep(P),Rep(E)}</c>.</item>
+ <item>If Q is a generator <c>P &lt;= E</c>, where <c>P</c> is
a pattern and <c>E</c> is an expression, then
- Rep(W) = <c>{b_generate,LINE,Rep(P),Rep(E)}</c>.</item>
- <item>If W is a filter <c>E</c>, which is an expression, then
- Rep(W) = <c>Rep(E)</c>.</item>
+ Rep(Q) = <c>{b_generate,LINE,Rep(P),Rep(E)}</c>.</item>
</list>
</section>
<section>
<title>Binary Element Type Specifiers</title>
<p>A type specifier list TSL for a binary element is a sequence of type
- specifiers <c>TS_1 - ... - TS_k</c>.
+ specifiers <c>TS_1 - ... - TS_k</c>, and
Rep(TSL) = <c>[Rep(TS_1), ..., Rep(TS_k)]</c>.</p>
- <p>When TS is a type specifier for a binary element, then:</p>
<list type="bulleted">
- <item>If TS is an atom <c>A</c>, then Rep(TS) = <c>A</c>.</item>
- <item>If TS is a couple <c>A:Value</c> where <c>A</c> is an atom
- and <c>Value</c> is an integer, then Rep(TS) =
- <c>{A,Value}</c>.</item>
+ <item>If TS is a type specifier <c>A</c>, where <c>A</c> is an atom,
+ then Rep(TS) = <c>A</c>.</item>
+ <item>If TS is a type specifier <c>A:Value</c>,
+ where <c>A</c> is an atom and <c>Value</c> is an integer,
+ then Rep(TS) = <c>{A,Value}</c>.</item>
</list>
</section>
<section>
- <title>Map Assoc and Exact Fields</title>
- <p>When W is an assoc or exact field (in the body of a map), then:</p>
+ <title>Associations</title>
+ <p>An association A is one of the following alternatives:</p>
<list type="bulleted">
- <item>If W is an assoc field <c>K => V</c>, where
- <c>K</c> and <c>V</c> are both expressions,
- then Rep(W) = <c>{map_field_assoc,LINE,Rep(K),Rep(V)}</c>.
+ <item>If A is an association <c>K => V</c>,
+ then Rep(A) = <c>{map_field_assoc,LINE,Rep(K),Rep(V)}</c>.
</item>
- <item>If W is an exact field <c>K := V</c>, where
- <c>K</c> and <c>V</c> are both expressions,
- then Rep(W) = <c>{map_field_exact,LINE,Rep(K),Rep(V)}</c>.
+ <item>If A is an association <c>K := V</c>,
+ then Rep(A) = <c>{map_field_exact,LINE,Rep(K),Rep(V)}</c>.
</item>
</list>
</section>
@@ -393,39 +426,39 @@
and catch clauses.</p>
<p>A clause <c>C</c> is one of the following alternatives:</p>
<list type="bulleted">
- <item>If C is a function clause <c>( Ps ) -> B</c>
- where <c>Ps</c> is a pattern sequence and <c>B</c> is a body, then
- Rep(C) = <c>{clause,LINE,Rep(Ps),[],Rep(B)}</c>.</item>
- <item>If C is a function clause <c>( Ps ) when Gs -> B</c>
- where <c>Ps</c> is a pattern sequence,
- <c>Gs</c> is a guard sequence and <c>B</c> is a body, then
- Rep(C) = <c>{clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}</c>.</item>
- <item>If C is an if clause <c>Gs -> B</c>
- where <c>Gs</c> is a guard sequence and <c>B</c> is a body, then
- Rep(C) = <c>{clause,LINE,[],Rep(Gs),Rep(B)}</c>.</item>
- <item>If C is a case clause <c>P -> B</c>
+ <item>If C is a case clause <c>P -> B</c>,
where <c>P</c> is a pattern and <c>B</c> is a body, then
Rep(C) = <c>{clause,LINE,[Rep(P)],[],Rep(B)}</c>.</item>
- <item>If C is a case clause <c>P when Gs -> B</c>
+ <item>If C is a case clause <c>P when Gs -> B</c>,
where <c>P</c> is a pattern,
<c>Gs</c> is a guard sequence and <c>B</c> is a body, then
Rep(C) = <c>{clause,LINE,[Rep(P)],Rep(Gs),Rep(B)}</c>.</item>
- <item>If C is a catch clause <c>P -> B</c>
+ <item>If C is a catch clause <c>P -> B</c>,
where <c>P</c> is a pattern and <c>B</c> is a body, then
Rep(C) = <c>{clause,LINE,[Rep({throw,P,_})],[],Rep(B)}</c>.</item>
- <item>If C is a catch clause <c>X : P -> B</c>
+ <item>If C is a catch clause <c>X : P -> B</c>,
where <c>X</c> is an atomic literal or a variable pattern,
- <c>P</c> is a pattern and <c>B</c> is a body, then
+ <c>P</c> is a pattern, and <c>B</c> is a body, then
Rep(C) = <c>{clause,LINE,[Rep({X,P,_})],[],Rep(B)}</c>.</item>
- <item>If C is a catch clause <c>P when Gs -> B</c>
- where <c>P</c> is a pattern, <c>Gs</c> is a guard sequence
+ <item>If C is a catch clause <c>P when Gs -> B</c>,
+ where <c>P</c> is a pattern, <c>Gs</c> is a guard sequence,
and <c>B</c> is a body, then
Rep(C) = <c>{clause,LINE,[Rep({throw,P,_})],Rep(Gs),Rep(B)}</c>.</item>
- <item>If C is a catch clause <c>X : P when Gs -> B</c>
+ <item>If C is a catch clause <c>X : P when Gs -> B</c>,
where <c>X</c> is an atomic literal or a variable pattern,
- <c>P</c> is a pattern, <c>Gs</c> is a guard sequence
+ <c>P</c> is a pattern, <c>Gs</c> is a guard sequence,
and <c>B</c> is a body, then
Rep(C) = <c>{clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)}</c>.</item>
+ <item>If C is a function clause <c>( Ps ) -> B</c>,
+ where <c>Ps</c> is a pattern sequence and <c>B</c> is a body, then
+ Rep(C) = <c>{clause,LINE,Rep(Ps),[],Rep(B)}</c>.</item>
+ <item>If C is a function clause <c>( Ps ) when Gs -> B</c>,
+ where <c>Ps</c> is a pattern sequence,
+ <c>Gs</c> is a guard sequence and <c>B</c> is a body, then
+ Rep(C) = <c>{clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}</c>.</item>
+ <item>If C is an if clause <c>Gs -> B</c>,
+ where <c>Gs</c> is a guard sequence and <c>B</c> is a body, then
+ Rep(C) = <c>{clause,LINE,[],Rep(Gs),Rep(B)}</c>.</item>
</list>
</section>
@@ -439,46 +472,61 @@
<c>[Rep(Gt_1), ..., Rep(Gt_k)]</c>.</p>
<p>A guard test <c>Gt</c> is one of the following alternatives:</p>
<list type="bulleted">
- <item>If Gt is an atomic literal L, then Rep(Gt) = Rep(L).</item>
- <item>If Gt is a variable pattern <c>V</c>, then
- Rep(Gt) = <c>{var,LINE,A}</c>, where A is an atom with
- a printname consisting of the same characters as <c>V</c>.</item>
- <item>If Gt is a tuple skeleton <c>{Gt_1, ..., Gt_k}</c>, then
- Rep(Gt) = <c>{tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item>
- <item>If Gt is <c>[]</c>, then Rep(Gt) = <c>{nil,LINE}</c>.</item>
- <item>If Gt is a cons skeleton <c>[Gt_h | Gt_t]</c>, then
- Rep(Gt) = <c>{cons,LINE,Rep(Gt_h),Rep(Gt_t)}</c>.</item>
+ <item>If Gt is an atomic literal <c>L</c>, then Rep(Gt) = Rep(L).</item>
<item>If Gt is a binary constructor
- <c>&lt;&lt;Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>></c>, then
+ <c>&lt;&lt;Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>></c>,
+ where each <c>Size_i</c> is a guard test and each
+ <c>TSL_i</c> is a type specificer list, then
Rep(Gt) = <c>{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)}]}</c>.
For Rep(TSL), see above.
- An omitted <c>Size</c> is represented by <c>default</c>.
- An omitted <c>TSL</c> (type specifier list) is represented
- by <c>default</c>.</item>
- <item>If Gt is <c>Gt_1 Op Gt_2</c>, where <c>Op</c>
- is a binary operator, then Rep(Gt) =
- <c>{op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}</c>.</item>
- <item>If Gt is <c>Op Gt_0</c>, where <c>Op</c> is a unary operator, then
+ An omitted <c>Size_i</c> is represented by <c>default</c>.
+ An omitted <c>TSL_i</c> is represented by <c>default</c>.</item>
+ <item>If Gt is a cons skeleton <c>[Gt_h | Gt_t]</c>, then
+ Rep(Gt) = <c>{cons,LINE,Rep(Gt_h),Rep(Gt_t)}</c>.</item>
+ <item>If Gt is a function call <c>A(Gt_1, ..., Gt_k)</c>,
+ where <c>A</c> is an atom, then Rep(Gt) =
+ <c>{call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item>
+ <item>If Gt is a function call <c>A_m:A(Gt_1, ..., Gt_k)</c>,
+ where <c>A_m</c> is the atom <c>erlang</c> and <c>A</c> is
+ an atom or an operator, then Rep(Gt) =
+ <c>{call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item>
+ <item>If Gt is a map creation <c>#{A_1, ..., A_k}</c>,
+ where each <c>A_i</c> is an association <c>Gt_i_1 => Gt_i_2</c>
+ or <c>Gt_i_1 := Gt_i_2</c>, then Rep(Gt) =
+ <c>{map,LINE,[Rep(A_1), ..., Rep(A_k)]}</c>. For Rep(A), see
+ above.</item>
+ <item>If Gt is a map update <c>Gt_0#{A_1, ..., A_k}</c>, where each
+ <c>A_i</c> is an association <c>Gt_i_1 => Gt_i_2</c>
+ or <c>Gt_i_1 := Gt_i_2</c>, then Rep(Gt) =
+ <c>{map,LINE,Rep(Gt_0),[Rep(A_1), ..., Rep(A_k)]}</c>.
+ For Rep(A), see above.</item>
+ <item>If Gt is nil, <c>[]</c>,
+ then Rep(Gt) = <c>{nil,LINE}</c>.</item>
+ <item>If Gt is an operator guard test <c>Gt_1 Op Gt_2</c>,
+ where <c>Op</c> is a binary operator other than the match
+ operator <c>=</c>, then
+ Rep(Gt) = <c>{op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}</c>.</item>
+ <item>If Gt is an operator guard test <c>Op Gt_0</c>,
+ where <c>Op</c> is a unary operator, then
Rep(Gt) = <c>{op,LINE,Op,Rep(Gt_0)}</c>.</item>
- <item>If Gt is <c>#Name{Field_1=Gt_1, ..., Field_k=Gt_k}</c>, then
- Rep(E) =
- <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(Gt_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(Gt_k)}]}</c>.</item>
- <item>If Gt is <c>#Name.Field</c>, then
- Rep(Gt) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item>
- <item>If Gt is <c>Gt_0#Name.Field</c>, then
- Rep(Gt) = <c>{record_field,LINE,Rep(Gt_0),Name,Rep(Field)}</c>.</item>
- <item>If Gt is <c>A(Gt_1, ..., Gt_k)</c>, where <c>A</c> is an atom, then
- Rep(Gt) = <c>{call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item>
- <item>If Gt is <c>A_m:A(Gt_1, ..., Gt_k)</c>, where <c>A_m</c> is
- the atom <c>erlang</c> and <c>A</c> is an atom or an operator, then
- Rep(Gt) = <c>{call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item>
- <item>If Gt is <c>{A_m,A}(Gt_1, ..., Gt_k)</c>, where <c>A_m</c> is
- the atom <c>erlang</c> and <c>A</c> is an atom or an operator, then
- Rep(Gt) = <c>{call,LINE,Rep({A_m,A}),[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.
- </item>
- <item>If Gt is <c>( Gt_0 )</c>, then
+ <item>If Gt is a parenthesized guard test <c>( Gt_0 )</c>, then
Rep(Gt) = <c>Rep(Gt_0)</c>, that is, parenthesized
guard tests cannot be distinguished from their bodies.</item>
+ <item>If Gt is a record creation
+ <c>#Name{Field_1=Gt_1, ..., Field_k=Gt_k}</c>,
+ where each <c>Field_i</c> is an atom or <c>_</c>, then Rep(Gt) =
+ <c>{record,LINE,Name,[{record_field,LINE,Rep(Field_1),Rep(Gt_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(Gt_k)}]}</c>.</item>
+ <item>If Gt is a record field access <c>Gt_0#Name.Field</c>,
+ where <c>Field</c> is an atom, then
+ Rep(Gt) = <c>{record_field,LINE,Rep(Gt_0),Name,Rep(Field)}</c>.</item>
+ <item>If Gt is a record field index <c>#Name.Field</c>,
+ where <c>Field</c> is an atom, then
+ Rep(Gt) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item>
+ <item>If Gt is a tuple skeleton <c>{Gt_1, ..., Gt_k}</c>, then
+ Rep(Gt) = <c>{tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item>
+ <item>If Gt is a variable pattern <c>V</c>, then
+ Rep(Gt) = <c>{var,LINE,A}</c>, where A is an atom with
+ a printname consisting of the same characters as <c>V</c>.</item>
</list>
<p>Note that every guard test has the same source form as some expression,
and is represented the same way as the corresponding expression.</p>
@@ -487,21 +535,11 @@
<section>
<title>Types</title>
<list type="bulleted">
- <item>If T is an annotated type <c>Anno :: Type</c>,
- where <c>Anno</c> is a variable and
- <c>Type</c> is a type, then Rep(T) =
- <c>{ann_type,LINE,[Rep(Anno),Rep(Type)]}</c>.</item>
+ <item>If T is an annotated type <c>A :: T_0</c>,
+ where <c>A</c> is a variable, then Rep(T) =
+ <c>{ann_type,LINE,[Rep(A),Rep(T_0)]}</c>.</item>
<item>If T is an atom or integer literal L, then Rep(T) = Rep(L).
</item>
- <item>If T is <c>L Op R</c>,
- where <c>Op</c> is a binary operator and <c>L</c> and <c>R</c>
- are types (this is an occurrence of an expression that can be
- evaluated to an integer at compile time), then
- Rep(T) = <c>{op,LINE,Op,Rep(L),Rep(R)}</c>.</item>
- <item>If T is <c>Op A</c>, where <c>Op</c> is a
- unary operator and <c>A</c> is a type (this is an occurrence of
- an expression that can be evaluated to an integer at compile time),
- then Rep(T) = <c>{op,LINE,Op,Rep(A)}</c>.</item>
<item>If T is a bitstring type <c>&lt;&lt;_:M,_:_*N>></c>,
where <c>M</c> and <c>N</c> are singleton integer types, then Rep(T) =
<c>{type,LINE,binary,[Rep(M),Rep(N)]}</c>.</item>
@@ -509,69 +547,71 @@
<c>{type,Line,nil,[]}</c>.</item>
<item>If T is a fun type <c>fun()</c>, then Rep(T) =
<c>{type,LINE,'fun',[]}</c>.</item>
- <item>If T is a fun type <c>fun((...) -> B)</c>,
- where <c>B</c> is a type, then
- Rep(T) = <c>{type,LINE,'fun',[{type,LINE,any},Rep(B)]}</c>.
+ <item>If T is a fun type <c>fun((...) -> T_0)</c>, then
+ Rep(T) = <c>{type,LINE,'fun',[{type,LINE,any},Rep(T_0)]}</c>.
</item>
<item>If T is a fun type <c>fun(Ft)</c>, where
<c>Ft</c> is a function type,
- then Rep(T) = <c>Rep(Ft)</c>.</item>
+ then Rep(T) = <c>Rep(Ft)</c>. For Rep(Ft), see below.</item>
<item>If T is an integer range type <c>L .. H</c>,
where <c>L</c> and <c>H</c> are singleton integer types, then
Rep(T) = <c>{type,LINE,range,[Rep(L),Rep(H)]}</c>.</item>
<item>If T is a map type <c>map()</c>, then Rep(T) =
<c>{type,LINE,map,any}</c>.</item>
- <item>If T is a map type <c>#{P_1, ..., P_k}</c>, where each
- <c>P_i</c> is a map pair type, then Rep(T) =
- <c>{type,LINE,map,[Rep(P_1), ..., Rep(P_k)]}</c>.</item>
- <item>If T is a map pair type <c>K => V</c>, where
- <c>K</c> and <c>V</c> are types, then Rep(T) =
- <c>{type,LINE,map_field_assoc,[Rep(K),Rep(V)]}</c>.</item>
- <item>If T is a predefined (or built-in) type <c>N(A_1, ..., A_k)</c>,
- where each <c>A_i</c> is a type, then Rep(T) =
- <c>{type,LINE,N,[Rep(A_1), ..., Rep(A_k)]}</c>.</item>
+ <item>If T is a map type <c>#{A_1, ..., A_k}</c>, where each
+ <c>A_i</c> is an association type, then Rep(T) =
+ <c>{type,LINE,map,[Rep(A_1), ..., Rep(A_k)]}</c>.
+ For Rep(A), see below.</item>
+ <item>If T is an operator type <c>T_1 Op T_2</c>,
+ where <c>Op</c> is a binary operator (this is an occurrence of
+ an expression that can be evaluated to an integer at compile
+ time), then
+ Rep(T) = <c>{op,LINE,Op,Rep(T_1),Rep(T_2)}</c>.</item>
+ <item>If T is an operator type <c>Op T_0</c>, where <c>Op</c> is a
+ unary operator (this is an occurrence of
+ an expression that can be evaluated to an integer at compile time),
+ then Rep(T) = <c>{op,LINE,Op,Rep(T_0)}</c>.</item>
+ <item>If T is <c>( T_0 )</c>, then Rep(T) = <c>Rep(T_0)</c>,
+ that is, parenthesized types cannot be distinguished from their
+ bodies.</item>
+ <item>If T is a predefined (or built-in) type <c>N(T_1, ..., T_k)</c>,
+ then Rep(T) =
+ <c>{type,LINE,N,[Rep(T_1), ..., Rep(T_k)]}</c>.</item>
<item>If T is a record type <c>#Name{F_1, ..., F_k}</c>,
where each <c>F_i</c> is a record field type, then Rep(T) =
<c>{type,LINE,record,[Rep(Name),Rep(F_1), ..., Rep(F_k)]}</c>.
- </item>
- <item>If T is a record field type <c>Name :: Type</c>,
- where <c>Type</c> is a type, then Rep(T) =
- <c>{type,LINE,field_type,[Rep(Name),Rep(Type)]}</c>.</item>
- <item>If T is a remote type <c>M:N(A_1, ..., A_k)</c>, where
- each <c>A_i</c> is a type, then Rep(T) =
- <c>{remote_type,LINE,[Rep(M),Rep(N),[Rep(A_1), ..., Rep(A_k)]]}</c>.
+ For Rep(F), see below.</item>
+ <item>If T is a remote type <c>M:N(T_1, ..., T_k)</c>, then Rep(T) =
+ <c>{remote_type,LINE,[Rep(M),Rep(N),[Rep(T_1), ..., Rep(T_k)]]}</c>.
</item>
<item>If T is a tuple type <c>tuple()</c>, then Rep(T) =
<c>{type,LINE,tuple,any}</c>.</item>
- <item>If T is a tuple type <c>{A_1, ..., A_k}</c>, where
- each <c>A_i</c> is a type, then Rep(T) =
- <c>{type,LINE,tuple,[Rep(A_1), ..., Rep(A_k)]}</c>.</item>
- <item>If T is a type union <c>T_1 | ... | T_k</c>,
- where each <c>T_i</c> is a type, then Rep(T) =
+ <item>If T is a tuple type <c>{T_1, ..., T_k}</c>, then Rep(T) =
+ <c>{type,LINE,tuple,[Rep(T_1), ..., Rep(T_k)]}</c>.</item>
+ <item>If T is a type union <c>T_1 | ... | T_k</c>, then Rep(T) =
<c>{type,LINE,union,[Rep(T_1), ..., Rep(T_k)]}</c>.</item>
<item>If T is a type variable <c>V</c>, then Rep(T) =
<c>{var,LINE,A}</c>, where <c>A</c> is an atom with a printname
consisting of the same characters as <c>V</c>. A type variable
is any variable except underscore (<c>_</c>).</item>
- <item>If T is a user-defined type <c>N(A_1, ..., A_k)</c>,
- where each <c>A_i</c> is a type, then Rep(T) =
- <c>{user_type,LINE,N,[Rep(A_1), ..., Rep(A_k)]}</c>.</item>
- <item>If T is <c>( T_0 )</c>, then Rep(T) = <c>Rep(T_0)</c>,
- that is, parenthesized types cannot be distinguished from their
- bodies.</item>
+ <item>If T is a user-defined type <c>N(T_1, ..., T_k)</c>,
+ then Rep(T) =
+ <c>{user_type,LINE,N,[Rep(T_1), ..., Rep(T_k)]}</c>.</item>
</list>
<section>
<title>Function Types</title>
+ <p>A function type Ft is one of the following alternatives:</p>
<list type="bulleted">
<item>If Ft is a constrained function type <c>Ft_1 when Fc</c>,
where <c>Ft_1</c> is a function type and
<c>Fc</c> is a function constraint, then Rep(T) =
- <c>{type,LINE,bounded_fun,[Rep(Ft_1),Rep(Fc)]}</c>.</item>
- <item>If Ft is a function type <c>(A_1, ..., A_n) -> B</c>,
- where each <c>A_i</c> and <c>B</c> are types, then
- Rep(Ft) = <c>{type,LINE,'fun',[{type,LINE,product,[Rep(A_1),
- ..., Rep(A_n)]},Rep(B)]}</c>.</item>
+ <c>{type,LINE,bounded_fun,[Rep(Ft_1),Rep(Fc)]}</c>.
+ For Rep(Fc), see below.</item>
+ <item>If Ft is a function type <c>(T_1, ..., T_n) -> T_0</c>,
+ where each <c>T_i</c> is a type, then
+ Rep(Ft) = <c>{type,LINE,'fun',[{type,LINE,product,[Rep(T_1),
+ ..., Rep(T_n)]},Rep(T_0)]}</c>.</item>
</list>
</section>
@@ -587,6 +627,24 @@
</item>
</list>
</section>
+
+ <section>
+ <title>Association Types</title>
+ <list type="bulleted">
+ <item>If A is an association type <c>K => V</c>, where
+ <c>K</c> and <c>V</c> are types, then Rep(A) =
+ <c>{type,LINE,map_field_assoc,[Rep(K),Rep(V)]}</c>.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Record Field Types</title>
+ <list type="bulleted">
+ <item>If F is a record field type <c>Name :: Type</c>,
+ where <c>Type</c> is a type, then Rep(F) =
+ <c>{type,LINE,field_type,[Rep(Name),Rep(Type)]}</c>.</item>
+ </list>
+ </section>
</section>
<section>
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) ->
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()}.
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()).
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 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2015</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -44,21 +44,33 @@
</description>
<datatypes>
<datatype>
- <name name="abstract_clause"></name>
- <desc><p>Parse tree for Erlang clause.</p>
+ <name>abstract_clause()</name>
+ <desc><p><marker id="type-abstract_clause"/>
+ Abstract form of an Erlang clause.</p>
</desc>
</datatype>
<datatype>
- <name name="abstract_expr"></name>
- <desc><p>Parse tree for Erlang expression.</p>
+ <name>abstract_expr()</name>
+ <desc><p><marker id="type-abstract_expr"/>
+ Abstract form of an Erlang expression.</p>
</desc>
</datatype>
<datatype>
- <name name="abstract_form"></name>
- <desc><p>Parse tree for Erlang form.</p>
+ <name>abstract_form()</name>
+ <desc><p><marker id="type-abstract_form"/>
+ Abstract form of an Erlang form.</p>
</desc>
</datatype>
<datatype>
+ <name>abstract_type()</name>
+ <desc><p><marker id="type-abstract_type"/>
+ Abstract form of an Erlang type.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="erl_parse_tree"></name>
+ </datatype>
+ <datatype>
<name name="error_description"></name>
</datatype>
<datatype>
@@ -180,7 +192,7 @@
<p>Converts the Erlang data structure <c><anno>Data</anno></c> into an
abstract form of type <c><anno>AbsTerm</anno></c>.</p>
<p>The <c><anno>Line</anno></c> option is the line that will
- be assigned to each node of the abstract form.</p>
+ be assigned to each node of <c><anno>AbsTerm</anno></c>.</p>
<p>The <c><anno>Encoding</anno></c> 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 @@
<func>
<name name="map_anno" arity="2"/>
<fsummary>
- Map a function over the annotations of an abstract form
+ Map a function over the annotations of a <c>erl_parse</c> tree
</fsummary>
<desc>
- <p>Modifies the abstract form <anno>Abstr</anno> by applying
- <anno>Fun</anno> on every collection of annotations of the
- abstract form. The abstract form is traversed in a
- depth-first, left-to-right, fashion.
+ <p>Modifies the <c>erl_parse</c> tree <c><anno>Abstr</anno></c>
+ by applying <c><anno>Fun</anno></c> on each collection of
+ annotations of the nodes of the <c>erl_parse</c> tree. The
+ <c>erl_parse</c> tree is traversed in a depth-first,
+ left-to-right, fashion.
</p>
</desc>
</func>
<func>
<name name="fold_anno" arity="3"/>
<fsummary>
- Fold a function over the annotations of an abstract form
+ Fold a function over the annotations of a <c>erl_parse</c> tree
</fsummary>
<desc>
- <p>Updates an accumulator by applying <anno>Fun</anno> on
- every collection of annotations of the abstract form
- <anno>Abstr</anno>. The first call to <anno>Fun</anno> has
- <anno>AccIn</anno> as argument, and the returned accumulator
- <anno>AccOut</anno> 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.
+ <p>Updates an accumulator by applying <c><anno>Fun</anno></c> on
+ each collection of annotations of the <c>erl_parse</c> tree
+ <c><anno>Abstr</anno></c>. The first call to
+ <c><anno>Fun</anno></c> has <c><anno>AccIn</anno></c> as
+ argument, and the returned accumulator
+ <c><anno>AccOut</anno></c> is passed to the next call, and
+ so on. The final value of the accumulator is returned. The
+ <c>erl_parse</c> tree is traversed in a depth-first, left-to-right,
+ fashion.
</p>
</desc>
</func>
<func>
<name name="mapfold_anno" arity="3"/>
<fsummary>
- Map and fold a function over the annotations of an abstract form
+ Map and fold a function over the annotations of a
+ <c>erl_parse</c> tree
</fsummary>
<desc>
- <p>Modifies the abstract form <anno>Abstr</anno> by applying
- <anno>Fun</anno> on every collection of annotations of the
- abstract form, while at the same time updating an
- accumulator. The first call to <anno>Fun</anno> has
- <anno>AccIn</anno> as second argument, and the returned
- accumulator <anno>AccOut</anno> 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.
+ <p>Modifies the <c>erl_parse</c> tree <c><anno>Abstr</anno></c>
+ by applying <c><anno>Fun</anno></c> on each collection of
+ annotations of the nodes of the <c>erl_parse</c> tree, while
+ at the same time updating an accumulator. The first call to
+ <c><anno>Fun</anno></c> has <c><anno>AccIn</anno></c> as
+ second argument, and the returned accumulator
+ <c><anno>AccOut</anno></c> is passed to the next call, and
+ so on. The modified <c>erl_parse</c> tree as well as the the
+ final value of the accumulator are returned. The
+ <c>erl_parse</c> tree is traversed in a depth-first,
+ left-to-right, fashion.
</p>
</desc>
</func>
@@ -246,12 +264,15 @@
Create new annotations
</fsummary>
<desc>
- <p>Creates an abstract form from a term which has the same
- structure as an abstract form, but <seealso
- marker="erl_anno#type-location">locations</seealso> where the
- abstract form has annotations. For each location, <seealso
- marker="erl_anno#new/1"><c>erl_anno:new/1</c></seealso> is
- called, and the annotations replace the location.
+ <p>Assumes that <c><anno>Term</anno></c> is a term with the same
+ structure as a <c>erl_parse</c> tree, but with <seealso
+ marker="erl_anno#type-location">locations</seealso> where a
+ <c>erl_parse</c> tree has collections of annotations.
+ Returns a <c>erl_parse</c> tree where each location <c>L</c>
+ has been replaced by the value returned by <seealso
+ marker="erl_anno#new/1"><c>erl_anno:new(L)</c></seealso>.
+ The term <c><anno>Term</anno></c> is traversed in a
+ depth-first, left-to-right, fashion.
</p>
</desc>
</func>
@@ -261,12 +282,14 @@
Return annotations as terms
</fsummary>
<desc>
- <p>Assumes that <anno>Term</anno> 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 calling <c>erl_anno:from_term(T)</c>. The
- term <anno>Term</anno> is traversed in a depth-first,
+ <p>Assumes that <c><anno>Term</anno></c> is a term with the same
+ structure as a <c>erl_parse</c> tree, but with terms,
+ <c>T</c> say, where a <c>erl_parse</c> tree has collections
+ of annotations. Returns a <c>erl_parse</c> tree where each
+ term <c>T</c> has been replaced by the value returned by
+ <seealso marker="erl_anno#from_term/1">
+ <c>erl_anno:from_term(T)</c></seealso>. The term
+ <c><anno>Term</anno></c> is traversed in a depth-first,
left-to-right, fashion.
</p>
</desc>
@@ -277,10 +300,13 @@
Return the representation of annotations
</fsummary>
<desc>
- <p>Returns a term where every collection of annotations Anno of
- <anno>Abstr</anno> has been replaced by the term returned by
- calling <c>erl_anno:to_term(Anno)</c>. The abstract form is
- traversed in a depth-first, left-to-right, fashion.
+ <p>Returns a term where each collection of annotations
+ <c>Anno</c> of the nodes of the <c>erl_parse</c> tree
+ <c><anno>Abstr</anno></c> has been replaced by the term
+ returned by <seealso marker="erl_anno#to_term/1">
+ <c>erl_anno:to_term(Anno)</c></seealso>. The
+ <c>erl_parse</c> tree is traversed in a depth-first,
+ left-to-right, fashion.
</p>
</desc>
</func>
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 e07ab2efc2..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.
@@ -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().
@@ -1083,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,
@@ -1100,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,
@@ -1115,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/io.erl b/lib/stdlib/src/io.erl
index 5dc8b4541e..f510f61e9f 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -444,7 +444,7 @@ scan_erl_form(Io, Prompt, Pos0, Options) ->
%% Parsing Erlang code.
-type parse_ret() :: {'ok',
- ExprList :: erl_parse:abstract_expr(),
+ ExprList :: [erl_parse:abstract_expr()],
EndLocation :: location()}
| {'eof', EndLocation :: location()}
| {'error',
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)).
diff --git a/lib/syntax_tools/src/erl_recomment.erl b/lib/syntax_tools/src/erl_recomment.erl
index 72e1e2d2f5..5ce533285d 100644
--- a/lib/syntax_tools/src/erl_recomment.erl
+++ b/lib/syntax_tools/src/erl_recomment.erl
@@ -611,12 +611,15 @@ expand_comment(C) ->
attrs :: erl_syntax:syntaxTreeAttributes(),
precomments = [] :: [erl_syntax:syntaxTree()],
postcomments = [] :: [erl_syntax:syntaxTree()],
- subtrees = [] :: [erl_syntax:syntaxTree()]}).
+ subtrees = [] :: [extendedSyntaxTree()]}).
+
-record(list, {min = 0 :: integer(),
max = 0 :: integer(),
subtrees = [] :: [erl_syntax:syntaxTree()]}).
+-type extendedSyntaxTree() :: #tree{} | #leaf{} | #list{}.
+
leaf_node(Min, Max, Value) ->
#leaf{min = Min,
max = Max,
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index 893398b71b..e98fcbcbb9 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -245,13 +245,13 @@ lists:keysearch(Name, 1, List)</code>
handle(Msg, State)
spawn(m, init, [])</code>
<p><em>Examples</em> where <c>ExprF</c> is a fun:</p>
- <code type="none">
-Fun1 = fun(X) -> X+1 end
-Fun1(3)
-=> 4
-
-fun lists:append/2([1,2], [3,4])
-=> [1,2,3,4]</code>
+ <pre>
+1> <input>Fun1 = fun(X) -> X+1 end,</input>
+<input>Fun1(3).</input>
+4
+2> <input>fun lists:append/2([1,2], [3,4]).</input>
+[1,2,3,4]
+3> </pre>
<p>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`.</code>
</p>
<list>
<item><p>A <c>badmatch</c> exception.</p>
- <p>This is if it is used in the context of the matching operator
+ <p>This is if it is used in the context of the match operator
as in the example.</p>
</item>
<item><p>Or resulting in the next clause being tested in function heads and
@@ -1085,7 +1085,7 @@ Ei = Value |
<p>Used in a bit string construction, <c>Value</c> is an expression
that is to evaluate to an integer, float, or bit string. If the
expression is not a single literal or variable, it
- is to be enclosed in parenthesis.</p>
+ is to be enclosed in parentheses.</p>
<p>Used in a bit string matching, <c>Value</c> must be a variable,
or an integer, float, or string.</p>
@@ -1319,7 +1319,7 @@ catch Expr</code>
{'EXIT',{badarith,[...]}}</pre>
<p>Notice that <c>catch</c> has low precedence and catch
subexpressions often needs to be enclosed in a block
- expression or in parenthesis:</p>
+ expression or in parentheses:</p>
<pre>
3> <input>A = catch 1+2.</input>
** 1: syntax error before: 'catch' **