Projects/Elixir/Erlex |

**compile:forms/[1,2]**

and functions in the modules **epp**

, **erl_eval**

, **erl_lint**

, **erl_pp**

, **erl_parse**

, and **io**

.
Parse trees are also used as input and output for parse transforms (see the **compile**

module).
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 **LINE**

below represents an integer,
and denotes the number of the line in the source file where the construction occurred.
Several instances of **LINE**

in the same construction may denote different lines.
Operators are not **.**

).
- If

is a**D****module declaration**with**forms**

, then:**F_i**

`F_1, ..., F_k`*yields*`Rep(D)`:

`[ Rep(F_1), ..., Rep(F_k) ]`

- If

is a**F****module****attribute**, then:

`-module( Mod )`*yields*`Rep(F)`:

`{ attribute, LINE, module, Mod }`

- If

is an**F****export****attribute**with**functions**

and**Fun_i****arities**

, then:**A_i**

`-export( [ Fun_1/A_1, ..., Fun_k/A_k ] )`*yields*`Rep(F)`:

`{ attribute, LINE, export,`

`[ { Fun_1, A_1 }, ..., { Fun_k, A_k } ] }`

- If

is an**F****import****attribute**with**functions**

and**Fun_i****arities**

, then:**A_i**

`-import( Mod, [ Fun_1/A_1, ..., Fun_k/A_k ] )`*yields*`Rep(F)`:

`{ attribute, LINE, import,`

`{ Mod, [ { Fun_1, A_1 }, ..., { Fun_k, A_k } ] } }`

- If

is a**F****compile****attribute**with**options**

, then:**Opt_i**

`-compile( { Opt_1, ..., Opt_k } )`*yields*`Rep(F)`:

`{ attribute, LINE, compile,`

`{ Opt_1, ..., Opt_k } }`

- If

is a**F****file****attribute**that specifies the current

and**File**

, then:**Line**

`-file( File, Line )`*yields*`Rep(F)`:

`{ attribute, LINE, file,`

`{ File, Line } }`

- If

is a**F****record****declaration**that specifies

(field/value expressions), then:**V_i**

`-record( Name, { V_1, ..., V_k } )`*yields*`Rep(F)`:

`{ attribute, LINE, record,`

`{ Name,`

`[ Rep(V_1), ..., Rep(V_k) ] } }`For

, see below.**Rep(V_i)**

- If

is a**F****type attribute**(i.e.,

or**opaque**

) where each**type**

is a**A_i****variable**, then:

`-Attr Name( A_1, ..., A_k ) :: T`*yields*`Rep(F)`:

`{ attribute, LINE, Attr,`

`{ Name, Rep(T),`

`[ Rep(A_1), ..., Rep(A_k) ] } }`For

, see below.**Rep(T)**

- If

is a**F****type spec**(i.e.,

or**callback**

) where each**spec**

is a**Tc_i****fun type clause**

with an**argument sequence**of the same length (i.e.,

), then:**Arity**

`-Attr F Tc_1; ...; Tc_k`*yields*`Rep(F)`:

`{ Attr, LINE,`

`{ { F, Arity },`

`[ Rep(Tc_1), ..., Rep(Tc_k) ] } }`For

, see below.**Rep(Tc_i)**

- If

is a**F****type spec**(i.e.,

or**callback**

) for**spec****module**

and**Mod****function**

,**Fun**

where each

is a**Tc_i****fun type clause**with an**argument sequence**of the same

length (i.e.,

), then:**Arity**

`-Attr Mod:Fun Tc_1; ...; Tc_k`*yields*`Rep(F)`:

`{ Attr, LINE,`

`{ { Mod, F, Arity },`

`[ Rep(Tc_1), ..., Rep(Tc_k) ] } }`For

, see below.**Rep(Tc_i)**

- If

is a**F****wild attribute**specified by a**name**

and**A****tuple**

, then:**T**

`-A(T)`*yields*`Rep(F)`:

`{ attribute, LINE, A, T }`

- If

is a**F****function declaration**where each

is a**Fc_i****function clause**

with a**pattern sequence**of the same length (i.e.,

), then:**Arity**

`Name Fc_1 ; ... ; Name Fc_k`*yields*`Rep(F)`:

`{ function, LINE, Name, Arity,`

`[ Rep(Fc_1), ...,Rep(Fc_k) ] }`

- If

is a**T****fun type clause**where

and**A_i**

are**Ret****types**, then:

`( A_1, ..., A_n ) -> Ret`*yields*`Rep(T)`:

`{ type, LINE, 'fun',`

`[ { type, LINE, product,`

`[ Rep(A_1), ..., Rep(A_n) ] },`

`Rep(Ret) ] }`

- If

is a**T****bounded fun type clause**, where

