aboutsummaryrefslogtreecommitdiffstats
path: root/erts/doc/src/absform.xml
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /erts/doc/src/absform.xml
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'erts/doc/src/absform.xml')
-rw-r--r--erts/doc/src/absform.xml444
1 files changed, 444 insertions, 0 deletions
diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml
new file mode 100644
index 0000000000..4c84412dd6
--- /dev/null
+++ b/erts/doc/src/absform.xml
@@ -0,0 +1,444 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2001</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>The Abstract Format</title>
+ <prepared>Arndt Jonasson</prepared>
+ <responsible>Kenneth Lundin</responsible>
+ <docno>1</docno>
+ <approved>Jultomten</approved>
+ <checked></checked>
+ <date>00-12-01</date>
+ <rev>A</rev>
+ <file>absform.xml</file>
+ </header>
+ <p></p>
+ <p>This document describes the standard representation of parse trees for Erlang
+ programs as Erlang terms. This representation is known as the <em>abstract format</em>.
+ Functions dealing with such parse trees are <c><![CDATA[compile:forms/[1,2]]]></c>
+ and functions in the modules
+ <c><![CDATA[epp]]></c>,
+ <c><![CDATA[erl_eval]]></c>,
+ <c><![CDATA[erl_lint]]></c>,
+ <c><![CDATA[erl_pp]]></c>,
+ <c><![CDATA[erl_parse]]></c>,
+ and
+ <c><![CDATA[io]]></c>.
+ They are also used as input and output for parse transforms (see the module
+ <c><![CDATA[compile]]></c>).</p>
+ <p>We use the function <c><![CDATA[Rep]]></c> to denote the mapping from an Erlang source
+ construct <c><![CDATA[C]]></c> to its abstract format representation <c><![CDATA[R]]></c>, and write
+ <c><![CDATA[R = Rep(C)]]></c>.
+ </p>
+ <p>The word <c><![CDATA[LINE]]></c> below represents an integer, and denotes the
+ number of the line in the source file where the construction occurred.
+ Several instances of <c><![CDATA[LINE]]></c> in the same construction may denote
+ different lines.</p>
+ <p>Since operators are not terms in their own right, when operators are
+ mentioned below, the representation of an operator should be taken to
+ be the atom with a printname consisting of the same characters as the
+ operator.
+ </p>
+
+ <section>
+ <title>Module declarations and forms</title>
+ <p>A module declaration consists of a sequence of forms that are either
+ function declarations or attributes.</p>
+ <list type="bulleted">
+ <item>If D is a module declaration consisting of the forms
+ <c><![CDATA[F_1]]></c>, ..., <c><![CDATA[F_k]]></c>, then
+ Rep(D) = <c><![CDATA[[Rep(F_1), ..., Rep(F_k)]]]></c>.</item>
+ <item>If F is an attribute <c><![CDATA[-module(Mod)]]></c>, then
+ Rep(F) = <c><![CDATA[{attribute,LINE,module,Mod}]]></c>.</item>
+ <item>If F is an attribute <c><![CDATA[-export([Fun_1/A_1, ..., Fun_k/A_k])]]></c>, then
+ Rep(F) = <c><![CDATA[{attribute,LINE,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}]]></c>.</item>
+ <item>If F is an attribute <c><![CDATA[-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])]]></c>, then
+ Rep(F) = <c><![CDATA[{attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}]]></c>.</item>
+ <item>If F is an attribute <c><![CDATA[-compile(Options)]]></c>, then
+ Rep(F) = <c><![CDATA[{attribute,LINE,compile,Options}]]></c>.</item>
+ <item>If F is an attribute <c><![CDATA[-file(File,Line)]]></c>, then
+ Rep(F) = <c><![CDATA[{attribute,LINE,file,{File,Line}}]]></c>.</item>
+ <item>If F is a record declaration <c><![CDATA[-record(Name,{V_1, ..., V_k})]]></c>, then
+ Rep(F) =
+ <c><![CDATA[{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}]]></c>. For Rep(V), see below.</item>
+ <item>If F is a wild attribute <c><![CDATA[-A(T)]]></c>, then
+ Rep(F) = <c><![CDATA[{attribute,LINE,A,T}]]></c>.
+ <br></br></item>
+ <item>If F is a function declaration <c><![CDATA[Name Fc_1 ; ... ; Name Fc_k]]></c>,
+ where each <c><![CDATA[Fc_i]]></c> is a function clause with a
+ pattern sequence of the same length <c><![CDATA[Arity]]></c>, then
+ Rep(F) = <c><![CDATA[{function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}]]></c>.</item>
+ </list>
+
+ <section>
+ <title>Record fields</title>
+ <p>Each field in a record declaration may have an optional
+ explicit default initializer expression</p>
+ <list type="bulleted">
+ <item>If V is <c><![CDATA[A]]></c>, then
+ Rep(V) = <c><![CDATA[{record_field,LINE,Rep(A)}]]></c>.</item>
+ <item>If V is <c><![CDATA[A = E]]></c>, then
+ Rep(V) = <c><![CDATA[{record_field,LINE,Rep(A),Rep(E)}]]></c>.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Representation of parse errors and end of file</title>
+ <p>In addition to the representations of forms, the list that represents
+ a module declaration (as returned by functions in <c><![CDATA[erl_parse]]></c> and
+ <c><![CDATA[epp]]></c>) may contain tuples <c><![CDATA[{error,E}]]></c> and <c><![CDATA[{warning,W}]]></c>, denoting
+ syntactically incorrect forms and warnings, and <c><![CDATA[{eof,LINE}]]></c>, denoting an end
+ of stream encountered before a complete form had been parsed.</p>
+ </section>
+ </section>
+
+ <section>
+ <title>Atomic literals</title>
+ <p>There are five kinds of atomic literals, which are represented in the
+ same way in patterns, expressions and guards:</p>
+ <list type="bulleted">
+ <item>If L is an integer or character literal, then
+ Rep(L) = <c><![CDATA[{integer,LINE,L}]]></c>.</item>
+ <item>If L is a float literal, then
+ Rep(L) = <c><![CDATA[{float,LINE,L}]]></c>.</item>
+ <item>If L is a string literal consisting of the characters
+ <c><![CDATA[C_1]]></c>, ..., <c><![CDATA[C_k]]></c>, then
+ Rep(L) = <c><![CDATA[{string,LINE,[C_1, ..., C_k]}]]></c>.</item>
+ <item>If L is an atom literal, then
+ Rep(L) = <c><![CDATA[{atom,LINE,L}]]></c>.</item>
+ </list>
+ <p>Note that negative integer and float literals do not occur as such; they are
+ parsed as an application of the unary negation operator.</p>
+ </section>
+
+ <section>
+ <title>Patterns</title>
+ <p>If <c><![CDATA[Ps]]></c> is a sequence of patterns <c><![CDATA[P_1, ..., P_k]]></c>, then
+ Rep(Ps) = <c><![CDATA[[Rep(P_1), ..., Rep(P_k)]]]></c>. Such sequences occur as the
+ list of arguments to a function or fun.</p>
+ <p>Individual patterns are represented as follows:</p>
+ <list type="bulleted">
+ <item>If P is an atomic literal L, then Rep(P) = Rep(L).</item>
+ <item>If P is a compound pattern <c><![CDATA[P_1 = P_2]]></c>, then
+ Rep(P) = <c><![CDATA[{match,LINE,Rep(P_1),Rep(P_2)}]]></c>.</item>
+ <item>If P is a variable pattern <c><![CDATA[V]]></c>, then
+ Rep(P) = <c><![CDATA[{var,LINE,A}]]></c>,
+ where A is an atom with a printname consisting of the same characters as
+ <c><![CDATA[V]]></c>.</item>
+ <item>If P is a universal pattern <c><![CDATA[_]]></c>, then
+ Rep(P) = <c><![CDATA[{var,LINE,'_'}]]></c>.</item>
+ <item>If P is a tuple pattern <c><![CDATA[{P_1, ..., P_k}]]></c>, then
+ Rep(P) = <c><![CDATA[{tuple,LINE,[Rep(P_1), ..., Rep(P_k)]}]]></c>.</item>
+ <item>If P is a nil pattern <c><![CDATA[[]]]></c>, then
+ Rep(P) = <c><![CDATA[{nil,LINE}]]></c>.</item>
+ <item>If P is a cons pattern <c><![CDATA[[P_h | P_t]]]></c>, then
+ Rep(P) = <c><![CDATA[{cons,LINE,Rep(P_h),Rep(P_t)}]]></c>.</item>
+ <item>If E is a binary pattern <c><![CDATA[<<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>>]]></c>, then
+ Rep(E) = <c><![CDATA[{bin,LINE,[{bin_element,LINE,Rep(P_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(P_k),Rep(Size_k),Rep(TSL_k)}]}]]></c>.
+ For Rep(TSL), see below.
+ An omitted <c><![CDATA[Size]]></c> is represented by <c><![CDATA[default]]></c>. An omitted <c><![CDATA[TSL]]></c>
+ (type specifier list) is represented by <c><![CDATA[default]]></c>.</item>
+ <item>If P is <c><![CDATA[P_1 Op P_2]]></c>, where <c><![CDATA[Op]]></c> is a binary operator (this
+ is either an occurrence of <c><![CDATA[++]]></c> applied to a literal string or character
+ list, or an occurrence of an expression that can be evaluated to a number
+ at compile time),
+ then Rep(P) = <c><![CDATA[{op,LINE,Op,Rep(P_1),Rep(P_2)}]]></c>.</item>
+ <item>If P is <c><![CDATA[Op P_0]]></c>, where <c><![CDATA[Op]]></c> is a unary operator (this is an
+ occurrence of an expression that can be evaluated to a number at compile
+ time), then Rep(P) = <c><![CDATA[{op,LINE,Op,Rep(P_0)}]]></c>.</item>
+ <item>If P is a record pattern <c><![CDATA[#Name{Field_1=P_1, ..., Field_k=P_k}]]></c>,
+ then Rep(P) =
+ <c><![CDATA[{record,LINE,Name, [{record_field,LINE,Rep(Field_1),Rep(P_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(P_k)}]}]]></c>.</item>
+ <item>If P is <c><![CDATA[#Name.Field]]></c>, then
+ Rep(P) = <c><![CDATA[{record_index,LINE,Name,Rep(Field)}]]></c>.</item>
+ <item>If P is <c><![CDATA[( P_0 )]]></c>, then
+ Rep(P) = <c><![CDATA[Rep(P_0)]]></c>,
+ i.e., patterns cannot be distinguished from their bodies.</item>
+ </list>
+ <p>Note that every pattern has the same source form as some expression, and is
+ represented the same way as the corresponding expression.</p>
+ </section>
+
+ <section>
+ <title>Expressions</title>
+ <p>A body B is a sequence of expressions <c><![CDATA[E_1, ..., E_k]]></c>, and
+ Rep(B) = <c><![CDATA[[Rep(E_1), ..., Rep(E_k)]]]></c>.</p>
+ <p>An expression E is one of the following alternatives:</p>
+ <list type="bulleted">
+ <item>If P is an atomic literal <c><![CDATA[L]]></c>, then
+ Rep(P) = Rep(L).</item>
+ <item>If E is <c><![CDATA[P = E_0]]></c>, then
+ Rep(E) = <c><![CDATA[{match,LINE,Rep(P),Rep(E_0)}]]></c>.</item>
+ <item>If E is a variable <c><![CDATA[V]]></c>, then
+ Rep(E) = <c><![CDATA[{var,LINE,A}]]></c>,
+ where <c><![CDATA[A]]></c> is an atom with a printname consisting of the same
+ characters as <c><![CDATA[V]]></c>.</item>
+ <item>If E is a tuple skeleton <c><![CDATA[{E_1, ..., E_k}]]></c>, then
+ Rep(E) = <c><![CDATA[{tuple,LINE,[Rep(E_1), ..., Rep(E_k)]}]]></c>.</item>
+ <item>If E is <c><![CDATA[[]]]></c>, then
+ Rep(E) = <c><![CDATA[{nil,LINE}]]></c>.</item>
+ <item>If E is a cons skeleton <c><![CDATA[[E_h | E_t]]]></c>, then
+ Rep(E) = <c><![CDATA[{cons,LINE,Rep(E_h),Rep(E_t)}]]></c>.</item>
+ <item>If E is a binary constructor <c><![CDATA[<<V_1:Size_1/TSL_1, ..., V_k:Size_k/TSL_k>>]]></c>, then
+ Rep(E) = <c><![CDATA[{bin,LINE,[{bin_element,LINE,Rep(V_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(V_k),Rep(Size_k),Rep(TSL_k)}]}]]></c>.
+ For Rep(TSL), see below.
+ An omitted <c><![CDATA[Size]]></c> is represented by <c><![CDATA[default]]></c>. An omitted <c><![CDATA[TSL]]></c>
+ (type specifier list) is represented by <c><![CDATA[default]]></c>.</item>
+ <item>If E is <c><![CDATA[E_1 Op E_2]]></c>, where <c><![CDATA[Op]]></c> is a binary operator,
+ then Rep(E) = <c><![CDATA[{op,LINE,Op,Rep(E_1),Rep(E_2)}]]></c>.</item>
+ <item>If E is <c><![CDATA[Op E_0]]></c>, where <c><![CDATA[Op]]></c> is a unary operator, then
+ Rep(E) = <c><![CDATA[{op,LINE,Op,Rep(E_0)}]]></c>.</item>
+ <item>If E is <c><![CDATA[#Name{Field_1=E_1, ..., Field_k=E_k}]]></c>, then
+ Rep(E) =
+ <c><![CDATA[{record,LINE,Name, [{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}]]></c>.</item>
+ <item>If E is <c><![CDATA[E_0#Name{Field_1=E_1, ..., Field_k=E_k}]]></c>, then
+ Rep(E) =
+ <c><![CDATA[{record,LINE,Rep(E_0),Name, [{record_field,LINE,Rep(Field_1),Rep(E_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(E_k)}]}]]></c>.</item>
+ <item>If E is <c><![CDATA[#Name.Field]]></c>, then
+ Rep(E) = <c><![CDATA[{record_index,LINE,Name,Rep(Field)}]]></c>.</item>
+ <item>If E is <c><![CDATA[E_0#Name.Field]]></c>, then
+ Rep(E) = <c><![CDATA[{record_field,LINE,Rep(E_0),Name,Rep(Field)}]]></c>.</item>
+ <item>If E is <c><![CDATA[catch E_0]]></c>, then
+ Rep(E) = <c><![CDATA[{'catch',LINE,Rep(E_0)}]]></c>.</item>
+ <item>If E is <c><![CDATA[E_0(E_1, ..., E_k)]]></c>, then
+ Rep(E) = <c><![CDATA[{call,LINE,Rep(E_0),[Rep(E_1), ..., Rep(E_k)]}]]></c>.</item>
+ <item>If E is <c><![CDATA[E_m:E_0(E_1, ..., E_k)]]></c>, then
+ Rep(E) =
+ <c><![CDATA[{call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]}]]></c>.</item>
+ <item>If E is a list comprehension <c><![CDATA[[E_0 || W_1, ..., W_k]]]></c>,
+ where each <c><![CDATA[W_i]]></c> is a generator or a filter, then
+ Rep(E) = <c><![CDATA[{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}]]></c>. For Rep(W), see
+ below.</item>
+ <item>If E is a binary comprehension <c><![CDATA[<<E_0 || W_1, ..., W_k>>]]></c>,
+ where each <c><![CDATA[W_i]]></c> is a generator or a filter, then
+ Rep(E) = <c><![CDATA[{bc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}]]></c>. For Rep(W), see
+ below.</item>
+ <item>If E is <c><![CDATA[begin B end]]></c>, where <c><![CDATA[B]]></c> is a body, then
+ Rep(E) = <c><![CDATA[{block,LINE,Rep(B)}]]></c>.</item>
+ <item>If E is <c><![CDATA[if Ic_1 ; ... ; Ic_k end]]></c>,
+ where each <c><![CDATA[Ic_i]]></c> is an if clause then
+ Rep(E) =
+ <c><![CDATA[{'if',LINE,[Rep(Ic_1), ..., Rep(Ic_k)]}]]></c>.</item>
+ <item>If E is <c><![CDATA[case E_0 of Cc_1 ; ... ; Cc_k end]]></c>,
+ where <c><![CDATA[E_0]]></c> is an expression and each <c><![CDATA[Cc_i]]></c> is a
+ case clause then
+ Rep(E) =
+ <c><![CDATA[{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]}]]></c>.</item>
+ <item>If E is <c><![CDATA[try B catch Tc_1 ; ... ; Tc_k end]]></c>,
+ where <c><![CDATA[B]]></c> is a body and each <c><![CDATA[Tc_i]]></c> is a catch clause then
+ Rep(E) =
+ <c><![CDATA[{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],[]}]]></c>.</item>
+ <item>If E is <c><![CDATA[try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end]]></c>,
+ where <c><![CDATA[B]]></c> is a body,
+ each <c><![CDATA[Cc_i]]></c> is a case clause and
+ each <c><![CDATA[Tc_j]]></c> is a catch clause then
+ Rep(E) =
+ <c><![CDATA[{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],[]}]]></c>.</item>
+ <item>If E is <c><![CDATA[try B after A end]]></c>,
+ where <c><![CDATA[B]]></c> and <c><![CDATA[A]]></c> are bodies then
+ Rep(E) =
+ <c><![CDATA[{'try',LINE,Rep(B),[],[],Rep(A)}]]></c>.</item>
+ <item>If E is <c><![CDATA[try B of Cc_1 ; ... ; Cc_k after A end]]></c>,
+ where <c><![CDATA[B]]></c> and <c><![CDATA[A]]></c> are a bodies and
+ each <c><![CDATA[Cc_i]]></c> is a case clause then
+ Rep(E) =
+ <c><![CDATA[{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[],Rep(A)}]]></c>.</item>
+ <item>If E is <c><![CDATA[try B catch Tc_1 ; ... ; Tc_k after A end]]></c>,
+ where <c><![CDATA[B]]></c> and <c><![CDATA[A]]></c> are bodies and
+ each <c><![CDATA[Tc_i]]></c> is a catch clause then
+ Rep(E) =
+ <c><![CDATA[{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],Rep(A)}]]></c>.</item>
+ <item>If E is <c><![CDATA[try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end]]></c>,
+ where <c><![CDATA[B]]></c> and <c><![CDATA[A]]></c> are a bodies,
+ each <c><![CDATA[Cc_i]]></c> is a case clause and
+ each <c><![CDATA[Tc_j]]></c> is a catch clause then
+ Rep(E) =
+ <c><![CDATA[{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],Rep(A)}]]></c>.</item>
+ <item>If E is <c><![CDATA[receive Cc_1 ; ... ; Cc_k end]]></c>,
+ where each <c><![CDATA[Cc_i]]></c> is a case clause then
+ Rep(E) =
+ <c><![CDATA[{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]}]]></c>.</item>
+ <item>If E is <c><![CDATA[receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end]]></c>,
+ where each <c><![CDATA[Cc_i]]></c> is a case clause,
+ <c><![CDATA[E_0]]></c> is an expression and <c><![CDATA[B_t]]></c> is a body, then
+ Rep(E) =
+ <c><![CDATA[{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)}]]></c>.</item>
+ <item>If E is <c><![CDATA[fun Name / Arity]]></c>, then
+ Rep(E) = <c><![CDATA[{'fun',LINE,{function,Name,Arity}}]]></c>.</item>
+ <item>If E is <c><![CDATA[fun Module:Name/Arity]]></c>, then
+ Rep(E) = <c><![CDATA[{'fun',LINE,{function,Module,Name,Arity}}]]></c>.</item>
+ <item>If E is <c><![CDATA[fun Fc_1 ; ... ; Fc_k end]]></c>
+ where each <c><![CDATA[Fc_i]]></c> is a function clause then Rep(E) =
+ <c><![CDATA[{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}]]></c>.</item>
+ <item>If E is <c><![CDATA[query [E_0 || W_1, ..., W_k] end]]></c>,
+ where each <c><![CDATA[W_i]]></c> is a generator or a filter, then
+ Rep(E) = <c><![CDATA[{'query',LINE,{lc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}}]]></c>.
+ For Rep(W), see below.</item>
+ <item>If E is <c><![CDATA[E_0.Field]]></c>, a Mnesia record access
+ inside a query, then
+ Rep(E) = <c><![CDATA[{record_field,LINE,Rep(E_0),Rep(Field)}]]></c>.</item>
+ <item>If E is <c><![CDATA[( E_0 )]]></c>, then
+ Rep(E) = <c><![CDATA[Rep(E_0)]]></c>,
+ i.e., parenthesized expressions cannot be distinguished from their bodies.</item>
+ </list>
+
+ <section>
+ <title>Generators and filters</title>
+ <p>When W is a generator or a filter (in the body of a list or binary comprehension), then:</p>
+ <list type="bulleted">
+ <item>If W is a generator <c><![CDATA[P <- E]]></c>, where <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[E]]></c>
+ is an expression, then
+ Rep(W) = <c><![CDATA[{generate,LINE,Rep(P),Rep(E)}]]></c>.</item>
+ <item>If W is a generator <c><![CDATA[P <= E]]></c>, where <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[E]]></c>
+ is an expression, then
+ Rep(W) = <c><![CDATA[{b_generate,LINE,Rep(P),Rep(E)}]]></c>.</item>
+ <item>If W is a filter <c><![CDATA[E]]></c>, which is an expression, then
+ Rep(W) = <c><![CDATA[Rep(E)]]></c>.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Binary element type specifiers</title>
+ <p>A type specifier list TSL for a binary element is a sequence of type
+ specifiers <c><![CDATA[TS_1 - ... - TS_k]]></c>.
+ Rep(TSL) = <c><![CDATA[[Rep(TS_1), ..., Rep(TS_k)]]]></c>.</p>
+ <p>When TS is a type specifier for a binary element, then:</p>
+ <list type="bulleted">
+ <item>If TS is an atom <c><![CDATA[A]]></c>, Rep(TS) = <c><![CDATA[A]]></c>.</item>
+ <item>If TS is a couple <c><![CDATA[A:Value]]></c> where <c><![CDATA[A]]></c> is an atom and <c><![CDATA[Value]]></c>
+ is an integer, Rep(TS) = <c><![CDATA[{A, Value}]]></c>.</item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Clauses</title>
+ <p>There are function clauses, if clauses, case clauses
+ and catch clauses.</p>
+ <p>A clause <c><![CDATA[C]]></c> is one of the following alternatives:</p>
+ <list type="bulleted">
+ <item>If C is a function clause <c><![CDATA[( Ps ) -> B]]></c>
+ where <c><![CDATA[Ps]]></c> is a pattern sequence and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,Rep(Ps),[],Rep(B)}]]></c>.</item>
+ <item>If C is a function clause <c><![CDATA[( Ps ) when Gs -> B]]></c>
+ where <c><![CDATA[Ps]]></c> is a pattern sequence,
+ <c><![CDATA[Gs]]></c> is a guard sequence and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}]]></c>.</item>
+ <item>If C is an if clause <c><![CDATA[Gs -> B]]></c>
+ where <c><![CDATA[Gs]]></c> is a guard sequence and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,[],Rep(Gs),Rep(B)}]]></c>.</item>
+ <item>If C is a case clause <c><![CDATA[P -> B]]></c>
+ where <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,[Rep(P)],[],Rep(B)}]]></c>.</item>
+ <item>If C is a case clause <c><![CDATA[P when Gs -> B]]></c>
+ where <c><![CDATA[P]]></c> is a pattern,
+ <c><![CDATA[Gs]]></c> is a guard sequence and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,[Rep(P)],Rep(Gs),Rep(B)}]]></c>.</item>
+ <item>If C is a catch clause <c><![CDATA[P -> B]]></c>
+ where <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,[Rep({throw,P,_})],[],Rep(B)}]]></c>.</item>
+ <item>If C is a catch clause <c><![CDATA[X : P -> B]]></c>
+ where <c><![CDATA[X]]></c> is an atomic literal or a variable pattern,
+ <c><![CDATA[P]]></c> is a pattern and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,[Rep({X,P,_})],[],Rep(B)}]]></c>.</item>
+ <item>If C is a catch clause <c><![CDATA[P when Gs -> B]]></c>
+ where <c><![CDATA[P]]></c> is a pattern, <c><![CDATA[Gs]]></c> is a guard sequence
+ and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,[Rep({throw,P,_})],Rep(Gs),Rep(B)}]]></c>.</item>
+ <item>If C is a catch clause <c><![CDATA[X : P when Gs -> B]]></c>
+ where <c><![CDATA[X]]></c> is an atomic literal or a variable pattern,
+ <c><![CDATA[P]]></c> is a pattern, <c><![CDATA[Gs]]></c> is a guard sequence
+ and <c><![CDATA[B]]></c> is a body, then
+ Rep(C) = <c><![CDATA[{clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)}]]></c>.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Guards</title>
+ <p>A guard sequence Gs is a sequence of guards <c><![CDATA[G_1; ...; G_k]]></c>, and
+ Rep(Gs) = <c><![CDATA[[Rep(G_1), ..., Rep(G_k)]]]></c>. If the guard sequence is
+ empty, Rep(Gs) = <c><![CDATA[[]]]></c>.</p>
+ <p>A guard G is a nonempty sequence of guard tests <c><![CDATA[Gt_1, ..., Gt_k]]></c>, and
+ Rep(G) = <c><![CDATA[[Rep(Gt_1), ..., Rep(Gt_k)]]]></c>.</p>
+ <p>A guard test <c><![CDATA[Gt]]></c> is one of the following alternatives:</p>
+ <list type="bulleted">
+ <item>If Gt is an atomic literal L, then Rep(Gt) = Rep(L).</item>
+ <item>If Gt is a variable pattern <c><![CDATA[V]]></c>, then
+ Rep(Gt) = <c><![CDATA[{var,LINE,A}]]></c>,
+ where A is an atom with a printname consisting of the same characters as
+ <c><![CDATA[V]]></c>.</item>
+ <item>If Gt is a tuple skeleton <c><![CDATA[{Gt_1, ..., Gt_k}]]></c>, then
+ Rep(Gt) = <c><![CDATA[{tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[[]]]></c>, then
+ Rep(Gt) = <c><![CDATA[{nil,LINE}]]></c>.</item>
+ <item>If Gt is a cons skeleton <c><![CDATA[[Gt_h | Gt_t]]]></c>, then
+ Rep(Gt) = <c><![CDATA[{cons,LINE,Rep(Gt_h),Rep(Gt_t)}]]></c>.</item>
+ <item>If Gt is a binary constructor <c><![CDATA[<<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>>]]></c>, then
+ Rep(Gt) = <c><![CDATA[{bin,LINE,[{bin_element,LINE,Rep(Gt_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(Gt_k),Rep(Size_k),Rep(TSL_k)}]}]]></c>.
+ For Rep(TSL), see above.
+ An omitted <c><![CDATA[Size]]></c> is represented by <c><![CDATA[default]]></c>. An omitted <c><![CDATA[TSL]]></c>
+ (type specifier list) is represented by <c><![CDATA[default]]></c>.</item>
+ <item>If Gt is <c><![CDATA[Gt_1 Op Gt_2]]></c>, where <c><![CDATA[Op]]></c>
+ is a binary operator, then Rep(Gt) = <c><![CDATA[{op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[Op Gt_0]]></c>, where <c><![CDATA[Op]]></c> is a unary operator, then
+ Rep(Gt) = <c><![CDATA[{op,LINE,Op,Rep(Gt_0)}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[#Name{Field_1=Gt_1, ..., Field_k=Gt_k}]]></c>, then
+ Rep(E) =
+ <c><![CDATA[{record,LINE,Name, [{record_field,LINE,Rep(Field_1),Rep(Gt_1)}, ..., {record_field,LINE,Rep(Field_k),Rep(Gt_k)}]}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[#Name.Field]]></c>, then
+ Rep(Gt) = <c><![CDATA[{record_index,LINE,Name,Rep(Field)}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[Gt_0#Name.Field]]></c>, then
+ Rep(Gt) = <c><![CDATA[{record_field,LINE,Rep(Gt_0),Name,Rep(Field)}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[A(Gt_1, ..., Gt_k)]]></c>, where <c><![CDATA[A]]></c> is an atom, then
+ Rep(Gt) = <c><![CDATA[{call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[A_m:A(Gt_1, ..., Gt_k)]]></c>, where <c><![CDATA[A_m]]></c> is
+ the atom <c><![CDATA[erlang]]></c> and <c><![CDATA[A]]></c> is an atom or an operator, then
+ Rep(Gt) = <c><![CDATA[{call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[{A_m,A}(Gt_1, ..., Gt_k)]]></c>, where <c><![CDATA[A_m]]></c> is
+ the atom <c><![CDATA[erlang]]></c> and <c><![CDATA[A]]></c> is an atom or an operator, then
+ Rep(Gt) = <c><![CDATA[{call,LINE,Rep({A_m,A}),[Rep(Gt_1), ..., Rep(Gt_k)]}]]></c>.</item>
+ <item>If Gt is <c><![CDATA[( Gt_0 )]]></c>, then
+ Rep(Gt) = <c><![CDATA[Rep(Gt_0)]]></c>,
+ i.e., parenthesized guard tests cannot be distinguished from their bodies.</item>
+ </list>
+ <p>Note that every guard test has the same source form as some expression,
+ and is represented the same way as the corresponding expression.</p>
+ </section>
+
+ <section>
+ <title>The abstract format after preprocessing</title>
+ <p>The compilation option <c><![CDATA[debug_info]]></c> can be given to the
+ compiler to have the abstract code stored in
+ the <c><![CDATA[abstract_code]]></c> chunk in the BEAM file
+ (for debugging purposes).</p>
+ <p>In OTP R9C and later, the <c><![CDATA[abstract_code]]></c> chunk will
+ contain</p>
+ <p><c><![CDATA[{raw_abstract_v1,AbstractCode}]]></c></p>
+ <p>where <c><![CDATA[AbstractCode]]></c> is the abstract code as described
+ in this document.</p>
+ <p>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 <c><![CDATA[abstract_v1]]></c> (R7B) or <c><![CDATA[abstract_v2]]></c>
+ (R8B).</p>
+ </section>
+</chapter>
+