From e5875001247e6a6ac4f474157a51a8c54f94ae49 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 14 Mar 2013 16:01:25 +0100 Subject: Convert XML files to UTF-8 --- erts/doc/src/absform.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index e512c19e05..55aef9f8ab 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -1,4 +1,4 @@ - + -- cgit v1.2.3 From a929df291877df45c93303d22995bbbebf6a2c45 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 12 Nov 2012 10:07:37 +0100 Subject: Document named fun expressions --- erts/doc/src/absform.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 55aef9f8ab..4acc03b133 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -290,6 +290,18 @@ If E is where each is a function clause then Rep(E) = . + If E is + where is a variable and each + is a function clause then Rep(E) = + . + + If E is , + where each is a generator or a filter, then + Rep(E) = . + For Rep(W), see below. + If E is , a Mnesia record access + inside a query, then + Rep(E) = . If E is , then Rep(E) = , i.e., parenthesized expressions cannot be distinguished from their bodies. -- cgit v1.2.3 From e5ccb57c0e45535d4b2b34cc85b177056b67b2da Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 31 Jan 2014 20:09:44 +0100 Subject: Document maps-related abstract syntax trees {map,Loc,Fields} {map,Loc,Argument,Fields} {map_field_assoc,Loc,Name,Value} {map_field_exact,Loc,Name,Value} --- erts/doc/src/absform.xml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 4acc03b133..835a4fc692 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -217,6 +217,14 @@ Rep(E) = . If E is , then Rep(E) = . + If E is where each + is a map assoc or exact field, then Rep(E) = + . For Rep(W), see + below. + If E is where + is a map assoc or exact field, then Rep(E) = + . For + Rep(W), see below. If E is , then Rep(E) = . If E is , then @@ -334,6 +342,21 @@ is an integer, Rep(TS) = . + +
+ Map assoc and exact fields +

When W is an assoc or exact field (in the body of a map), then:

+ + If W is an assoc field V]]>, where + and are both expressions, + then Rep(W) = . + + If W is an exact field , where + and are both expressions, + then Rep(W) = . + + +
-- cgit v1.2.3 From d1fbf82a0a43f91e2bbf95060dc09a1573e487c2 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 8 Feb 2014 01:39:57 +0100 Subject: Document abstract format of type-related trees --- erts/doc/src/absform.xml | 163 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 835a4fc692..12cb06c151 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -80,6 +80,28 @@ If F is a record declaration , then Rep(F) = . For Rep(V), see below. + If F is a type attribute (i.e. or + ) + where each + is a variable, then Rep(F) = + . + For Rep(T), see below. + If F is a type spec (i.e. or + ) + , + where each is a fun type clause with an + argument sequence of the same length , then + Rep(F) = + . + For Rep(Tc_i), see below. + If F is a type spec (i.e. or + ) + , + where each is a fun type clause with an + argument sequence of the same length , then + Rep(F) = + . + For Rep(Tc_i), see below. If F is a wild attribute , then Rep(F) = .

@@ -89,6 +111,132 @@ Rep(F) = . +
+ Type clauses + + If T is a fun type clause + Ret]]>, where each + and are types, then + Rep(T) = + . + + If T is a bounded fun type clause , + where is an unbounded fun type clause and + is a type guard sequence, then Rep(T) = + . + +
+ +
+ Type guards + + If G is a constraint , where + is an atom and each is a + type, then Rep(G) = + . + + If G is a type definition , + where is a variable and + is a type, then Rep(G) = + . + +
+ +
+ Types + + If T is a type definition , + where is a variable and + is a type, then Rep(T) = + . + If T is a type union , + where each is a type, then Rep(T) = + . + If T is a type range , + where and are types, then + Rep(T) = . + If T is a binary operation , + where is an arithmetic or bitwise binary operator + and and are types, then + Rep(T) = . + If T is , where is an + arithmetic or bitwise unary operator and is a + type, then Rep(T) = . + If T is a fun type , then Rep(T) = + . + If T is a parenthesized type , then + Rep(T) = , i.e. parenthesized + types are distinguished from their bodies. It should be noted though + that parenthesized types that are immediate subtrees of operator + expressions and binary types are peeled off. + If T is a variable , then Rep(T) = + , where is an atom + with a printname consisting of the same characters as + . + If T is an atomic literal L and L is not a string literal, then + Rep(T) = Rep(L). + If T is a tuple or map type (i.e. + or ), then Rep(T) = + . + If T is a type , where each + is a type, then Rep(T) = + . + If T is a remote type , where + each is a type and and + , then Rep(T) = + . + + If T is the nil type , then Rep(T) = + . + If T is a list type , where + is a type, then Rep(T) = + . + If T is a non-empty list type , where + is a type, then Rep(T) = + . + If T is a map type , where each + is a map pair type, then Rep(T) = + . + If T is a map pair type V]]>, where + and are types, + then Rep(T) = + . + If T is a tuple type , where + each is a type, then Rep(T) = + . + If T is a record type , where + is an atom, then Rep(T) = + . + If T is a record type , + where is an atom, then Rep(T) = + . + + If T is a record field type , + where is an atom, then Rep(T) = + . + If T is a record field type >]]>, then Rep(T) = + . + + If T is a binary type >]]>, where + is a type, then Rep(T) = + . + If T is a binary type >]]>, + where is a type, then Rep(T) = + . + If T is a binary type >]]>, + where and is a type, then + Rep(T) = + . + + If T is a fun type Ret)]]>, then + Rep(T) = . + + If T is a fun type , where + is an unbounded fun type clause, + then Rep(T) = . + +
+
Record fields

Each field in a record declaration may have an optional @@ -98,6 +246,21 @@ Rep(V) = . If V is , then Rep(V) = . + If V is , where is + an atom and is a type and it does not contain + syntactically, then Rep(V) = + . + Note that if is an annotated type, it will be wrapped in + parentheses. + If V is , where is + an atom and is a type, then Rep(V) = + . + + If V is , where + is an atom, is an expression and + is a type, then Rep(V) = + . +