is an**Tc****unbounded fun type clause**

and

is a**Tg****type guard sequence**, then:

`Tc when Tg`*yields*`Rep(T)`:

`{ type, LINE, bounded_fun,`

`[ Rep(Tc), Rep(Tg) ] }`

Legal guards in Erlang are boolean functions placed after the key word, "when" and before the arrow, "->". Guards may appear as part of a function definition or in "receive", 'if', "case", and "try/catch" expressions. -- Erlang Programming/guards

- If

is a**G****type guard**based on a**constraint**,

where

is an**A****atom**and each

is a**T_i****type**, then:

`A( T_1, ..., T_k )`*yields*`Rep(G)`:

`{ type, LINE, constraint,`

`[ Rep(A),`

`[ Rep(T_1), ..., Rep(T_k) ] ] }`

- If

is a**G****type guard**based on a**type definition**,

where

is a**Name****variable**and

is a**Type****type**, then:

`Name :: Type`*yields*`Rep(G)`:

`{ type, LINE, constraint,`

`[ { atom, LINE, is_subtype},`

`[ Rep(Name), Rep(Type) ] ] }`

Types describe sets of Erlang terms. Types consist of, and are built from, a set of predefined types, for example,`,`

integer()`, and`

atom()`. Predefined types represent a typically infinite set of Erlang terms that belong to this type. For example, the type`

pid()`stands for the set of all Erlang atoms. -- Types and Function Specifications`

atom()

- If

is a**T****type definition**where

is a**Name****variable**and

is a**Type****type**, then:

`Name :: Type`*yields*`Rep(T)`:

`{ ann_type, LINE,`

`[ Rep(Name), Rep(Type) ] }`

- If

is a**T****type union**where each

is a**A_i****type**, then:

`A_1 | ... | A_k`*yields*`Rep(T)`:

`{ type, LINE, union,`

`[ Rep(A_1), ..., Rep(A_k) ] }`

- If

is a**T****type range**where

and**L**

are**R****types**, then:

`L .. R`*yields*`Rep(T)`:

`{ type, LINE, range,`

`[ Rep(L), Rep(R) ] }`

- If

is a**T****binary operation**where

is an**Op****arithmetic**or**bitwise binary operator**

and

and**L**

are**R****types**, then:

`L Op R`*yields*`Rep(T)`:

`{ op, LINE, Op, Rep(L), Rep(R) }`

- If

is an**Op****arithmetic**or**bitwise unary operator**and

is a**A****type**, then:

`Op A`*yields*`Rep(T)`:

`{ op, LINE, Op, Rep(A) }`

- If

is a**T****fun type**, then:

`fun()`*yields*`Rep(T)`:

`{ type, LINE, 'fun', [] }`

- If

is a**T****variable**

, where**V**

is an**A****atom**with a**printname**

consisting of the same characters as

, then:**V**

`V`*yields*`Rep(T)`:

`{ var, LINE, A }`

- If

is an**T****atomic literal**

which is**L***not*a**string literal**, then:

`L`*yields*`Rep(T)`:

`Rep(L)`

- If

is a**T****tuple type**or**map type**(i.e.,

or**tuple**

), then:**map**

`F()`*yields*`Rep(T)`:

`{ type, LINE, F, any }`

- If

is a**T****type**named

where each**F**

is a**A_i****type**, then:

`F( A_1, ..., A_k )`*yields*`Rep(T)`:

`{ user_type, LINE, F,`

`[ Rep(A_1), ..., Rep(A_k) ] }`

- If

is a**T****remote type**from**module**

and**Mod****function**

,**Fun**

where each

is a**A_i****type**, then:

`Mod:Fun( A_1, ..., A_k )`*yields*`Rep(T)`:

`{ remote_type, LINE,`

`[ Rep(Mod), Rep(Fun),`

`[ Rep(A_1), ..., Rep(A_k) ] ] }`

- If

is the**T****nil type**, then:

`[]`*yields*`Rep(T)`:

`{ type, LINE, nil, [] }`

- If

is a**T****list type**where

is a**A****type**, then:

`[ A ]`*yields*`Rep(T)`:

`{ type, LINE, list,`

`[ Rep(A) ] }`

- If

is a**T****non-empty list type**where

is a**A****type**, then:

`[ A, ... ]`*yields*`Rep(T)`:

`{ type, LINE, nonempty_list,`

`[ Rep(A) ] }`

- If

is a**T****map type**where each

is a**P_i****map pair type**, then:

`#{ P_1, ..., P_k }`*yields*`Rep(T)`:

`{ type, LINE, map,`

`[ Rep(P_1), ..., Rep(P_k) ] }`

- If

is a**T****map pair type**where

and**K**

are**V****types**, then:

`K => V`*yields*`Rep(T)`:

`{ type, LINE, map_field_assoc,`

`[ Rep(K), Rep(V) ] }`

- If

is a**T****tuple type**where each

is a**A_i****type**, then:

`{ A_1, ..., A_k }`*yields*`Rep(T)`:

`{ type, LINE, tuple,`

`[ Rep(A_1), ..., Rep(A_k) ] }`

- If

is a**T****record type**where

is an**Name****atom**, then:

`#Name{}`*yields*`Rep(T)`:

`{ type, LINE, record,`

`[ [ Rep(Name) ] }`

- If

is a**T****record type**where

is an**Name****atom**and

are**F_i****fields**, then:

`#Name{ F_1, ..., F_k }`*yields*`Rep(T)`:

`{ type, LINE, record,`

`[ Rep(Name),`

`[ [ Rep(F_1), ..., Rep(F_k) ] ] }`

- If

is a**T****record field type**where

is an**Name****atom**and

is a**Type****type**, then:

`Name :: Type`*yields*`Rep(T)`:

`{ type, LINE, field_type,`

`[ Rep(Name), Rep(Type) ] }`

- If

is a**T****record field type**, then:

`<<>>`*yields*`Rep(T)`:

`{ type, LINE, binary,`

`[ { integer, LINE, 0 },`

`[ { integer, LINE, 0 } ] }`

- If

is a**T****binary type**where

is a**B****type**, then:

`<< _ : B >>`*yields*`Rep(T)`:

`{ type, LINE, binary,`

`[ Rep(B),`

`[ { integer, LINE, 0 } ] }`

- If

is a**T****binary type**where

is a**U****type**, then:

`<< _ : _ * U >>`*yields*`Rep(T)`:

`{ type, LINE, binary,`

`[ { integer, LINE, 0 },`

`Rep(U) ] }`

- If

is a**T****binary type**where

and**B**

are**U****types**, then:

`<< _ : B , _ : _ * U >>`*yields*`Rep(T)`:

`{ type, LINE, binary,`

`[ [ Rep(B), Rep(U) ] }`

- If

is a**T****fun type**and

is a**Ret****return type**, then:

`fun( (...) -> Ret )`*yields*`Rep(T)`:

`{ type, LINE, 'fun',`

`[ { type, LINE, product, [] },`

`Rep(Ret) ] }`

- If

is a**T****fun type**where

is an**Tc****unbounded fun type clause**, then:

`fun(Tc)`*yields*`Rep(T)`:

`Rep(Tc)`

A record is a data structure for storing a fixed number of elements. It has named fields and is similar to a struct in C. Record expressions are translated to tuple expressions during compilation. -- Records (Erlang Reference Manual User's Guide)

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

- In

, if**V**

is an**A****atom**, then:

`A`*yields*`Rep(V)`:

`{ record_field, LINE, Rep(A) }`

- In

, if**V**

is an**A****atom**and

is an**E****expression**, then:

`A = E`*yields*`Rep(V)`:

`{ record_field, LINE, Rep(A), Rep(E) }`

- In

, if**V**

is an**A****atom**and

is a valid**T****type**, then:

`A :: T`*yields*`Rep(V)`:

`{ typed_record_field,`

`{ record_field, LINE, Rep(A) },`

`Rep(undefined | T) }`Note that if

is an**T****annotated type**, it will be wrapped in parentheses.

- In

, if**V**

is an**A****atom**and

is a**T****type**, then:

`A :: T`*yields*`Rep(V)`:

`{ typed_record_field,`

`{ record_field, LINE, Rep(A) },`

`Rep(T) }`

- In

, if**V**

is an**A****atom**,

is an**E****expression**, and

is a**T****type**, then:

`A = E :: T`*yields*`Rep(V)`:

`{ typed_record_field,`

`{ record_field, LINE, Rep(A), Rep(E) },`

`Rep(T) }`

**erl_parse**

and **epp**

) may contain tuples
that indicate exceptional situations.
- Syntactically incorrect forms are denoted by

.**{ error, E }**

- Warnings are denoted by

.**{ warning, W }**

- An end of file (i.e., stream) encountered during the parsing of a form is denoted by

.**{ eof, LINE }**

- If

is an**L****integer**or**character literal**, then:

`L`*yields*`Rep(L)`:

`{ integer, LINE, L }`

- If

is a**L****float literal**, then:

`L`*yields*`Rep(L)`:

`{ float, LINE, L }`

- If

is a**L****string literal**consisting of the characters

, then:**C_1, ..., C_k**

`L`*yields*`Rep(L)`:

`{ string, LINE,`

`[ C_1, ..., C_k ] }`

- If

is an**L****atom literal**, then:

`L`*yields*`Rep(L)`:

`{ atom, LINE, L }`

- If

is a sequence of**Ps****patterns**

, then:**P_i**

`P_1, ..., P_k`*yields*`Rep(Ps)`:

`[ Rep(P_1), ..., Rep(P_k) ]`Such sequences occur as the list of arguments to a function or fun.

- If

is an**P****atomic literal**

, then:**L**

`L`*yields*`Rep(P)`:

`Rep(L)`

- If

is a**P****compound pattern**composed of

and**P_1**

, then:**P_2**

`P_1 = P_2`*yields*`Rep(P)`:

`{ match, LINE, Rep(P_1), Rep(P_2) }`

- If

is a**P****variable pattern**, where

is an**A****atom**with a**printname**

consisting of the same characters as

, then:**V**

`V`*yields*`Rep(P)`:

`{ var, LINE, A },`

- If

is a**P****universal pattern**, then:

`_`*yields*`Rep(P)`:

`{ var, LINE, '_' }`

- If

is a**P****tuple pattern**containing

, then:**P_i**

`{ P_1, ..., P_k }`*yields*`Rep(P)`:

`{ tuple, LINE,`

`[ Rep(P_1), ..., Rep(P_k) ] }`

- If

is a**P****nil pattern**, then:

`[]`*yields*`Rep(P)`:

`{ nil, LINE }`

- If

is a**P****cons pattern**composed of**patterns**

(head) and**P_h**

(tail), then:**P_t**

`[ P_h | P_t ]`*yields*`Rep(P)`:

`{ cons, LINE, Rep(P_h), Rep(P_t) }`

- If

is a**E****binary pattern**composed of**sizes**

and**Size_1****type specifier lists**

, then:**TSL_i**

`<<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>>`*yields*`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

, see below. An omitted**Rep(TSL)**

is represented by default.**Size**

An omitted

(type specifier list) is represented by default.**TSL**

- In

, if**P**

is a**Op****binary operator**and

are**P_i****patterns**, then:

`P_1 Op P_2`*yields*`Rep(P)`:

`{ op, LINE, Op, Rep(P_1), Rep(P_2) }`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.

- In

, if**P**

is a**Op****unary operator**and

is a**P_0****pattern**, then:

`Op P_0`*yields*`Rep(P)`:

`{ op, LINE, Op, Rep(P_0) }`This is an occurrence of an expression that can be evaluated to a number at compile time.

- If

is a**P****record pattern**where

are**Field_i****fields**and

are**P_i****patterns**, then:

`#Name{Field_1=P_1, ..., Field_k=P_k}`*yields*`Rep(P)`:

`{ record, LINE, Name,`

`[ { record_field, LINE, Rep(Field_1), Rep(P_1) }, ...,`

`{ record_field, LINE, Rep(Field_k), Rep(P_k) } ] }`

- If

is a**P****record pattern**where

is a**Field****field**and

is a**Name****record**, then:

`#Name.Field`*yields*`Rep(P)`:

`{ record_index, LINE, Name, Rep(Field) }`

- If

is a**P****parenthesized pattern**with

as its**P_0****body**, then:

`( P_0 )`*yields*`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 represented the same way as the corresponding expression.

- If a
**body**

is a sequence of**B****expressions**

, then:**E_i**

`E_1, ..., E_k`*yields*`Rep(B)`:

`[ Rep(E_1), ..., Rep(E_k) ]`

**E**

is one of the following alternatives:
- If

is an**P****atomic literal**

, then:**L**

`Rep(P) = Rep(L)`

- In

, if**E**

is an**E_0****expression**and

is a**P****pattern**, then:

`P = E_0`*yields*`Rep(E)`:

`{ match, LINE, Rep(P), Rep(E_0) }`

- In

, if**E**

is a**V****variable**and

is an**A****atom**with a**printname**

consisting of the same characters as

, then:**V**

`Rep(E) = { var, LINE, A }`

- If

is a**E****tuple skeleton**containing**expressions**

, then:**E_i**

`{ E_1, ..., E_k }`*yields*`Rep(E)`:

`{ tuple, LINE,`

`[ Rep(E_1), ..., Rep(E_k) ] }`

- If

is an**E****empty list**, then:

`[]`*yields*`Rep(E)`:

`{ nil, LINE }`

- If

is a**E****cons skeleton**composed of expressions

(head) and**E_h**

(tail), then:**E_t**

`[ E_h | E_t ]`*yields*`Rep(E)`:

`{ cons, LINE, Rep(E_h), Rep(E_t) }`

- If

is a**E****binary construct**, then:

`<<V_1:Size_1/TSL_1, ..., V_k:Size_k/TSL_k>>`*yields*`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

, see below. An omitted**Rep(TSL)**

