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') 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