diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /erts/doc/src/absform.xml | |
download | otp-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.xml | 444 |
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> + |