is represented by default.**Size**

An omitted

(type specifier list) is represented by default.**TSL**

- In

, if**E**

is a**Op****binary operator**, then:

`E_1 Op E_2`*yields*`Rep(E)`:

`{ op, LINE, Op, Rep(E_1), Rep(E_2) }`

- In

, if**E**

is a**Op****unary operator**, then:

`Op E_0`*yields*`Rep(E)`:

`{ op, LINE, Op, Rep(E_0) }`

- In

, if**E**

is a**Name****record name**,

are**E_i****expressions**, and

are**Field_i****field names**, then:

`#Name{Field_1=E_1, ..., Field_k=E_k}`*yields*`Rep(E)`:

`{ record, LINE, Name,`

`[ { record_field, LINE, Rep(Field_1), Rep(E_1) }, ...,`

`{ record_field, LINE, Rep(Field_k), Rep(E_k) } ] }`

- In

, if**E**

is an**E_0****expression**which evaluates to a**Name****record**,

the other

are**E_i****expressions**, and

are**Field_i****field names**, then:

`E_0#Name{Field_1=E_1, ..., Field_k=E_k}`*yields*`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) } ] }`

- In

, if**E**

is a**Name****record name**and

is a**Field****field name**, then:

`#Name.Field`*yields*`Rep(E)`:

`{ record_index, LINE, Name, Rep(Field) }`

- In

, if**E**

is an**E_0****expression**which evaluates to a**Name****record**

and

is a**Field****field name**, then:

`E_0#Name.Field`*yields*`Rep(E)`:

`{ record_field, LINE, Rep(E_0), Name, Rep(Field) }`

- In

, if each**E**

is a**W_i****map assoc**or**exact field**, then:

`#{ W_1, ..., W_k }`*yields*`Rep(E)`:

`{ map, LINE,`

`[ Rep(W_1), ..., Rep(W_k) ] }`For

, see below.**Rep(W)**

- In

, if each**E**

is a**W_i****map assoc**or**exact field**, then:

`E_0#{ W_1, ..., W_k }`*yields*`Rep(E)`:

`{ map, LINE, Rep(E_0),`

`[ Rep(W_1), ..., Rep(W_k) ] }`For

, see below.**Rep(W)**

- In

, if**E**

is a**E_0****catch expression**, then:

`catch E_0`*yields*`Rep(E)`:

`{ 'catch', LINE, Rep(E_0) }`

- In

, if**E**

is a**E_0****function name**and

are**E_i****arguments**, then:

`E_0( E_1, ..., E_k )`*yields*`Rep(E)`:

`{ call, LINE, Rep(E_0),`

`[ Rep(E_1), ..., Rep(E_k) ] }`

- In

, if**E**

is a**E_m****module name**,

is a**E_0****function name**,

and the remaining

are**E_i****arguments**, then:

`E_m:E_0( E_1, ..., E_k )`*yields*`Rep(E)`:

`{ call, LINE,`

`{ remote, LINE, Rep(E_m), Rep(E_0) },`

`[ Rep(E_1), ..., Rep(E_k) ] }`

- If

is a**E****list comprehension**where

is the**E_0****resulting data structure**

and each

is a**W_i****generator**or a**filter**, then:

`[ E_0 || W_1, ..., W_k ]`*yields*`Rep(E)`:

`{ lc, LINE, Rep(E_0),`

`[ Rep(W_1), ..., Rep(W_k) ] }`For

, see below.**Rep(W)**

- If

is a**E****binary comprehension**where

is the**E_0****resulting data structure**

and each

is a**W_i****generator**or a**filter**, then:

`<<E_0 || W_1, ..., W_k>>`*yields*`Rep(E)`:

`{ bc, LINE, Rep(E_0),`

`[ Rep(W_1), ..., Rep(W_k) ] }`For

, see below.**Rep(W)**

- In

, if**E**

is a**B****body**, then:

`begin B end`*yields*`Rep(E)`:

`{ block, LINE, Rep(B) }`

- In

, if each**E**

is an**Ic_i****if clause**, then:

`if Ic_1 ; ... ; Ic_k end`*yields*`Rep(E)`:

`{ 'if', LINE,`

`[ Rep(Ic_1), ..., Rep(Ic_k) ] }`

- In

, if**E**

is an**E_0****expression**and each

is a**Cc_i****case clause**, then:

`case E_0 of Cc_1 ; ... ; Cc_k end`*yields*`Rep(E)`:

`{ 'case', LINE, Rep(E_0),`

`[ Rep(Cc_1), ..., Rep(Cc_k) ] }`

- In

, if**E**

is a**B****body**and each

is a**Tc_i****catch clause**, then:

`try B catch Tc_1 ; ... ; Tc_k end`*yields*`Rep(E)`:

`{ 'try', LINE, Rep(B), [],`

`[ Rep(Tc_1), ..., Rep(Tc_k) ],`

`[] }`

- In

, if**E**

is a**B****body**, each

is a**Cc_i****case clause**, and each

is a**Tc_j****catch clause**, then:

`try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end`*yields*`Rep(E)`:

`{ 'try', LINE, Rep(B),`

`[ Rep(Cc_1), ..., Rep(Cc_k) ],`

`[ Rep(Tc_1), ..., Rep(Tc_n) ], [] }`

- In

, if**E**

and**B**

are**A****bodies**, then:

`try B after A end`*yields*`Rep(E)`:

`{ 'try', LINE, Rep(B), [], [], Rep(A) }`

- In

, if**E**

and**B****A****are bodies**and each

is a**Cc_i****case clause**, then:

`try B of Cc_1 ; ... ; Cc_k after A end`*yields*`Rep(E)`:

`{ 'try', LINE, Rep(B),`

`[ Rep(Cc_1), ..., Rep(Cc_k) ],`

`[], Rep(A) }`

- In

, if**E**

and**B**

are**A****bodies**and each

is a**Tc_i****catch clause**, then:

`try B catch Tc_1 ; ... ; Tc_k after A end`*yields*`Rep(E)`:

`{ 'try', LINE, Rep(B), [],`

`[ Rep(Tc_1), ..., Rep(Tc_k) ],`

`Rep(A) }`

- In

, if**E**

and**B**

are**A****bodies**, each

is a**Cc_i****case clause**, and each

is a**Tc_j****catch clause**, then:

`try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end`*yields*`Rep(E)`:

`{ 'try', LINE, Rep(B),`

`[ Rep(Cc_1), ..., Rep(Cc_k) ],`

`[ Rep(Tc_1), ..., Rep(Tc_n) ],`

`Rep(A) }`

- In

, if each**E**

is a**Cc_i****case clause**, then:

`receive Cc_1 ; ... ; Cc_k end`*yields*`Rep(E)`:

`{ 'receive', LINE,`

`[ Rep(Cc_1), ..., Rep(Cc_k) ] }`

- In

, if each**E**

is a**Cc_i****case clause**,

is an**E_0****expression**, and

is a**B_t****body**, then:

`receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end`*yields*`Rep(E)`:

`{ 'receive', LINE,`

`[ Rep(Cc_1), ..., Rep(Cc_k) ],`

`Rep(E_0), Rep(B_t) }`

- In

, if**E**

is a**Name****function name**and

is the**Arity****arity**, then:

`fun Name / Arity`*yields*`Rep(E)`:

`{ 'fun', LINE,`

`{ function, Name, Arity} }`

- In

, if**E**

is a**Module****module name**,

is a**Name****function name**, and

is the**Arity****arity**, then:

`fun Module:Name/Arity`*yields*`Rep(E)`:

`{ 'fun', LINE,`

`{ function, Rep(Module), Rep(Name), Rep(Arity) } }`Before the R15 release, this was:

`Rep(E) = {'fun', LINE,`

`{ function, Module, Name, Arity } }`

- In

, if each**E**

is a**Fc_i****function clause**, then:

`fun Fc_1 ; ... ; Fc_k end`*yields*`Rep(E)`:

`{ 'fun', LINE,`

`{ clauses,`

`[ Rep(Fc_1), ..., Rep(Fc_k) ] } }`

- In

, if**E**

is a**Name****variable**and each

is a**Fc_i****function clause**, then:

`fun Name Fc_1 ; ... ; Name Fc_k end`*yields*`Rep(E)`:

`{ named_fun, LINE, Name,`

`[ Rep(Fc_1), ..., Rep(Fc_k) ] }`

- In
**query**

, if each**E**

is a**W_i****generator**or a**filter**, then:

`[ E_0 || W_1, ..., W_k ] end`*yields*`Rep(E)`:

`{ 'query', LINE,`

`{ lc, LINE, Rep(E_0),`

`[ Rep(W_1), ..., Rep(W_k) ] } }`For

, see below.**Rep(W)**

- If

is a**E****Mnesia record access**inside a**query**where

is ??? and**E_0**

is ???, then:**Field**

`E_0.Field`*yields*`Rep(E)`:

`{ record_field, LINE, Rep(E_0), Rep(Field) }`

- In

, if**E**

is an**E_0****expression**, then:

`( E_0 )`*yields*`Rep(E)`:

`Rep(E_0)`That is, parenthesized expressions cannot be distinguished from their bodies.

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

**W**

is a - If

is a**W****generator**, where

is a**P****pattern**and

is an**E****expression**, then:

`P <- E`*yields*`Rep(W)`:

`{ generate, LINE, Rep(P), Rep(E) }`

- If

is a**W****generator**, where

is a**P****pattern**and

is an**E****expression**, then:

`P <= E`*yields*`Rep(W)`:

`{ b_generate, LINE, Rep(P), Rep(E) }`

- If

is a**W****filter**

, which is an**E****expression**, then:

`Rep(W) = Rep(E)`

- If a
**type specifier list**

for a**TSL****binary element**is a sequence of**type specifiers**, then:

`TS_1 - ... - TS_k`*yields*`Rep(TSL)`:

`[ Rep(TS_1), ..., Rep(TS_k) ]`

**TS**

is a - If

is an**TS****atom**, then:`A`*yields*`Rep(TS)`:

`A`

- If

is a**TS****couple**, where

is an**A****atom**and

is an**Value****integer**, then:

`A:Value`*yields*`Rep(TS)`:

`{ A, Value }`

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

**W**

is an - If

is an**W****assoc field**, where

and**K**

are both**V****expressions**, then:

`K => V`*yields*`Rep(W)`:

`{ map_field_assoc, LINE, Rep(K), Rep(V) }`

- If

is an**W****exact field**, where

and**K**

are both**V****expressions**, then:

`K := V`*yields*`Rep(W)`:

`{ map_field_exact, LINE, Rep(K), Rep(V) }`

There are function clauses, if clauses, case clauses, and catch clauses.
A clause C is one of the following alternatives:

- If

is a**C****function clause**where

is a**Ps****pattern sequence**and

is a**B****body**, then:

`( Ps ) -> B`*yields*`Rep(C)`:

`{ clause, LINE, Rep(Ps), [], Rep(B) }`

- If

is a**C****function clause**where

is a**Ps****pattern sequence**,

is a**Gs****guard sequence**, and

is a**B****body**, then:

`( Ps ) when Gs -> B`*yields*`Rep(C)`:

`{ clause, LINE, Rep(Ps), Rep(Gs), Rep(B) }`

- If

is an**C****if clause**where

is a**Gs****guard sequence**and

is a**B****body**, then:

`Gs -> B`*yields*`Rep(C)`:

`{ clause, LINE, [], Rep(Gs), Rep(B) }`

- If

is a**C****case clause**where

is a**P****pattern**and

is a**B****body**, then:

`P -> B`*yields*`Rep(C)`:

`{ clause, LINE,`

`[ Rep(P) ],`

`[], Rep(B) }`

- If

is a**C****case clause**where

is a**P****pattern**,

is a**Gs****guard sequence**, and

is a**B****body**, then:

`P when Gs -> B`*yields*`Rep(C)`:

`{ clause, LINE,`

`[ Rep(P) ],`

`Rep(Gs), Rep(B) }`

- If

is a**C****catch clause**where

is a**P****pattern**and

is a**B****body**, then:

`P -> B`*yields*`Rep(C)`:

`{ clause, LINE,`

`[ Rep( { throw, P, _ } ) ],`

`[], Rep(B) }`

- If

is a**C****catch clause**where

is an**X****atomic literal**or a**variable pattern**,

is a**P****pattern**, and

is a**B****body**, then:

`X : P -> B`*yields*`Rep(C)`:

`{ clause, LINE,`

`[ Rep( { X, P, _ } ) ],`

`[], Rep(B) }`

- If

is a**C****catch clause**where

is a**P****pattern**,

is a**Gs****guard sequence**, and

is a**B****body**, then:

`P when Gs -> B`*yields*`Rep(C)`:

`{ clause, LINE,`

`[ Rep( { throw, P, _ } ) ],`

`Rep(Gs), Rep(B) }`

- If

is a**C****catch clause**where

is an**X****atomic literal**or a**variable pattern**,

is a**P****pattern**,

is a**Gs****guard sequence**, and

is a**B****body**, then:

`X : P when Gs -> B`*yields*`Rep(C)`:

`{ clause, LINE,`

`[ Rep( { X, P, _ } ) ],`

`Rep(Gs), Rep(B) }`

- If a
**guard sequence**

is a sequence of**Gs****guards**

, then:**G_i**

`G_1; ...; G_k`*yields*`Rep(Gs)`:

`[ Rep(G_1), ..., Rep(G_k) ]`

- If the
**guard sequence**is empty,

.**Rep(Gs) = []**

- If a guard

is a nonempty sequence of guard tests, then:**G**

`Gt_1, ..., Gt_k`*yields*`Rep(G)`:

`[ Rep(Gt_1), ..., Rep(Gt_k) ]`

**Gt**

is one of the following alternatives:
- If

is an**Gt****atomic literal**

, then**L**

.**Rep(Gt) = Rep(L)**