-- cgit v1.2.3 From 417f9960371607e6d618d9dda108787558a9cef5 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 10 Jun 2015 16:30:53 +0200 Subject: Update the documentation of the abstract format The parenthesized type with tag 'paren_type' is no longer created by the Erlang Parser as of OTP 18.0. The tag 'user_type' is used for user defined types as of OTP 18.0. In releases before commit 7ad783 'type' is used. --- erts/doc/src/absform.xml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 12cb06c151..e1a8c2e517 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -4,7 +4,7 @@
- 20012013 + 20012015 Ericsson AB. All Rights Reserved. @@ -164,11 +164,6 @@ type, then Rep(T) = . If T is a fun type , then Rep(T) = . - If T is a parenthesized type , then - Rep(T) = , i.e. parenthesized - types are distinguished from their bodies. It should be noted though - that parenthesized types that are immediate subtrees of operator - expressions and binary types are peeled off. If T is a variable , then Rep(T) = , where is an atom with a printname consisting of the same characters as @@ -180,7 +175,7 @@ . If T is a type , where each is a type, then Rep(T) = - . + . If T is a remote type , where each is a type and and , then Rep(T) = -- cgit v1.2.3 From 738c34d4bb8f1a3811acd00af8c6c12107f8315b Mon Sep 17 00:00:00 2001 From: Bruce Yinhe Date: Thu, 18 Jun 2015 11:31:02 +0200 Subject: Change license text to APLv2 --- erts/doc/src/absform.xml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index e1a8c2e517..547d5e583d 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -8,16 +8,17 @@ Ericsson AB. All Rights Reserved. - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -- cgit v1.2.3 From 1b8dcd4741399a9190d361bb517130163365680e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Fri, 28 Aug 2015 14:29:41 +0200 Subject: Add missing behavior/behaviours to absform docs --- erts/doc/src/absform.xml | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 547d5e583d..df2553ced3 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -70,6 +70,10 @@ Rep(D) = . If F is an attribute , then Rep(F) = . + If F is an attribute , then + Rep(F) = . + If F is an attribute , then + Rep(F) = . If F is an attribute , then Rep(F) = . If F is an attribute , then -- cgit v1.2.3 From 6e93fb788aebb9050da2166749b41ff54197e049 Mon Sep 17 00:00:00 2001 From: Kostis Sagonas Date: Thu, 7 May 2015 14:43:02 +0200 Subject: Take out automatic insertion of 'undefined' from typed record fields Background ----------- In record fields with a type declaration but without an initializer, the Erlang parser inserted automatically the singleton type 'undefined' to the list of declared types, if that value was not present there. I.e. the record declaration: -record(rec, {f1 :: float(), f2 = 42 :: integer(), f3 :: some_mod:some_typ()}). was translated by the parser to: -record(rec, {f1 :: float() | 'undefined', f2 = 42 :: integer(), f3 :: some_mod:some_typ() | 'undefined'}). The rationale for this was that creation of a "dummy" #rec{} record should not result in a warning from dialyzer that e.g. the implicit initialization of the #rec.f1 field violates its type declaration. Problems --------- This seemingly innocent action has some unforeseen consequences. For starters, there is no way for programmers to declare that e.g. only floats make sense for the f1 field of #rec{} records when there is no `obvious' default initializer for this field. (This also affects tools like PropEr that use these declarations produced by the Erlang parser to generate random instances of records for testing purposes.) It also means that dialyzer does not warn if e.g. an is_atom/1 test or something more exotic like an atom_to_list/1 call is performed on the value of the f1 field. Similarly, there is no way to extend dialyzer to warn if it finds record constructions where f1 is not initialized to some float. Last but not least, it is semantically problematic when the type of the field is an opaque type: creating a union of an opaque and a structured type is very problematic for analysis because it fundamentally breaks the opacity of the term at that point. Change ------- To solve these problems the parser will not automatically insert the 'undefined' value anymore; instead the user has the option to choose the places where this value makes sense (for the field) and where it does not and insert the | 'undefined' there manually. Consequences of this change ---------------------------- This change means that dialyzer will issue a warning for all places where records with uninitialized fields are created and those fields have a declared type that is incompatible with 'undefined' (e.g. float()). This warning can be suppressed easily by adding | 'undefined' to the type of this field. This also adds documentation that the user really intends to create records where this field is uninitialized. --- erts/doc/src/absform.xml | 6 ------ 1 file changed, 6 deletions(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index df2553ced3..49fe784d06 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -246,12 +246,6 @@ Rep(V) = . If V is , then Rep(V) = . - If V is , where is - an atom and is a type and it does not contain - syntactically, then Rep(V) = - . - Note that if is an annotated type, it will be wrapped in - parentheses. If V is , where is an atom and is a type, then Rep(V) = . -- cgit v1.2.3 From 23885a8ab609688641098a759110e295052323f8 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Tue, 1 Dec 2015 10:58:43 +0100 Subject: erts: Correct the types section in The Abstract Format document The Types section is more consistent with Kostis' text in The Reference Manual. --- erts/doc/src/absform.xml | 375 ++++++++++++++++++++++------------------------- 1 file changed, 178 insertions(+), 197 deletions(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index df2553ced3..8584898a9d 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -61,7 +61,7 @@

- Module declarations and forms + Module Declarations and Forms

A module declaration consists of a sequence of forms that are either function declarations or attributes.

@@ -78,204 +78,87 @@ Rep(F) = . If F is an attribute , then Rep(F) = . + If F is an attribute , then + Rep(F) = . If F is an attribute , then Rep(F) = . If F is an attribute , then Rep(F) = . - If F is a record declaration , then - Rep(F) = - . For Rep(V), see below. - If F is a type attribute (i.e. or - ) - where each - is a variable, then Rep(F) = - . - For Rep(T), see below. - If F is a type spec (i.e. or - ) - , - where each is a fun type clause with an - argument sequence of the same length , then - Rep(F) = - . - For Rep(Tc_i), see below. - If F is a type spec (i.e. or - ) - , - where each is a fun type clause with an - argument sequence of the same length , then - Rep(F) = - . - For Rep(Tc_i), see below. + If F is a record declaration + -record(Name,{V_1, ..., V_k}), 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 atom type or the atom opaque, + each V_i is a variable, and T is a type, then Rep(F) = + {attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}}. + + If F is a function specification + -Spec Name Ft_1; ...; Ft_k, + where Spec is either the atom spec or the atom + callback, and each Ft_i is a possibly constrained + function type with an argument sequence of the same length + Arity, then Rep(F) = + {attribute,Line,Spec,{{Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}. + + If F is a function specification + -spec Mod:Name Ft_1; ...; Ft_k, + where each Ft_i is a possibly constrained + function type with an argument sequence of the same length + Arity, then Rep(F) = + {attribute,Line,spec,{{Mod,Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}. + If F is a wild attribute , then Rep(F) = .

- If F is a function declaration , - where each is a function clause with a - pattern sequence of the same length , then - Rep(F) = . + If F is a function declaration + Name Fc_1 ; ... ; Name Fc_k, + where each Fc_i is a function clause with a + pattern sequence of the same length Arity, then + Rep(F) = {function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}. +
- Type clauses - - If T is a fun type clause - Ret]]>, where each - and are types, then - Rep(T) = - . - - If T is a bounded fun type clause , - where is an unbounded fun type clause and - is a type guard sequence, then Rep(T) = - . - -
- -
- Type guards - - If G is a constraint , where - is an atom and each is a - type, then Rep(G) = - . - - If G is a type definition , - where is a variable and - is a type, then Rep(G) = - . - -
- -
- Types - - If T is a type definition , - where is a variable and - is a type, then Rep(T) = - . - If T is a type union , - where each is a type, then Rep(T) = - . - If T is a type range , - where and are types, then - Rep(T) = . - If T is a binary operation , - where is an arithmetic or bitwise binary operator - and and are types, then - Rep(T) = . - If T is , where is an - arithmetic or bitwise unary operator and is a - type, then Rep(T) = . - If T is a fun type , then Rep(T) = - . - If T is a variable , then Rep(T) = - , where is an atom - with a printname consisting of the same characters as - . - If T is an atomic literal L and L is not a string literal, then - Rep(T) = Rep(L). - If T is a tuple or map type (i.e. - or ), then Rep(T) = - . - If T is a type , where each - is a type, then Rep(T) = - . - If T is a remote type , where - each is a type and and - , then Rep(T) = - . - - If T is the nil type , then Rep(T) = - . - If T is a list type , where - is a type, then Rep(T) = - . - If T is a non-empty list type , where - is a type, then Rep(T) = - . - If T is a map type , where each - is a map pair type, then Rep(T) = - . - If T is a map pair type V]]>, where - and are types, - then Rep(T) = - . - If T is a tuple type , where - each is a type, then Rep(T) = - . - If T is a record type , where - is an atom, then Rep(T) = - . - If T is a record type , - where is an atom, then Rep(T) = - . - - If T is a record field type , - where is an atom, then Rep(T) = - . - If T is a record field type >]]>, then Rep(T) = - . - - If T is a binary type >]]>, where - is a type, then Rep(T) = - . - If T is a binary type >]]>, - where is a type, then Rep(T) = - . - If T is a binary type >]]>, - where and is a type, then - Rep(T) = - . - - If T is a fun type Ret)]]>, then - Rep(T) = . - - If T is a fun type , where - is an unbounded fun type clause, - then Rep(T) = . - -
- -
- Record fields + Record Fields