- If Gt is a
**variable pattern**

, where**V**

is an**A****atom**with a**printname**

consisting of the same characters as

, then:**V**

`V`*yields*`Rep(Gt)`:

`{ var, LINE, A }`

- If

is a**Gt****tuple skeleton**, then:

`{ Gt_1, ..., Gt_k }`*yields*`Rep(Gt)`:

`{ tuple, LINE,`

`[ Rep(Gt_1), ..., Rep(Gt_k) ] }`

- If

is**Gt**

, then:**[]**

`Rep(Gt) = { nil, LINE }`

- If

is a**Gt****cons skeleton**, then:

`[ Gt_h | Gt_t ]`*yields*`Rep(Gt)`:

`{ cons, LINE, Rep(Gt_h), Rep(Gt_t) }`

- If

is a**Gt****binary constructor**, then:

`<<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>>`*yields*`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

, see above. An omitted**Rep(TSL)**

is represented by default.**Size**

An omitted

(type specifier list) is represented by default.**TSL**

- If

is a**Op****binary operator**, then:

`Gt_1 Op Gt_2`*yields*`Rep(Gt)`:

`{ op, LINE, Op, Rep(Gt_1), Rep(Gt_2) }`

- If

is a**Op****unary operator**, then:

`Op Gt_0`*yields*`Rep(Gt)`:

`{ op, LINE, Op, Rep(Gt_0) }`

- In

, if**Gt**

are ??? and**Field_i**

are ???, then:**Gt_i**

`#Name{ Field_1=Gt_1, ..., Field_k=Gt_k }`*yields*`Rep(Gt)`:

`{ record, LINE, Name,`

`[ { record_field, LINE, Rep(Field_1), Rep(Gt_1) }, ...,`

`{ record_field, LINE, Rep(Field_k), Rep(Gt_k) } ] }`

- In

, if**Gt**

is ??? and**Name**

is ???, then:**Field**

`#Name.Field`*yields*`Rep(Gt)`:

`{ record_index, LINE, Name, Rep(Field) }`

- In

, if**Gt**

is ???,**Gt_0**

is ???, and**Name**

is ???, then:**Field**

`Gt_0#Name.Field`*yields*`Rep(Gt)`:

`{ record_field, LINE, Rep(Gt_0), Name, Rep(Field) }`

- In

, if**Gt**

is an**A****atom**and

are ???, then:**Gt_i**

`A(Gt_1, ..., Gt_k)`*yields*`Rep(Gt)`:

`{ call, LINE, Rep(A),`

`[ Rep(Gt_1), ..., Rep(Gt_k) ] }`

- In

, if**Gt**

is the**A_m****atom**

and**erlang**

is an**A****atom**or an**operator**, then:

`A_m:A(Gt_1, ..., Gt_k)`*yields*`Rep(Gt)`:

`{ call, LINE,`

`{ remote, LINE, Rep(A_m), Rep(A) },`

`[ Rep(Gt_1), ..., Rep(Gt_k) ] }`

- In

, if**Gt**

is the**A_m****atom**

and**erlang**

is an**A****atom**or an**operator**, then:

`{A_m, A}(Gt_1, ..., Gt_k)`*yields*`Rep(Gt)`:

`{ call, LINE, Rep({A_m,A}),`

`[ Rep(Gt_1), ..., Rep(Gt_k) ] }`

- If

is**Gt**

, then**( Gt_0 )****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, and is represented the same way as the corresponding expression.

- If the compilation option

is given to the compiler, the abstract code**debug_info**

will be stored in the

chunk in the BEAM file (for debugging purposes).**abstract_code**

- In OTP R9C and later, the

chunk will contain the tuple**abstract_code**

, where**{ raw_abstract_v1, AbstractCode }**

is the abstract code**AbstractCode**

as described in this document.

- In releases of OTP prior to R9C, the abstract code (after more processing) was stored

in the BEAM file. The first element of the tuple would be either

(R7B)**abstract_v1**

or

(R8B).**abstract_v2**

- Erlang Programming (Wikibooks)

- Parse Tools (PDF)

This wiki page is maintained by Rich Morin, an independent consultant specializing in software design, development, and documentation. Please feel free to email comments, inquiries, suggestions, etc!

Edit | Attach | Print version | History: r22 < r21 < r20 < r19 | Backlinks | View wiki text | More topic actions

Topic revision: r22 - 04 Apr 2016, RichMorin

Copyright © by the contributing authors. All material on this wiki is the property of the contributing authors.

Foswiki version**v2.1.6**, Release **Foswiki-2.1.6**, Plugin API version **2.4**

Ideas, requests, problems regarding CFCL Wiki? Send us email

Foswiki version

Ideas, requests, problems regarding CFCL Wiki? Send us email