Each field in a record declaration may have an optional - explicit default initializer expression

+ explicit default initializer expression, as well as an + optional type.

If V is , then Rep(V) = . - If V is , then + If V is , + where E is an expression, then Rep(V) = . - If V is , where is - an atom and is a type and it does not contain - syntactically, then Rep(V) = - . - Note that if is an annotated type, it will be wrapped in - parentheses. - If V is , where is - an atom and is a type, then Rep(V) = - . - - If V is , where - is an atom, is an expression and - is a type, then Rep(V) = - . - + If V is A :: T, where T is a + type and it does not contain + undefined syntactically, then Rep(V) = + {typed_record_field,{record_field,LINE,Rep(A)},Rep(undefined | T)}. + + If V is A :: T, where T is a type, then Rep(V) = + {typed_record_field,{record_field,LINE,Rep(A)},Rep(T)}. + + If V is A = E :: T, where + E is an expression and T is a type, then Rep(V) = + {typed_record_field,{record_field,LINE,Rep(A),Rep(E)},Rep(T)}. +
- Representation of parse errors and end of file + Representation of Parse Errors and End-of-file

In addition to the representations of forms, the list that represents - a module declaration (as returned by functions in and - ) may contain tuples and , denoting - syntactically incorrect forms and warnings, and , denoting an end - of stream encountered before a complete form had been parsed.

+ a module declaration (as returned by functions in erl_parse and + epp) may contain tuples {error,E} and + {warning,W}, denoting syntactically incorrect forms and + warnings, and {eof,LINE}, denoting an end-of-stream + encountered before a complete form had been parsed.

- Atomic literals + Atomic Literals

There are five kinds of atomic literals, which are represented in the same way in patterns, expressions and guards:

@@ -330,12 +213,12 @@ time), then Rep(P) = . If P is a record pattern , then Rep(P) = - . + . If P is , then Rep(P) = . If P is , then Rep(P) = , - i.e., patterns cannot be distinguished from their bodies. + that is, patterns cannot be distinguished from their bodies.

Note that every pattern has the same source form as some expression, and is represented the same way as the corresponding expression.

@@ -372,10 +255,10 @@ Rep(E) = . If E is , then Rep(E) = - . + . If E is , then Rep(E) = - . + . If E is , then Rep(E) = . If E is , then @@ -466,20 +349,13 @@ is a function clause then Rep(E) = . - If E is , - where each is a generator or a filter, then - Rep(E) = . - For Rep(W), see below. - If E is , a Mnesia record access - inside a query, then - Rep(E) = . If E is , then - Rep(E) = , - i.e., parenthesized expressions cannot be distinguished from their bodies. + Rep(E) = Rep(E_0), that is, parenthesized + expressions cannot be distinguished from their bodies.
- Generators and filters + Generators and Filters

When W is a generator or a filter (in the body of a list or binary comprehension), then:

If W is a generator , where is a pattern and @@ -494,20 +370,20 @@
- Binary element type specifiers + Binary Element Type Specifiers

A type specifier list TSL for a binary element is a sequence of type specifiers . Rep(TSL) = .

When TS is a type specifier for a binary element, then:

- If TS is an atom , Rep(TS) = . + If TS is an atom , then Rep(TS) = . If TS is a couple where is an atom and - is an integer, Rep(TS) = . + is an integer, then Rep(TS) = {A,Value}.
- Map assoc and exact fields + Map Assoc and Exact Fields

When W is an assoc or exact field (in the body of a map), then:

If W is an assoc field V]]>, where @@ -595,7 +471,7 @@ Rep(Gt) = . If Gt is , then Rep(E) = - . + . If Gt is , then Rep(Gt) = . If Gt is , then @@ -609,15 +485,120 @@ the atom and is an atom or an operator, then Rep(Gt) = . If Gt is , then - Rep(Gt) = , - i.e., parenthesized guard tests cannot be distinguished from their bodies. + Rep(Gt) = , that is, parenthesized + guard tests cannot be distinguished from their bodies.

Note that every guard test has the same source form as some expression, and is represented the same way as the corresponding expression.

- The abstract format after preprocessing + Types + + If T is an annotated type Anno :: Type, + where Anno is a variable and + Type is a type, then Rep(T) = + {ann_type,LINE,[Rep(Anno),Rep(Type)]}. + If T is an atom or integer literal L, then Rep(T) = Rep(L). + + If T is L Op R, + where Op is a binary operator and L and R + 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, where Op is a + unary operator and A is a type (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)}. + If T is a bitstring type <<_:M,_:_*N>>, + where M and N are singleton integer types, then Rep(T) = + {type,LINE,binary,[Rep(M),Rep(N)]}. + If T is the empty list type [], then Rep(T) = + {type,Line,nil,[]}. + If T is a fun type fun(), then Rep(T) = + {type,LINE,'fun',[]}. + If T is a fun type fun((...) -> B), + where B is a type, then + Rep(T) = {type,LINE,'fun',[{type,LINE,any},Rep(B)]}. + + If T is a fun type fun(Ft), where + Ft is a function type, + then Rep(T) = Rep(Ft). + If T is an integer range type L .. H, + where L and H 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 and V 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 each A_i is a type, then Rep(T) = + {type,LINE,N,[Rep(A_1), ..., Rep(A_k)]}. + If T is a record type #Name{F_1, ..., F_k}, + where each F_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, + where Type 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 + each A_i is a type, then Rep(T) = + {remote_type,LINE,[Rep(M),Rep(N),[Rep(A_1), ..., Rep(A_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 + each A_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 each T_i is a type, 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}, where A is an atom with a printname + consisting of the same characters as V. A type variable + is any variable except underscore (_). + If T is a user-defined type N(A_1, ..., A_k), + where each A_i is a type, then Rep(T) = + {user_type,LINE,N,[Rep(A_1), ..., Rep(A_k)]}. + If T is ( T_0 ), then Rep(T) = Rep(T_0), + that is, parenthesized types cannot be distinguished from their + bodies. + + +
+ Function Types + + If Ft is a constrained function type Ft_1 when Fc, + where Ft_1 is a function type and + Fc 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 each A_i and B are types, then + Rep(Ft) = {type,LINE,'fun',[{type,LINE,product,[Rep(A_1), + ..., Rep(A_n)]},Rep(B)]}. + +
+ +
+ Function Constraints +

A function constraint Fc is a nonempty sequence of constraints + C_1, ..., C_k, and + Rep(Fc) = [Rep(C_1), ..., Rep(C_k)].

+ + If C is a constraint is_subtype(V, T) or V :: T, + where V is a type variable and T is a type, then + Rep(C) = {type,LINE,constraint,[Rep(F),[Rep(V),Rep(T)]]}. + + +
+
+ +
+ The Abstract Format After Preprocessing

The compilation option can be given to the compiler to have the abstract code stored in the chunk in the BEAM file -- cgit v1.2.3 From af1e0396fda62efb6c0817134b419b166b110d09 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Tue, 1 Dec 2015 12:45:03 +0100 Subject: erts: Remove CDATA from The Abstract Format document --- erts/doc/src/absform.xml | 579 +++++++++++++++++++++++------------------------ 1 file changed, 288 insertions(+), 291 deletions(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 8584898a9d..ca06794a53 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -11,7 +11,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software @@ -19,7 +19,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - + The Abstract Format @@ -35,24 +35,24 @@

This document describes the standard representation of parse trees for Erlang programs as Erlang terms. This representation is known as the abstract format. - Functions dealing with such parse trees are + Functions dealing with such parse trees are compile:forms/[1,2] and functions in the modules - , - , - , - , - , + epp, + erl_eval, + erl_lint, + erl_pp, + erl_parse, and - . + io. They are also used as input and output for parse transforms (see the module - ).

-

We use the function to denote the mapping from an Erlang source - construct to its abstract format representation , and write - . + compile).

+

We use the function Rep to denote the mapping from an Erlang source + construct C to its abstract format representation R, and write + R = Rep(C).

-

The word below represents an integer, and denotes the +

The word LINE below represents an integer, and denotes the number of the line in the source file where the construction occurred. - Several instances of in the same construction may denote + Several instances of LINE in the same construction may denote different lines.

Since operators are not terms in their own right, when operators are mentioned below, the representation of an operator should be taken to @@ -66,24 +66,24 @@ function declarations or attributes.

If D is a module declaration consisting of the forms - , ..., , then - Rep(D) = . - If F is an attribute , then - Rep(F) = . - If F is an attribute , then - Rep(F) = . - If F is an attribute , then - Rep(F) = . - If F is an attribute , then - Rep(F) = . - If F is an attribute , then - Rep(F) = . - If F is an attribute , then - Rep(F) = . - If F is an attribute , then - Rep(F) = . - If F is an attribute , then - Rep(F) = . + 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 -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 -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) = {attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}. @@ -109,8 +109,8 @@ Arity, then Rep(F) = {attribute,Line,spec,{{Mod,Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}. - If F is a wild attribute , then - Rep(F) = . + 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, @@ -126,11 +126,11 @@ explicit default initializer expression, as well as an optional type.

- If V is , then - Rep(V) = . - If V is , + If V is A, then + Rep(V) = {record_field,LINE,Rep(A)}. + If V is A = E, where E is an expression, then - Rep(V) = . + Rep(V) = {record_field,LINE,Rep(A),Rep(E)}. If V is A :: T, where T is a type and it does not contain undefined syntactically, then Rep(V) = @@ -163,14 +163,14 @@ same way in patterns, expressions and guards:

If L is an integer or character literal, then - Rep(L) = . + Rep(L) = {integer,LINE,L}.
If L is a float literal, then - Rep(L) = . + Rep(L) = {float,LINE,L}.
If L is a string literal consisting of the characters - , ..., , then - Rep(L) = . + C_1, ..., C_k, then + Rep(L) = {string,LINE,[C_1, ..., C_k]}.
If L is an atom literal, then - Rep(L) = . + 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.

@@ -178,46 +178,46 @@
Patterns -

If is a sequence of patterns , then - Rep(Ps) = . Such sequences occur as the +

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 a compound pattern , then - Rep(P) = . - If P is a variable pattern , then - Rep(P) = , + 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 - . - If P is a universal pattern , then - Rep(P) = . - If P is a tuple pattern , then - Rep(P) = . - If P is a nil pattern , then - Rep(P) = . - If P is a cons pattern , then - Rep(P) = . - If E is a binary pattern >]]>, then - Rep(E) = . + 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 omitted is represented by . An omitted - (type specifier list) is represented by . - If P is , where is a binary operator (this - is either an occurrence of applied to a literal string or character + An omitted Size is represented by default. An omitted TSL + (type specifier list) is represented by default. + If P is P_1 Op P_2, where Op 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) = . - If P is , where is a unary operator (this is an + then Rep(P) = {op,LINE,Op,Rep(P_1),Rep(P_2)}. + If P is Op P_0, where Op is a unary operator (this is an occurrence of an expression that can be evaluated to a number at compile - time), then Rep(P) = . - If P is a record pattern , + 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) = - . - If P is , then - Rep(P) = . - If P is , 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 ( P_0 ), then + Rep(P) = Rep(P_0), that is, patterns cannot be distinguished from their bodies.

Note that every pattern has the same source form as some expression, and is @@ -226,159 +226,153 @@

Expressions -

A body B is a sequence of expressions , and - Rep(B) = .

+

A body B is a 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 , then - Rep(P) = Rep(L). - If E is , then - Rep(E) = . - If E is a variable , then - Rep(E) = , - where is an atom with a printname consisting of the same - characters as . - If E is a tuple skeleton , then - Rep(E) = . - If E is , then - Rep(E) = . - If E is a cons skeleton , then - Rep(E) = . - If E is a binary constructor >]]>, then - Rep(E) = . + If P is an atomic literal L, then Rep(P) = 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}, + where A is an atom with a printname consisting of the same + characters as V. + 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 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 omitted is represented by . An omitted - (type specifier list) is represented by . - If E is , where is a binary operator, - then Rep(E) = . - If E is , where is a unary operator, then - Rep(E) = . - If E is , then - Rep(E) = - . - If E is , then - Rep(E) = - . - If E is , then - Rep(E) = . - If E is , then - Rep(E) = . - If E is where each - is a map assoc or exact field, then Rep(E) = - . For Rep(W), see - below. - If E is where - is a map assoc or exact field, then Rep(E) = - . For - Rep(W), see below. - If E is , then - Rep(E) = . - If E is , then - Rep(E) = . - If E is , then + An omitted Size is represented by default. An omitted TSL + (type specifier list) is represented by default. + If E is E_1 Op E_2, where Op is a binary operator, + then Rep(E) = {op,LINE,Op,Rep(E_1),Rep(E_2)}. + If E is Op E_0, where Op 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}, + 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) = - . - If E is a list comprehension , - where each is a generator or a filter, then - Rep(E) = . For Rep(W), see + {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)}. + 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 below. - If E is a binary comprehension >]]>, - where each is a generator or a filter, then - Rep(E) = . For Rep(W), see + 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 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 || W_1, ..., W_k], + where each W_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 below. - If E is , where is a body, then - Rep(E) = . - If E is , - where each is an if clause then - Rep(E) = - . - If E is , - where is an expression and each is a - case clause then - Rep(E) = - . - If E is , - where is a body and each is a catch clause then + If E is a binary comprehension + <<E_0 || W_1, ..., W_k>>, + where each W_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. + If E is begin B end, where B is a body, then + Rep(E) = {block,LINE,Rep(B)}. + If E is if Ic_1 ; ... ; Ic_k end, + where each Ic_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, + where E_0 is an expression and each Cc_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, + where B is a body and each Tc_i is a catch clause then Rep(E) = - . - If E is , - where is a body, - each is a case clause and - each is a catch clause then + {'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, + where B is a body, + each Cc_i is a case clause and + each Tc_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, + where B and A are bodies then Rep(E) = + {'try',LINE,Rep(B),[],[],Rep(A)}. + If E is try B of Cc_1 ; ... ; Cc_k after A end, + where B and A are a bodies and + each Cc_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, + where B and A are bodies and + each Tc_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, + where B and A are a bodies, + each Cc_i is a case clause and + each Tc_j is a catch clause then Rep(E) = - . - If E is , - where and are bodies then - Rep(E) = - . - If E is , - where and are a bodies and - each is a case clause then - Rep(E) = - . - If E is , - where and are bodies and - each is a catch clause then - Rep(E) = - . - If E is , - where and are a bodies, - each is a case clause and - each is a catch clause then - Rep(E) = - . - If E is , - where each is a case clause then - Rep(E) = - . - If E is B_t end]]>, - where each is a case clause, - is an expression and is a body, then - Rep(E) = - . - If E is , then - Rep(E) = . - If E is , then - Rep(E) = . - (Before the R15 release: Rep(E) = .) - If E is - where each is a function clause then Rep(E) = - . - If E is - where is a variable and each - is a function 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 each Cc_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 each Cc_i is a case clause, + E_0 is an expression and B_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 each Fc_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 + where Name 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 , then + If E is ( E_0 ), then Rep(E) = Rep(E_0), that is, parenthesized expressions cannot be distinguished from their bodies.
Generators and Filters -

When W is a generator or a filter (in the body of a list or binary comprehension), then:

+

When W is a generator or a filter (in the body of a list or + binary comprehension), then:

- If W is a generator , where is a pattern and - is an expression, then - Rep(W) = . - If W is a generator , where is a pattern and - is an expression, then - Rep(W) = . - If W is a filter , which is an expression, then - Rep(W) = . + If W is a generator P <- E, where P is + a pattern and E is an expression, then + Rep(W) = {generate,LINE,Rep(P),Rep(E)}. + If W is a generator P <= E, where P is + a pattern and E is an expression, then + Rep(W) = {b_generate,LINE,Rep(P),Rep(E)}. + If W is a filter E, which is an expression, then + Rep(W) = Rep(E).
Binary Element Type Specifiers

A type specifier list TSL for a binary element is a sequence of type - specifiers . - Rep(TSL) = .

+ specifiers TS_1 - ... - TS_k. + Rep(TSL) = [Rep(TS_1), ..., Rep(TS_k)].

When TS is a type specifier for a binary element, then:

- If TS is an atom , then Rep(TS) = . - If TS is a couple where is an atom and - is an integer, then Rep(TS) = {A,Value}. + If TS is an atom A, then Rep(TS) = A. + If TS is a couple A:Value where A is an atom + and Value is an integer, then Rep(TS) = + {A,Value}.
@@ -386,13 +380,13 @@ Map Assoc and Exact Fields

When W is an assoc or exact field (in the body of a map), then:

- If W is an assoc field V]]>, where - and are both expressions, - then Rep(W) = . + If W is an assoc field K => V, where + K and V are both expressions, + then Rep(W) = {map_field_assoc,LINE,Rep(K),Rep(V)}. - If W is an exact field , where - and are both expressions, - then Rep(W) = . + If W is an exact field K := V, where + K and V are both expressions, + then Rep(W) = {map_field_exact,LINE,Rep(K),Rep(V)}.
@@ -400,92 +394,95 @@
Clauses -

There are function clauses, if clauses, case clauses +

There are function clauses, if clauses, case clauses and catch clauses.

-

A clause is one of the following alternatives:

+

A clause C is one of the following alternatives:

- If C is a function clause B]]> - where is a pattern sequence and is a body, then - Rep(C) = . - If C is a function clause B]]> - where is a pattern sequence, - is a guard sequence and is a body, then - Rep(C) = . - If C is an if clause B]]> - where is a guard sequence and is a body, then - Rep(C) = . - If C is a case clause B]]> - where is a pattern and is a body, then - Rep(C) = . - If C is a case clause B]]> - where is a pattern, - is a guard sequence and is a body, then - Rep(C) = . - If C is a catch clause B]]> - where is a pattern and is a body, then - Rep(C) = . - If C is a catch clause B]]> - where is an atomic literal or a variable pattern, - is a pattern and is a body, then - Rep(C) = . - If C is a catch clause B]]> - where is a pattern, is a guard sequence - and is a body, then - Rep(C) = . - If C is a catch clause B]]> - where is an atomic literal or a variable pattern, - is a pattern, is a guard sequence - and is a body, then - Rep(C) = . + If C is a function clause ( Ps ) -> B + where Ps is a pattern sequence and B is a body, then + Rep(C) = {clause,LINE,Rep(Ps),[],Rep(B)}. + If C is a function clause ( Ps ) when Gs -> B + where Ps is a pattern sequence, + Gs is a guard sequence and B is a body, then + Rep(C) = {clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}. + If C is an if clause Gs -> B + where Gs is a guard sequence and B is a body, then + Rep(C) = {clause,LINE,[],Rep(Gs),Rep(B)}. + If C is a case clause P -> B + where P is a pattern and B is a body, then + Rep(C) = {clause,LINE,[Rep(P)],[],Rep(B)}. + If C is a case clause P when Gs -> B + where P is a pattern, + Gs is a guard sequence and B is a body, then + Rep(C) = {clause,LINE,[Rep(P)],Rep(Gs),Rep(B)}. + If C is a catch clause P -> B + where P is a pattern and B is a body, then + Rep(C) = {clause,LINE,[Rep({throw,P,_})],[],Rep(B)}. + If C is a catch clause X : P -> B + where X is an atomic literal or a variable pattern, + P is a pattern and B is a body, then + Rep(C) = {clause,LINE,[Rep({X,P,_})],[],Rep(B)}. + If C is a catch clause P when Gs -> B + where P is a pattern, Gs is a guard sequence + and B 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 + where X is an atomic literal or a variable pattern, + P is a pattern, Gs is a guard sequence + and B is a body, then + Rep(C) = {clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)}.
Guards -

A guard sequence Gs is a sequence of guards , and - Rep(Gs) = . If the guard sequence is - empty, Rep(Gs) = .

-

A guard G is a nonempty sequence of guard tests , and - Rep(G) = .

-

A guard test is one of the following alternatives:

+

A guard sequence Gs is a sequence of guards G_1; ...; G_k, and + Rep(Gs) = [Rep(G_1), ..., Rep(G_k)]. If the guard sequence is + empty, Rep(Gs) = [].

+

A guard G is a nonempty sequence of guard tests + Gt_1, ..., Gt_k, and Rep(G) = + [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 a variable pattern , then - Rep(Gt) = , - where A is an atom with a printname consisting of the same characters as - . - If Gt is a tuple skeleton , then - Rep(Gt) = . - If Gt is , then - Rep(Gt) = . - If Gt is a cons skeleton , then - Rep(Gt) = . - If Gt is a binary constructor >]]>, then - Rep(Gt) = . + 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 as V. + 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 + 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 omitted is represented by . An omitted - (type specifier list) is represented by . - If Gt is , where - is a binary operator, then Rep(Gt) = . - If Gt is , where is a unary operator, then - Rep(Gt) = . - If Gt is , then + An omitted Size is represented by default. + An omitted TSL (type specifier list) is represented + by default. + If Gt is Gt_1 Op Gt_2, where Op + is a binary operator, then Rep(Gt) = + {op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}. + If Gt is Op Gt_0, where Op 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) = - . - If Gt is , then - Rep(Gt) = . - If Gt is , then - Rep(Gt) = . - If Gt is , where is an atom, then - Rep(Gt) = . - If Gt is , where is - the atom and is an atom or an operator, then - Rep(Gt) = . - If Gt is , where is - the atom and is an atom or an operator, then - Rep(Gt) = . - If Gt is , then - Rep(Gt) = , that is, parenthesized + {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 Gt_0#Name.Field, then + Rep(Gt) = {record_field,LINE,Rep(Gt_0),Name,Rep(Field)}. + If Gt is A(Gt_1, ..., Gt_k), where A 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), where A_m is + the atom erlang and A 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), where A_m is + the atom erlang and A is an atom or an operator, then + Rep(Gt) = {call,LINE,Rep({A_m,A}),[Rep(Gt_1), ..., Rep(Gt_k)]}. + + If Gt is ( Gt_0 ), then + Rep(Gt) = Rep(Gt_0), that is, parenthesized guard tests cannot be distinguished from their bodies.

Note that every guard test has the same source form as some expression, @@ -599,18 +596,18 @@

The Abstract Format After Preprocessing -

The compilation option can be given to the - compiler to have the abstract code stored in - the chunk in the BEAM file +

The compilation option debug_info can be given to the + compiler to have the abstract code stored in + the abstract_code chunk in the BEAM file (for debugging purposes).

-

In OTP R9C and later, the chunk will +

In OTP R9C and later, the abstract_code chunk will contain

-

-

where is the abstract code as described +

{raw_abstract_v1,AbstractCode}

+

where AbstractCode is the abstract code as described in this document.

In releases of OTP prior to R9C, the abstract code after some more processing was stored in the BEAM file. The first element of the - tuple would be either (R7B) or + tuple would be either abstract_v1 (R7B) or abstract_v2 (R8B).

-- cgit v1.2.3 From ce22e0f430a98cc096b056066d427edbd2449a13 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 9 Dec 2015 08:53:31 +0100 Subject: erts: Correct the types section in The Abstract Format document Fixed a mistake in commit 23885a. --- erts/doc/src/absform.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index ca06794a53..186c9a1143 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -588,7 +588,7 @@ If C is a constraint is_subtype(V, T) or V :: T, where V is a type variable and T is a type, then - Rep(C) = {type,LINE,constraint,[Rep(F),[Rep(V),Rep(T)]]}. + Rep(C) = {type,LINE,constraint,[{atom,LINE,is_subtype},[Rep(V),Rep(T)]]}.
-- cgit v1.2.3 From 34e02fed50bbaa2af7b1828968b6ec02a54e98c8 Mon Sep 17 00:00:00 2001 From: Hans Bolinder 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(-) (limited to 'erts/doc/src/absform.xml') 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 @@
- 20012015 + 20012016 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 each V_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 patterns P_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 association P_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 Rep(P) = Rep(P_0), that is, patterns cannot be distinguished from their bodies. @@ -221,11 +228,11 @@
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 each A_i is an association E_i_1 => E_i_2 + or E_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 each A_i is an association E_i_1 => E_i_2 + or E_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 each W_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 each Q_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 each W_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 each Q_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, where B 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 try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end, where B and A are a bodies, - each Cc_i is a case clause and + each Cc_i is a case clause, and each Tc_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)}. @@ -328,10 +337,10 @@ {'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 each Fc_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, where Name is a variable and each Fc_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, where P is + If Q is a generator P <- E, where P is a pattern and E is an expression, then - Rep(W) = {generate,LINE,Rep(P),Rep(E)}. - If W is a generator P <= E, where P is + Rep(Q) = {generate,LINE,Rep(P),Rep(E)}. + If Q is a generator P <= E, where P is a pattern and E is an expression, then - Rep(W) = {b_generate,LINE,Rep(P),Rep(E)}. - If W is a filter E, which is an expression, then - Rep(W) = Rep(E). + Rep(Q) = {b_generate,LINE,Rep(P),Rep(E)}. + If Q is a filter E, where E 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. + specifiers TS_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 where A is an atom - and Value is an integer, then Rep(TS) = - {A,Value}. + If TS is a type specifier A, where A is an atom, + then Rep(TS) = A. + If TS is a type specifier A:Value, + where A is an atom and Value is an integer, + then Rep(TS) = {A,Value}.
- 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 and V 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 and V 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)}.
@@ -393,37 +399,37 @@ and catch clauses.

A clause C is one of the following alternatives:

- If C is a function clause ( Ps ) -> B + If C is a function clause ( Ps ) -> B, where Ps is a pattern sequence and B 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, where Ps is a pattern sequence, Gs is a guard sequence and B 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, where Gs is a guard sequence and B 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, where P is a pattern and B 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, where P is a pattern, Gs is a guard sequence and B 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, where P is a pattern and B 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, where X is an atomic literal or a variable pattern, - P is a pattern and B is a body, then + P is a pattern, and B is a body, then Rep(C) = {clause,LINE,[Rep({X,P,_})],[],Rep(B)}. - If C is a catch clause P when Gs -> B - where P is a pattern, Gs is a guard sequence + If C is a catch clause P when Gs -> B, + where P is a pattern, Gs is a guard sequence, and B 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, where X 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, and B is a body, then Rep(C) = {clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)}. @@ -439,7 +445,7 @@ [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 V, then Rep(Gt) = {var,LINE,A}, where A is an atom with a printname consisting of the same characters as V. @@ -467,15 +473,21 @@ Rep(Gt) = {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 each A_i is an association Gt_i_1 => Gt_i_2 + or Gt_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 association Gt_i_1 => Gt_i_2 + or Gt_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), where A 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), where A_m is the atom erlang and A 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), where A_m is - the atom erlang and A is an atom or an operator, then - Rep(Gt) = {call,LINE,Rep({A_m,A}),[Rep(Gt_1), ..., Rep(Gt_k)]}. - If Gt is ( Gt_0 ), then Rep(Gt) = Rep(Gt_0), that is, parenthesized guard tests cannot be distinguished from their bodies. @@ -487,21 +499,20 @@
Types - If T is an annotated type Anno :: Type, - where Anno 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, + where A 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, - where Op is a binary operator and L and R - 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, where Op is a - unary operator and A is a type (this is an occurrence of + If T is an operator type T_1 Op T_2, + where Op 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, where Op 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)}. + then Rep(T) = {op,LINE,Op,Rep(T_0)}. If T is a bitstring type <<_:M,_:_*N>>, where M and N are singleton integer types, then Rep(T) = {type,LINE,binary,[Rep(M),Rep(N)]}. @@ -509,53 +520,44 @@ {type,Line,nil,[]}. If T is a fun type fun(), then Rep(T) = {type,LINE,'fun',[]}. - If T is a fun type fun((...) -> B), - where B 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 fun(Ft), where Ft is a function type, - then Rep(T) = Rep(Ft). + then Rep(T) = Rep(Ft). For Rep(Ft), see below. If T is an integer range type L .. H, where L and H 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 and V 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 each A_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 each F_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, - where Type 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 - each A_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 - each A_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 each T_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}, where A is an atom with a printname consisting of the same characters as V. A type variable is any variable except underscore (_). - If T is a user-defined type N(A_1, ..., A_k), - where each A_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 ( T_0 ), then Rep(T) = Rep(T_0), that is, parenthesized types cannot be distinguished from their bodies. @@ -563,15 +565,17 @@
Function Types +

A function type Ft is one of the following alternatives:

If Ft is a constrained function type Ft_1 when Fc, where Ft_1 is a function type and Fc 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 each A_i and B 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 each T_i is a type, then + Rep(Ft) = {type,LINE,'fun',[{type,LINE,product,[Rep(T_1), + ..., Rep(T_n)]},Rep(T_0)]}.
@@ -587,6 +591,24 @@
+ +
+ Association Types + + If A is an association type K => V, where + K and V 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, + where Type 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 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(-) (limited to 'erts/doc/src/absform.xml') 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 each V_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 atom type or the atom opaque, - each V_i is a variable, and T 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 each Fc_i is a function clause with a + pattern sequence of the same length Arity, 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 each V_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 atom type or the atom opaque, + each V_i is a variable, and T 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 each Fc_i is a function clause with a - pattern sequence of the same length Arity, 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 each TSL_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 omitted Size_i is represented by default. + An omitted TSL_i is represented by default. 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 omitted Size is represented by default. An omitted TSL - (type specifier list) is represented by default. - If P is P_1 Op P_2, where Op 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, where Op 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 each A_i is an association P_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, + where Op 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, + where Op 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 ( P_0 ), then Rep(P) = Rep(P_0), - that is, patterns cannot be distinguished from their bodies. + that is, parenthesized patterns cannot be distinguished from their + bodies. + If P is a record field index pattern #Name.Field, + where Field 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 each Field_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}, - where A is an atom with a printname consisting of the same - characters as V. - 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 each Q_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 each Size_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 omitted Size_i is represented by default. + An omitted TSL_i is represented by default. + If E is a block expression begin B end, + where B 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, + where E_0 is an expression and each Cc_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 omitted Size is represented by default. An omitted TSL - (type specifier list) is represented by default. - If E is E_1 Op E_2, where Op is a binary operator, - then Rep(E) = {op,LINE,Op,Rep(E_1),Rep(E_2)}. - If E is Op E_0, where Op 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 each Fc_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, + where Name 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 each Ic_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 each Q_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 each A_i is an association E_i_1 => E_i_2 or E_i_1 := E_i_2, then Rep(E) = @@ -273,95 +303,92 @@ or E_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 each Q_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 each Q_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, where B is a body, then - Rep(E) = {block,LINE,Rep(B)}. - If E is if Ic_1 ; ... ; Ic_k end, - where each Ic_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, - where E_0 is an expression and each Cc_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, + where P 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, + where Op 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, + where Op 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 each Cc_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 each Cc_i is a case clause, + E_0 is an expression and B_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 each Field_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, + where Field is an atom, then + Rep(E) = {record_field,LINE,Rep(E_0),Name,Rep(Field)}. + If E is a record field index #Name.Field, + where Field 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 each Field_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, where B is a body and each Tc_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, where B is a body, each Cc_i is a case clause and each Tc_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, where B and A 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, where B and A are a bodies and each Cc_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, where B and A are bodies and each Tc_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, where B and A are a bodies, each Cc_i is a case clause, and each Tc_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 each Cc_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 each Cc_i is a case clause, - E_0 is an expression and B_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 each Fc_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, - where Name 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}, + where A is an atom with a printname consisting of the same + characters as V.
Qualifiers

A qualifier Q is one of the following alternatives:

+ If Q is a filter E, where E is an expression, then + Rep(Q) = Rep(E). If Q is a generator P <- E, where P is a pattern and E is an expression, then Rep(Q) = {generate,LINE,Rep(P),Rep(E)}. If Q is a generator P <= E, where P is a pattern and E is an expression, then Rep(Q) = {b_generate,LINE,Rep(P),Rep(E)}. - If Q is a filter E, where E is an expression, then - Rep(Q) = Rep(E).
@@ -399,16 +426,6 @@ and catch clauses.

A clause C is one of the following alternatives:

- If C is a function clause ( Ps ) -> B, - where Ps is a pattern sequence and B is a body, then - Rep(C) = {clause,LINE,Rep(Ps),[],Rep(B)}. - If C is a function clause ( Ps ) when Gs -> B, - where Ps is a pattern sequence, - Gs is a guard sequence and B is a body, then - Rep(C) = {clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}. - If C is an if clause Gs -> B, - where Gs is a guard sequence and B is a body, then - Rep(C) = {clause,LINE,[],Rep(Gs),Rep(B)}. If C is a case clause P -> B, where P is a pattern and B is a body, then Rep(C) = {clause,LINE,[Rep(P)],[],Rep(B)}. @@ -432,6 +449,16 @@ P is a pattern, Gs is a guard sequence, and B is a body, then Rep(C) = {clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)}. + If C is a function clause ( Ps ) -> B, + where Ps is a pattern sequence and B is a body, then + Rep(C) = {clause,LINE,Rep(Ps),[],Rep(B)}. + If C is a function clause ( Ps ) when Gs -> B, + where Ps is a pattern sequence, + Gs is a guard sequence and B is a body, then + Rep(C) = {clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}. + If C is an if clause Gs -> B, + where Gs is a guard sequence and B is a body, then + Rep(C) = {clause,LINE,[],Rep(Gs),Rep(B)}.
@@ -446,33 +473,23 @@

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 as V. - 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 each Size_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 omitted Size is represented by default. - An omitted TSL (type specifier list) is represented - by default. - If Gt is Gt_1 Op Gt_2, where Op - is a binary operator, then Rep(Gt) = - {op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}. - If Gt is Op Gt_0, where Op 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 Gt_0#Name.Field, then - Rep(Gt) = {record_field,LINE,Rep(Gt_0),Name,Rep(Field)}. + An omitted Size_i is represented by default. + An omitted TSL_i is represented by default.
+ 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), + where A 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), + where A_m is the atom erlang and A 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 each A_i is an association Gt_i_1 => Gt_i_2 or Gt_i_1 := Gt_i_2, then Rep(Gt) = @@ -483,14 +500,33 @@ or Gt_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), where A 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), where A_m is - the atom erlang and A 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, + where Op 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, + where Op 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 each Field_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, + where Field is an atom, then + Rep(Gt) = {record_field,LINE,Rep(Gt_0),Name,Rep(Field)}. + If Gt is a record field index #Name.Field, + where Field 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 as V.

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, - where Op 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, where Op 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 <<_:M,_:_*N>>, where M and N are singleton integer types, then Rep(T) = {type,LINE,binary,[Rep(M),Rep(N)]}. @@ -535,6 +562,18 @@ 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, + where Op 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, where Op 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 N(T_1, ..., T_k), then Rep(T) = {type,LINE,N,[Rep(T_1), ..., Rep(T_k)]}. @@ -558,9 +597,6 @@ 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 From e1b95c4a48e08fb4bc42626db8614a3cd46d2a5e Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 3 Mar 2016 10:38:18 +0100 Subject: erts: Use 'bit string' in The Abstract Format document --- erts/doc/src/absform.xml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index ccdecf44ec..13756ddfdc 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -182,7 +182,7 @@

Individual patterns are represented as follows:

If P is an atomic literal L, then Rep(P) = Rep(L). - If P is a binary pattern + If P is a bit string 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 each TSL_i is a type specificer list, then @@ -241,12 +241,13 @@

An expression E is one of the following alternatives:

If E is an atomic literal L, then Rep(E) = Rep(L). - If E is a binary comprehension + If E is a bit string comprehension <<E_0 || Q_1, ..., Q_k>>, where each Q_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>>, + If E is a bit string constructor + <<E_1:Size_1/TSL_1, ..., E_k:Size_k/TSL_k>>, where each Size_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)}]}. @@ -386,16 +387,17 @@ If Q is a generator P <- E, where P is a pattern and E is an expression, then Rep(Q) = {generate,LINE,Rep(P),Rep(E)}. - If Q is a generator P <= E, where P is + If Q is a bit string generator + P <= E, where P is a pattern and E is an expression, then Rep(Q) = {b_generate,LINE,Rep(P),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, and + Bit String Element Type Specifiers +

A type specifier list TSL for a bit string element is a sequence + of type specifiers TS_1 - ... - TS_k, and Rep(TSL) = [Rep(TS_1), ..., Rep(TS_k)].

If TS is a type specifier A, where A is an atom, @@ -473,7 +475,7 @@

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 binary constructor + If Gt is a bit string constructor <<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>>, where each Size_i is a guard test and each TSL_i is a type specificer list, then @@ -540,7 +542,7 @@ {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 a bitstring type <<_:M,_:_*N>>, + If T is a bit string type <<_:M,_:_*N>>, where M and N are singleton integer types, then Rep(T) = {type,LINE,binary,[Rep(M),Rep(N)]}. If T is the empty list type [], then Rep(T) = -- cgit v1.2.3 From 1cb11595f5d4860b38c8bf6d56073ba0032a51a9 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 13 Apr 2016 14:43:43 +0200 Subject: erts: Add exact association types to the abstract format doc --- erts/doc/src/absform.xml | 3 +++ 1 file changed, 3 insertions(+) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 13756ddfdc..6d6ba224a0 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -636,6 +636,9 @@ If A is an association type K => V, where K and V are types, then Rep(A) = {type,LINE,map_field_assoc,[Rep(K),Rep(V)]}. + If A is an association type K := V, where + K and V are types, then Rep(A) = + {type,LINE,map_field_exact,[Rep(K),Rep(V)]}.
-- cgit v1.2.3 From ab950a81bc3361322ce955703f468f314c05e546 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 31 Mar 2016 15:55:46 +0200 Subject: erts: Remove some attributes from the abstract format doc Some wild attributes are no longer mentioned separately. --- erts/doc/src/absform.xml | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 6d6ba224a0..bfabb7f042 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -68,22 +68,12 @@ 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 -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 -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 -file(File,Line), then Rep(F) = {attribute,LINE,file,{File,Line}}. If F is a function declaration -- cgit v1.2.3 From 3b2d98cf1cf8983896293a220275b6ebfa7a609d Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 19 May 2016 09:21:02 +0200 Subject: erts: Correct character repr in doc of the abstract format Barklund's and Virding's spec states that character literals are represented by {integer, Line, L}. The copy-and-paste bug is fixed the description of the abstract format. --- erts/doc/src/absform.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'erts/doc/src/absform.xml') diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index bfabb7f042..0b04f8f70e 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -152,9 +152,11 @@ If L is an atom literal, then Rep(L) = {atom,LINE,L}. + If L is a character literal, then + Rep(L) = {char,LINE,L}. If L is a float literal, then Rep(L) = {float,LINE,L}. - If L is an integer or character literal, then + If L is an integer literal, then Rep(L) = {integer,LINE,L}. If L is a string literal consisting of the characters C_1, ..., C_k, then -- cgit v1.2.3