diff options
Diffstat (limited to 'erts/doc')
-rw-r--r-- | erts/doc/src/absform.xml | 598 | ||||
-rw-r--r-- | erts/doc/src/erl.xml | 5 | ||||
-rw-r--r-- | erts/doc/src/erl_driver.xml | 113 | ||||
-rw-r--r-- | erts/doc/src/erl_nif.xml | 112 | ||||
-rw-r--r-- | erts/doc/src/erlang.xml | 268 |
5 files changed, 807 insertions, 289 deletions
diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 1c0c3e1319..ccdecf44ec 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2015</year> + <year>2001</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -68,31 +68,29 @@ <item>If D is a module declaration consisting of the forms <c>F_1</c>, ..., <c>F_k</c>, then Rep(D) = <c>[Rep(F_1), ..., Rep(F_k)]</c>.</item> - <item>If F is an attribute <c>-module(Mod)</c>, then - Rep(F) = <c>{attribute,LINE,module,Mod}</c>.</item> <item>If F is an attribute <c>-behavior(Behavior)</c>, then Rep(F) = <c>{attribute,LINE,behavior,Behavior}</c>.</item> <item>If F is an attribute <c>-behaviour(Behaviour)</c>, then Rep(F) = <c>{attribute,LINE,behaviour,Behaviour}</c>.</item> + <item>If F is an attribute <c>-compile(Options)</c>, then + Rep(F) = <c>{attribute,LINE,compile,Options}</c>.</item> <item>If F is an attribute <c>-export([Fun_1/A_1, ..., Fun_k/A_k])</c>, then Rep(F) = <c>{attribute,LINE,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}</c>.</item> - <item>If F is an attribute <c>-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])</c>, then - Rep(F) = <c>{attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}</c>.</item> <item>If F is an attribute <c>-export_type([Type_1/A_1, ..., Type_k/A_k])</c>, then Rep(F) = <c>{attribute,LINE,export_type,[{Type_1,A_1}, ..., {Type_k,A_k}]}</c>.</item> - <item>If F is an attribute <c>-compile(Options)</c>, then - Rep(F) = <c>{attribute,LINE,compile,Options}</c>.</item> + <item>If F is an attribute <c>-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])</c>, then + Rep(F) = <c>{attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}</c>.</item> + <item>If F is an attribute <c>-module(Mod)</c>, then + Rep(F) = <c>{attribute,LINE,module,Mod}</c>.</item> + <item>If F is an attribute <c>-optional_callbacks([Fun_1/A_1, ..., Fun_k/A_k])</c>, then + Rep(F) = <c>{attribute,LINE,optional_callbacks,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}</c>.</item> <item>If F is an attribute <c>-file(File,Line)</c>, then Rep(F) = <c>{attribute,LINE,file,{File,Line}}</c>.</item> - <item>If F is a record declaration - <c>-record(Name,{V_1, ..., V_k})</c>, then Rep(F) = - <c>{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}</c>. - For Rep(V), see below.</item> - <item>If F is a type declaration - <c>-Type Name(V_1, ..., V_k) :: T</c>, where - <c>Type</c> is either the atom <c>type</c> or the atom <c>opaque</c>, - each <c>V_i</c> is a variable, and <c>T</c> is a type, then Rep(F) = - <c>{attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}}</c>. + <item>If F is a function declaration + <c>Name Fc_1 ; ... ; Name Fc_k</c>, + where each <c>Fc_i</c> is a function clause with a + pattern sequence of the same length <c>Arity</c>, then + Rep(F) = <c>{function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}</c>. </item> <item>If F is a function specification <c>-Spec Name Ft_1; ...; Ft_k</c>, @@ -109,15 +107,20 @@ <c>Arity</c>, then Rep(F) = <c>{attribute,Line,spec,{{Mod,Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}</c>. </item> + <item>If F is a record declaration + <c>-record(Name,{V_1, ..., V_k})</c>, + where each <c>V_i</c> is a record field, then Rep(F) = + <c>{attribute,LINE,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}</c>. + For Rep(V), see below.</item> + <item>If F is a type declaration + <c>-Type Name(V_1, ..., V_k) :: T</c>, where + <c>Type</c> is either the atom <c>type</c> or the atom <c>opaque</c>, + each <c>V_i</c> is a variable, and <c>T</c> is a type, then Rep(F) = + <c>{attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}}</c>. + </item> <item>If F is a wild attribute <c>-A(T)</c>, then Rep(F) = <c>{attribute,LINE,A,T}</c>. <br></br></item> - <item>If F is a function declaration - <c>Name Fc_1 ; ... ; Name Fc_k</c>, - where each <c>Fc_i</c> is a function clause with a - pattern sequence of the same length <c>Arity</c>, then - Rep(F) = <c>{function,LINE,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}</c>. - </item> </list> <section> @@ -157,15 +160,15 @@ <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>{integer,LINE,L}</c>.</item> + <item>If L is an atom literal, then + Rep(L) = <c>{atom,LINE,L}</c>.</item> <item>If L is a float literal, then Rep(L) = <c>{float,LINE,L}</c>.</item> + <item>If L is an integer or character literal, then + Rep(L) = <c>{integer,LINE,L}</c>.</item> <item>If L is a string literal consisting of the characters <c>C_1</c>, ..., <c>C_k</c>, then Rep(L) = <c>{string,LINE,[C_1, ..., C_k]}</c>.</item> - <item>If L is an atom literal, then - Rep(L) = <c>{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> @@ -173,47 +176,59 @@ <section> <title>Patterns</title> - <p>If <c>Ps</c> is a sequence of patterns <c>P_1, ..., P_k</c>, then + <p>If Ps is a sequence of patterns <c>P_1, ..., P_k</c>, then Rep(Ps) = <c>[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 an atomic literal <c>L</c>, then Rep(P) = Rep(L).</item> + <item>If P is a binary pattern + <c><<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>></c>, where each + <c>Size_i</c> is an expression that can be evaluated to an integer + and each <c>TSL_i</c> is a type specificer list, then + Rep(P) = <c>{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>Size_i</c> is represented by <c>default</c>. + An omitted <c>TSL_i</c> is represented by <c>default</c>.</item> <item>If P is a compound pattern <c>P_1 = P_2</c>, then Rep(P) = <c>{match,LINE,Rep(P_1),Rep(P_2)}</c>.</item> - <item>If P is a variable pattern <c>V</c>, then - Rep(P) = <c>{var,LINE,A}</c>, - where A is an atom with a printname consisting of the same characters as - <c>V</c>.</item> - <item>If P is a universal pattern <c>_</c>, then - Rep(P) = <c>{var,LINE,'_'}</c>.</item> - <item>If P is a tuple pattern <c>{P_1, ..., P_k}</c>, then - Rep(P) = <c>{tuple,LINE,[Rep(P_1), ..., Rep(P_k)]}</c>.</item> - <item>If P is a nil pattern <c>[]</c>, then - Rep(P) = <c>{nil,LINE}</c>.</item> <item>If P is a cons pattern <c>[P_h | P_t]</c>, then Rep(P) = <c>{cons,LINE,Rep(P_h),Rep(P_t)}</c>.</item> - <item>If E is a binary pattern <c><<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>></c>, then - Rep(E) = <c>{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>Size</c> is represented by <c>default</c>. An omitted <c>TSL</c> - (type specifier list) is represented by <c>default</c>.</item> - <item>If P is <c>P_1 Op P_2</c>, where <c>Op</c> is a binary operator (this - is either an occurrence of <c>++</c> applied to a literal string or character + <item>If P is a map pattern <c>#{A_1, ..., A_k}</c>, where each + <c>A_i</c> is an association <c>P_i_1 := P_i_2</c>, then Rep(P) = + <c>{map,LINE,[Rep(A_1), ..., Rep(A_k)]}</c>. For Rep(A), see + below.</item> + <item>If P is a nil pattern <c>[]</c>, then + Rep(P) = <c>{nil,LINE}</c>.</item> + <item>If P is an operator pattern <c>P_1 Op P_2</c>, + where <c>Op</c> is a binary operator (this is either an occurrence + of <c>++</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>{op,LINE,Op,Rep(P_1),Rep(P_2)}</c>.</item> - <item>If P is <c>Op P_0</c>, where <c>Op</c> is a unary operator (this is an - occurrence of an expression that can be evaluated to a number at compile + <item>If P is an operator pattern <c>Op P_0</c>, + where <c>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>{op,LINE,Op,Rep(P_0)}</c>.</item> - <item>If P is a record pattern <c>#Name{Field_1=P_1, ..., Field_k=P_k}</c>, - then Rep(P) = - <c>{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>#Name.Field</c>, then - Rep(P) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> - <item>If P is <c>( P_0 )</c>, then + <item>If P is a parenthesized pattern <c>( P_0 )</c>, then Rep(P) = <c>Rep(P_0)</c>, - that is, patterns cannot be distinguished from their bodies.</item> + that is, parenthesized patterns cannot be distinguished from their + bodies.</item> + <item>If P is a record field index pattern <c>#Name.Field</c>, + where <c>Field</c> is an atom, then + Rep(P) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> + <item>If P is a record pattern + <c>#Name{Field_1=P_1, ..., Field_k=P_k}</c>, + where each <c>Field_i</c> is an atom or <c>_</c>, then Rep(P) = + <c>{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 a tuple pattern <c>{P_1, ..., P_k}</c>, then + Rep(P) = <c>{tuple,LINE,[Rep(P_1), ..., Rep(P_k)]}</c>.</item> + <item>If P is a universal pattern <c>_</c>, then + Rep(P) = <c>{var,LINE,'_'}</c>.</item> + <item>If P is a variable pattern <c>V</c>, then + Rep(P) = <c>{var,LINE,A}</c>, + where A is an atom with a printname consisting of the same characters as + <c>V</c>.</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> @@ -221,167 +236,185 @@ <section> <title>Expressions</title> - <p>A body B is a sequence of expressions <c>E_1, ..., E_k</c>, and - Rep(B) = <c>[Rep(E_1), ..., Rep(E_k)]</c>.</p> + <p>A body B is a nonempty sequence of expressions <c>E_1, ..., E_k</c>, + and Rep(B) = <c>[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>L</c>, then Rep(P) = Rep(L).</item> - <item>If E is <c>P = E_0</c>, then - Rep(E) = <c>{match,LINE,Rep(P),Rep(E_0)}</c>.</item> - <item>If E is a variable <c>V</c>, then Rep(E) = <c>{var,LINE,A}</c>, - where <c>A</c> is an atom with a printname consisting of the same - characters as <c>V</c>.</item> - <item>If E is a tuple skeleton <c>{E_1, ..., E_k}</c>, then - Rep(E) = <c>{tuple,LINE,[Rep(E_1), ..., Rep(E_k)]}</c>.</item> - <item>If E is <c>[]</c>, then - Rep(E) = <c>{nil,LINE}</c>.</item> - <item>If E is a cons skeleton <c>[E_h | E_t]</c>, then - Rep(E) = <c>{cons,LINE,Rep(E_h),Rep(E_t)}</c>.</item> - <item>If E is a binary constructor <c><<V_1:Size_1/TSL_1, ..., V_k:Size_k/TSL_k>></c>, then Rep(E) = - <c>{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>. + <item>If E is an atomic literal <c>L</c>, then Rep(E) = Rep(L).</item> + <item>If E is a binary comprehension + <c><<E_0 || Q_1, ..., Q_k>></c>, + where each <c>Q_i</c> is a qualifier, then + Rep(E) = <c>{bc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}</c>. + For Rep(Q), see below.</item> + <item>If E is a binary constructor <c><<E_1:Size_1/TSL_1, ..., E_k:Size_k/TSL_k>></c>, + where each <c>Size_i</c> is an expression and each + <c>TSL_i</c> is a type specificer list, then Rep(E) = + <c>{bin,LINE,[{bin_element,LINE,Rep(E_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,LINE,Rep(E_k),Rep(Size_k),Rep(TSL_k)}]}</c>. For Rep(TSL), see below. - An omitted <c>Size</c> is represented by <c>default</c>. An omitted <c>TSL</c> - (type specifier list) is represented by <c>default</c>.</item> - <item>If E is <c>E_1 Op E_2</c>, where <c>Op</c> is a binary operator, - then Rep(E) = <c>{op,LINE,Op,Rep(E_1),Rep(E_2)}</c>.</item> - <item>If E is <c>Op E_0</c>, where <c>Op</c> is a unary operator, then - Rep(E) = <c>{op,LINE,Op,Rep(E_0)}</c>.</item> - <item>If E is <c>#Name{Field_1=E_1, ..., Field_k=E_k}</c>, - then Rep(E) = - <c>{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>E_0#Name{Field_1=E_1, ..., Field_k=E_k}</c>, then - Rep(E) = - <c>{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>#Name.Field</c>, then - Rep(E) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> - <item>If E is <c>E_0#Name.Field</c>, then - Rep(E) = <c>{record_field,LINE,Rep(E_0),Name,Rep(Field)}</c>.</item> - <item>If E is <c>#{W_1, ..., W_k}</c> where each - <c>W_i</c> is a map assoc or exact field, then Rep(E) = - <c>{map,LINE,[Rep(W_1), ..., Rep(W_k)]}</c>. For Rep(W), see - below.</item> - <item>If E is <c>E_0#{W_1, ..., W_k}</c> where - <c>W_i</c> is a map assoc or exact field, then Rep(E) = - <c>{map,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}</c>. - For Rep(W), see below.</item> - <item>If E is <c>catch E_0</c>, then + An omitted <c>Size_i</c> is represented by <c>default</c>. + An omitted <c>TSL_i</c> is represented by <c>default</c>.</item> + <item>If E is a block expression <c>begin B end</c>, + where <c>B</c> is a body, then + Rep(E) = <c>{block,LINE,Rep(B)}</c>.</item> + <item>If E is a case expression <c>case E_0 of Cc_1 ; ... ; Cc_k end</c>, + where <c>E_0</c> is an expression and each <c>Cc_i</c> is a + case clause then Rep(E) = + <c>{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item> + <item>If E is a catch expression <c>catch E_0</c>, then Rep(E) = <c>{'catch',LINE,Rep(E_0)}</c>.</item> - <item>If E is <c>E_0(E_1, ..., E_k)</c>, then + <item>If E is a cons skeleton <c>[E_h | E_t]</c>, then + Rep(E) = <c>{cons,LINE,Rep(E_h),Rep(E_t)}</c>.</item> + <item>If E is a fun expression <c>fun Name/Arity</c>, then + Rep(E) = <c>{'fun',LINE,{function,Name,Arity}}</c>.</item> + <item>If E is a fun expression + <c>fun Module:Name/Arity</c>, then Rep(E) = + <c>{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}}</c>. + (Before the R15 release: Rep(E) = + <c>{'fun',LINE,{function,Module,Name,Arity}}</c>.)</item> + <item>If E is a fun expression <c>fun Fc_1 ; ... ; Fc_k end</c>, + where each <c>Fc_i</c> is a function clause then Rep(E) = + <c>{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}</c>.</item> + <item>If E is a fun expression + <c>fun Name Fc_1 ; ... ; Name Fc_k end</c>, + where <c>Name</c> is a variable and each + <c>Fc_i</c> is a function clause then Rep(E) = + <c>{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]}</c>. + </item> + <item>If E is a function call <c>E_0(E_1, ..., E_k)</c>, then Rep(E) = <c>{call,LINE,Rep(E_0),[Rep(E_1), ..., Rep(E_k)]}</c>.</item> - <item>If E is <c>E_m:E_0(E_1, ..., E_k)</c>, then Rep(E) = - <c>{call,LINE,{remote,LINE,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]}</c>. + <item>If E is a function call <c>E_m:E_0(E_1, ..., E_k)</c>, + then Rep(E) = + <c>{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>[E_0 || W_1, ..., W_k]</c>, - where each <c>W_i</c> is a generator or a filter, then Rep(E) = - <c>{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><<E_0 || W_1, ..., W_k>></c>, - where each <c>W_i</c> is a generator or a filter, then - Rep(E) = <c>{bc,LINE,Rep(E_0),[Rep(W_1), ..., Rep(W_k)]}</c>. - For Rep(W), see below.</item> - <item>If E is <c>begin B end</c>, where <c>B</c> is a body, then - Rep(E) = <c>{block,LINE,Rep(B)}</c>.</item> - <item>If E is <c>if Ic_1 ; ... ; Ic_k end</c>, + <item>If E is an if expression <c>if Ic_1 ; ... ; Ic_k end</c>, where each <c>Ic_i</c> is an if clause then Rep(E) = <c>{'if',LINE,[Rep(Ic_1), ..., Rep(Ic_k)]}</c>.</item> - <item>If E is <c>case E_0 of Cc_1 ; ... ; Cc_k end</c>, - where <c>E_0</c> is an expression and each <c>Cc_i</c> is a - case clause then Rep(E) = - <c>{'case',LINE,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item> - <item>If E is <c>try B catch Tc_1 ; ... ; Tc_k end</c>, + <item>If E is a list comprehension <c>[E_0 || Q_1, ..., Q_k]</c>, + where each <c>Q_i</c> is a qualifier, then Rep(E) = + <c>{lc,LINE,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}</c>. For Rep(Q), see + below.</item> + <item>If E is a map creation <c>#{A_1, ..., A_k}</c>, + where each <c>A_i</c> is an association <c>E_i_1 => E_i_2</c> + or <c>E_i_1 := E_i_2</c>, then Rep(E) = + <c>{map,LINE,[Rep(A_1), ..., Rep(A_k)]}</c>. For Rep(A), see + below.</item> + <item>If E is a map update <c>E_0#{A_1, ..., A_k}</c>, + where each <c>A_i</c> is an association <c>E_i_1 => E_i_2</c> + or <c>E_i_1 := E_i_2</c>, then Rep(E) = + <c>{map,LINE,Rep(E_0),[Rep(A_1), ..., Rep(A_k)]}</c>. + For Rep(A), see below.</item> + <item>If E is a match operator expression <c>P = E_0</c>, + where <c>P</c> is a pattern, then + Rep(E) = <c>{match,LINE,Rep(P),Rep(E_0)}</c>.</item> + <item>If E is nil, <c>[]</c>, then + Rep(E) = <c>{nil,LINE}</c>.</item> + <item>If E is an operator expression <c>E_1 Op E_2</c>, + where <c>Op</c> is a binary operator other than the match + operator <c>=</c>, then + Rep(E) = <c>{op,LINE,Op,Rep(E_1),Rep(E_2)}</c>.</item> + <item>If E is an operator expression <c>Op E_0</c>, + where <c>Op</c> is a unary operator, then + Rep(E) = <c>{op,LINE,Op,Rep(E_0)}</c>.</item> + <item>If E is a parenthesized expression <c>( E_0 )</c>, then + Rep(E) = <c>Rep(E_0)</c>, that is, parenthesized + expressions cannot be distinguished from their bodies.</item> + <item>If E is a receive expression <c>receive Cc_1 ; ... ; Cc_k end</c>, + where each <c>Cc_i</c> is a case clause then Rep(E) = + <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item> + <item>If E is a receive expression + <c>receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end</c>, + where each <c>Cc_i</c> is a case clause, + <c>E_0</c> is an expression and <c>B_t</c> is a body, then Rep(E) = + <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)}</c>.</item> + <item>If E is a record creation + <c>#Name{Field_1=E_1, ..., Field_k=E_k}</c>, + where each <c>Field_i</c> is an atom or <c>_</c>, then Rep(E) = + <c>{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 a record field access <c>E_0#Name.Field</c>, + where <c>Field</c> is an atom, then + Rep(E) = <c>{record_field,LINE,Rep(E_0),Name,Rep(Field)}</c>.</item> + <item>If E is a record field index <c>#Name.Field</c>, + where <c>Field</c> is an atom, then + Rep(E) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> + <item>If E is a record update + <c>E_0#Name{Field_1=E_1, ..., Field_k=E_k}</c>, + where each <c>Field_i</c> is an atom, then Rep(E) = + <c>{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 a tuple skeleton <c>{E_1, ..., E_k}</c>, then + Rep(E) = <c>{tuple,LINE,[Rep(E_1), ..., Rep(E_k)]}</c>.</item> + <item>If E is a try expression <c>try B catch Tc_1 ; ... ; Tc_k end</c>, where <c>B</c> is a body and each <c>Tc_i</c> is a catch clause then Rep(E) = <c>{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],[]}</c>.</item> - <item>If E is <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end</c>, + <item>If E is a try expression + <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end</c>, where <c>B</c> is a body, each <c>Cc_i</c> is a case clause and each <c>Tc_j</c> is a catch clause then Rep(E) = <c>{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],[]}</c>.</item> - <item>If E is <c>try B after A end</c>, + <item>If E is a try expression <c>try B after A end</c>, where <c>B</c> and <c>A</c> are bodies then Rep(E) = <c>{'try',LINE,Rep(B),[],[],Rep(A)}</c>.</item> - <item>If E is <c>try B of Cc_1 ; ... ; Cc_k after A end</c>, + <item>If E is a try expression + <c>try B of Cc_1 ; ... ; Cc_k after A end</c>, where <c>B</c> and <c>A</c> are a bodies and each <c>Cc_i</c> is a case clause then Rep(E) = <c>{'try',LINE,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[],Rep(A)}</c>.</item> - <item>If E is <c>try B catch Tc_1 ; ... ; Tc_k after A end</c>, + <item>If E is a try expression + <c>try B catch Tc_1 ; ... ; Tc_k after A end</c>, where <c>B</c> and <c>A</c> are bodies and each <c>Tc_i</c> is a catch clause then Rep(E) = <c>{'try',LINE,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],Rep(A)}</c>.</item> - <item>If E is <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end</c>, + <item>If E is a try expression + <c>try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end</c>, where <c>B</c> and <c>A</c> are a bodies, - each <c>Cc_i</c> is a case clause and + each <c>Cc_i</c> is a case clause, and each <c>Tc_j</c> is a catch clause then Rep(E) = <c>{'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>receive Cc_1 ; ... ; Cc_k end</c>, - where each <c>Cc_i</c> is a case clause then Rep(E) = - <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)]}</c>.</item> - <item>If E is <c>receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end</c>, - where each <c>Cc_i</c> is a case clause, - <c>E_0</c> is an expression and <c>B_t</c> is a body, then Rep(E) = - <c>{'receive',LINE,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)}</c>.</item> - <item>If E is <c>fun Name / Arity</c>, then - Rep(E) = <c>{'fun',LINE,{function,Name,Arity}}</c>.</item> - <item>If E is <c>fun Module:Name/Arity</c>, then Rep(E) = - <c>{'fun',LINE,{function,Rep(Module),Rep(Name),Rep(Arity)}}</c>. - (Before the R15 release: Rep(E) = - <c>{'fun',LINE,{function,Module,Name,Arity}}</c>.)</item> - <item>If E is <c>fun Fc_1 ; ... ; Fc_k end</c> - where each <c>Fc_i</c> is a function clause then Rep(E) = - <c>{'fun',LINE,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}</c>.</item> - <item>If E is <c>fun Name Fc_1 ; ... ; Name Fc_k end</c> - where <c>Name</c> is a variable and each - <c>Fc_i</c> is a function clause then Rep(E) = - <c>{named_fun,LINE,Name,[Rep(Fc_1), ..., Rep(Fc_k)]}</c>. - </item> - <item>If E is <c>( E_0 )</c>, then - Rep(E) = <c>Rep(E_0)</c>, that is, parenthesized - expressions cannot be distinguished from their bodies.</item> + <item>If E is a variable <c>V</c>, then Rep(E) = <c>{var,LINE,A}</c>, + where <c>A</c> is an atom with a printname consisting of the same + characters as <c>V</c>.</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> + <title>Qualifiers</title> + <p>A qualifier Q is one of the following alternatives:</p> <list type="bulleted"> - <item>If W is a generator <c>P <- E</c>, where <c>P</c> is + <item>If Q is a filter <c>E</c>, where <c>E</c> is an expression, then + Rep(Q) = <c>Rep(E)</c>.</item> + <item>If Q is a generator <c>P <- E</c>, where <c>P</c> is a pattern and <c>E</c> is an expression, then - Rep(W) = <c>{generate,LINE,Rep(P),Rep(E)}</c>.</item> - <item>If W is a generator <c>P <= E</c>, where <c>P</c> is + Rep(Q) = <c>{generate,LINE,Rep(P),Rep(E)}</c>.</item> + <item>If Q is a generator <c>P <= E</c>, where <c>P</c> is a pattern and <c>E</c> is an expression, then - Rep(W) = <c>{b_generate,LINE,Rep(P),Rep(E)}</c>.</item> - <item>If W is a filter <c>E</c>, which is an expression, then - Rep(W) = <c>Rep(E)</c>.</item> + Rep(Q) = <c>{b_generate,LINE,Rep(P),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>TS_1 - ... - TS_k</c>. + specifiers <c>TS_1 - ... - TS_k</c>, and Rep(TSL) = <c>[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>A</c>, then Rep(TS) = <c>A</c>.</item> - <item>If TS is a couple <c>A:Value</c> where <c>A</c> is an atom - and <c>Value</c> is an integer, then Rep(TS) = - <c>{A,Value}</c>.</item> + <item>If TS is a type specifier <c>A</c>, where <c>A</c> is an atom, + then Rep(TS) = <c>A</c>.</item> + <item>If TS is a type specifier <c>A:Value</c>, + where <c>A</c> is an atom and <c>Value</c> is an integer, + then Rep(TS) = <c>{A,Value}</c>.</item> </list> </section> <section> - <title>Map Assoc and Exact Fields</title> - <p>When W is an assoc or exact field (in the body of a map), then:</p> + <title>Associations</title> + <p>An association A is one of the following alternatives:</p> <list type="bulleted"> - <item>If W is an assoc field <c>K => V</c>, where - <c>K</c> and <c>V</c> are both expressions, - then Rep(W) = <c>{map_field_assoc,LINE,Rep(K),Rep(V)}</c>. + <item>If A is an association <c>K => V</c>, + then Rep(A) = <c>{map_field_assoc,LINE,Rep(K),Rep(V)}</c>. </item> - <item>If W is an exact field <c>K := V</c>, where - <c>K</c> and <c>V</c> are both expressions, - then Rep(W) = <c>{map_field_exact,LINE,Rep(K),Rep(V)}</c>. + <item>If A is an association <c>K := V</c>, + then Rep(A) = <c>{map_field_exact,LINE,Rep(K),Rep(V)}</c>. </item> </list> </section> @@ -393,39 +426,39 @@ and catch clauses.</p> <p>A clause <c>C</c> is one of the following alternatives:</p> <list type="bulleted"> - <item>If C is a function clause <c>( Ps ) -> B</c> - where <c>Ps</c> is a pattern sequence and <c>B</c> is a body, then - Rep(C) = <c>{clause,LINE,Rep(Ps),[],Rep(B)}</c>.</item> - <item>If C is a function clause <c>( Ps ) when Gs -> B</c> - where <c>Ps</c> is a pattern sequence, - <c>Gs</c> is a guard sequence and <c>B</c> is a body, then - Rep(C) = <c>{clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}</c>.</item> - <item>If C is an if clause <c>Gs -> B</c> - where <c>Gs</c> is a guard sequence and <c>B</c> is a body, then - Rep(C) = <c>{clause,LINE,[],Rep(Gs),Rep(B)}</c>.</item> - <item>If C is a case clause <c>P -> B</c> + <item>If C is a case clause <c>P -> B</c>, where <c>P</c> is a pattern and <c>B</c> is a body, then Rep(C) = <c>{clause,LINE,[Rep(P)],[],Rep(B)}</c>.</item> - <item>If C is a case clause <c>P when Gs -> B</c> + <item>If C is a case clause <c>P when Gs -> B</c>, where <c>P</c> is a pattern, <c>Gs</c> is a guard sequence and <c>B</c> is a body, then Rep(C) = <c>{clause,LINE,[Rep(P)],Rep(Gs),Rep(B)}</c>.</item> - <item>If C is a catch clause <c>P -> B</c> + <item>If C is a catch clause <c>P -> B</c>, where <c>P</c> is a pattern and <c>B</c> is a body, then Rep(C) = <c>{clause,LINE,[Rep({throw,P,_})],[],Rep(B)}</c>.</item> - <item>If C is a catch clause <c>X : P -> B</c> + <item>If C is a catch clause <c>X : P -> B</c>, where <c>X</c> is an atomic literal or a variable pattern, - <c>P</c> is a pattern and <c>B</c> is a body, then + <c>P</c> is a pattern, and <c>B</c> is a body, then Rep(C) = <c>{clause,LINE,[Rep({X,P,_})],[],Rep(B)}</c>.</item> - <item>If C is a catch clause <c>P when Gs -> B</c> - where <c>P</c> is a pattern, <c>Gs</c> is a guard sequence + <item>If C is a catch clause <c>P when Gs -> B</c>, + where <c>P</c> is a pattern, <c>Gs</c> is a guard sequence, and <c>B</c> is a body, then Rep(C) = <c>{clause,LINE,[Rep({throw,P,_})],Rep(Gs),Rep(B)}</c>.</item> - <item>If C is a catch clause <c>X : P when Gs -> B</c> + <item>If C is a catch clause <c>X : P when Gs -> B</c>, where <c>X</c> is an atomic literal or a variable pattern, - <c>P</c> is a pattern, <c>Gs</c> is a guard sequence + <c>P</c> is a pattern, <c>Gs</c> is a guard sequence, and <c>B</c> is a body, then Rep(C) = <c>{clause,LINE,[Rep({X,P,_})],Rep(Gs),Rep(B)}</c>.</item> + <item>If C is a function clause <c>( Ps ) -> B</c>, + where <c>Ps</c> is a pattern sequence and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,Rep(Ps),[],Rep(B)}</c>.</item> + <item>If C is a function clause <c>( Ps ) when Gs -> B</c>, + where <c>Ps</c> is a pattern sequence, + <c>Gs</c> is a guard sequence and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,Rep(Ps),Rep(Gs),Rep(B)}</c>.</item> + <item>If C is an if clause <c>Gs -> B</c>, + where <c>Gs</c> is a guard sequence and <c>B</c> is a body, then + Rep(C) = <c>{clause,LINE,[],Rep(Gs),Rep(B)}</c>.</item> </list> </section> @@ -439,46 +472,61 @@ <c>[Rep(Gt_1), ..., Rep(Gt_k)]</c>.</p> <p>A guard test <c>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>V</c>, then - Rep(Gt) = <c>{var,LINE,A}</c>, where A is an atom with - a printname consisting of the same characters as <c>V</c>.</item> - <item>If Gt is a tuple skeleton <c>{Gt_1, ..., Gt_k}</c>, then - Rep(Gt) = <c>{tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> - <item>If Gt is <c>[]</c>, then Rep(Gt) = <c>{nil,LINE}</c>.</item> - <item>If Gt is a cons skeleton <c>[Gt_h | Gt_t]</c>, then - Rep(Gt) = <c>{cons,LINE,Rep(Gt_h),Rep(Gt_t)}</c>.</item> + <item>If Gt is an atomic literal <c>L</c>, then Rep(Gt) = Rep(L).</item> <item>If Gt is a binary constructor - <c><<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>></c>, then + <c><<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>></c>, + where each <c>Size_i</c> is a guard test and each + <c>TSL_i</c> is a type specificer list, then Rep(Gt) = <c>{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>Size</c> is represented by <c>default</c>. - An omitted <c>TSL</c> (type specifier list) is represented - by <c>default</c>.</item> - <item>If Gt is <c>Gt_1 Op Gt_2</c>, where <c>Op</c> - is a binary operator, then Rep(Gt) = - <c>{op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}</c>.</item> - <item>If Gt is <c>Op Gt_0</c>, where <c>Op</c> is a unary operator, then + An omitted <c>Size_i</c> is represented by <c>default</c>. + An omitted <c>TSL_i</c> is represented by <c>default</c>.</item> + <item>If Gt is a cons skeleton <c>[Gt_h | Gt_t]</c>, then + Rep(Gt) = <c>{cons,LINE,Rep(Gt_h),Rep(Gt_t)}</c>.</item> + <item>If Gt is a function call <c>A(Gt_1, ..., Gt_k)</c>, + where <c>A</c> is an atom, then Rep(Gt) = + <c>{call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> + <item>If Gt is a function call <c>A_m:A(Gt_1, ..., Gt_k)</c>, + where <c>A_m</c> is the atom <c>erlang</c> and <c>A</c> is + an atom or an operator, then Rep(Gt) = + <c>{call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> + <item>If Gt is a map creation <c>#{A_1, ..., A_k}</c>, + where each <c>A_i</c> is an association <c>Gt_i_1 => Gt_i_2</c> + or <c>Gt_i_1 := Gt_i_2</c>, then Rep(Gt) = + <c>{map,LINE,[Rep(A_1), ..., Rep(A_k)]}</c>. For Rep(A), see + above.</item> + <item>If Gt is a map update <c>Gt_0#{A_1, ..., A_k}</c>, where each + <c>A_i</c> is an association <c>Gt_i_1 => Gt_i_2</c> + or <c>Gt_i_1 := Gt_i_2</c>, then Rep(Gt) = + <c>{map,LINE,Rep(Gt_0),[Rep(A_1), ..., Rep(A_k)]}</c>. + For Rep(A), see above.</item> + <item>If Gt is nil, <c>[]</c>, + then Rep(Gt) = <c>{nil,LINE}</c>.</item> + <item>If Gt is an operator guard test <c>Gt_1 Op Gt_2</c>, + where <c>Op</c> is a binary operator other than the match + operator <c>=</c>, then + Rep(Gt) = <c>{op,LINE,Op,Rep(Gt_1),Rep(Gt_2)}</c>.</item> + <item>If Gt is an operator guard test <c>Op Gt_0</c>, + where <c>Op</c> is a unary operator, then Rep(Gt) = <c>{op,LINE,Op,Rep(Gt_0)}</c>.</item> - <item>If Gt is <c>#Name{Field_1=Gt_1, ..., Field_k=Gt_k}</c>, then - Rep(E) = - <c>{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>#Name.Field</c>, then - Rep(Gt) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> - <item>If Gt is <c>Gt_0#Name.Field</c>, then - Rep(Gt) = <c>{record_field,LINE,Rep(Gt_0),Name,Rep(Field)}</c>.</item> - <item>If Gt is <c>A(Gt_1, ..., Gt_k)</c>, where <c>A</c> is an atom, then - Rep(Gt) = <c>{call,LINE,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> - <item>If Gt is <c>A_m:A(Gt_1, ..., Gt_k)</c>, where <c>A_m</c> is - the atom <c>erlang</c> and <c>A</c> is an atom or an operator, then - Rep(Gt) = <c>{call,LINE,{remote,LINE,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> - <item>If Gt is <c>{A_m,A}(Gt_1, ..., Gt_k)</c>, where <c>A_m</c> is - the atom <c>erlang</c> and <c>A</c> is an atom or an operator, then - Rep(Gt) = <c>{call,LINE,Rep({A_m,A}),[Rep(Gt_1), ..., Rep(Gt_k)]}</c>. - </item> - <item>If Gt is <c>( Gt_0 )</c>, then + <item>If Gt is a parenthesized guard test <c>( Gt_0 )</c>, then Rep(Gt) = <c>Rep(Gt_0)</c>, that is, parenthesized guard tests cannot be distinguished from their bodies.</item> + <item>If Gt is a record creation + <c>#Name{Field_1=Gt_1, ..., Field_k=Gt_k}</c>, + where each <c>Field_i</c> is an atom or <c>_</c>, then Rep(Gt) = + <c>{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 a record field access <c>Gt_0#Name.Field</c>, + where <c>Field</c> is an atom, then + Rep(Gt) = <c>{record_field,LINE,Rep(Gt_0),Name,Rep(Field)}</c>.</item> + <item>If Gt is a record field index <c>#Name.Field</c>, + where <c>Field</c> is an atom, then + Rep(Gt) = <c>{record_index,LINE,Name,Rep(Field)}</c>.</item> + <item>If Gt is a tuple skeleton <c>{Gt_1, ..., Gt_k}</c>, then + Rep(Gt) = <c>{tuple,LINE,[Rep(Gt_1), ..., Rep(Gt_k)]}</c>.</item> + <item>If Gt is a variable pattern <c>V</c>, then + Rep(Gt) = <c>{var,LINE,A}</c>, where A is an atom with + a printname consisting of the same characters as <c>V</c>.</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> @@ -487,21 +535,11 @@ <section> <title>Types</title> <list type="bulleted"> - <item>If T is an annotated type <c>Anno :: Type</c>, - where <c>Anno</c> is a variable and - <c>Type</c> is a type, then Rep(T) = - <c>{ann_type,LINE,[Rep(Anno),Rep(Type)]}</c>.</item> + <item>If T is an annotated type <c>A :: T_0</c>, + where <c>A</c> is a variable, then Rep(T) = + <c>{ann_type,LINE,[Rep(A),Rep(T_0)]}</c>.</item> <item>If T is an atom or integer literal L, then Rep(T) = Rep(L). </item> - <item>If T is <c>L Op R</c>, - where <c>Op</c> is a binary operator and <c>L</c> and <c>R</c> - are types (this is an occurrence of an expression that can be - evaluated to an integer at compile time), then - Rep(T) = <c>{op,LINE,Op,Rep(L),Rep(R)}</c>.</item> - <item>If T is <c>Op A</c>, where <c>Op</c> is a - unary operator and <c>A</c> is a type (this is an occurrence of - an expression that can be evaluated to an integer at compile time), - then Rep(T) = <c>{op,LINE,Op,Rep(A)}</c>.</item> <item>If T is a bitstring type <c><<_:M,_:_*N>></c>, where <c>M</c> and <c>N</c> are singleton integer types, then Rep(T) = <c>{type,LINE,binary,[Rep(M),Rep(N)]}</c>.</item> @@ -509,69 +547,71 @@ <c>{type,Line,nil,[]}</c>.</item> <item>If T is a fun type <c>fun()</c>, then Rep(T) = <c>{type,LINE,'fun',[]}</c>.</item> - <item>If T is a fun type <c>fun((...) -> B)</c>, - where <c>B</c> is a type, then - Rep(T) = <c>{type,LINE,'fun',[{type,LINE,any},Rep(B)]}</c>. + <item>If T is a fun type <c>fun((...) -> T_0)</c>, then + Rep(T) = <c>{type,LINE,'fun',[{type,LINE,any},Rep(T_0)]}</c>. </item> <item>If T is a fun type <c>fun(Ft)</c>, where <c>Ft</c> is a function type, - then Rep(T) = <c>Rep(Ft)</c>.</item> + then Rep(T) = <c>Rep(Ft)</c>. For Rep(Ft), see below.</item> <item>If T is an integer range type <c>L .. H</c>, where <c>L</c> and <c>H</c> are singleton integer types, then Rep(T) = <c>{type,LINE,range,[Rep(L),Rep(H)]}</c>.</item> <item>If T is a map type <c>map()</c>, then Rep(T) = <c>{type,LINE,map,any}</c>.</item> - <item>If T is a map type <c>#{P_1, ..., P_k}</c>, where each - <c>P_i</c> is a map pair type, then Rep(T) = - <c>{type,LINE,map,[Rep(P_1), ..., Rep(P_k)]}</c>.</item> - <item>If T is a map pair type <c>K => V</c>, where - <c>K</c> and <c>V</c> are types, then Rep(T) = - <c>{type,LINE,map_field_assoc,[Rep(K),Rep(V)]}</c>.</item> - <item>If T is a predefined (or built-in) type <c>N(A_1, ..., A_k)</c>, - where each <c>A_i</c> is a type, then Rep(T) = - <c>{type,LINE,N,[Rep(A_1), ..., Rep(A_k)]}</c>.</item> + <item>If T is a map type <c>#{A_1, ..., A_k}</c>, where each + <c>A_i</c> is an association type, then Rep(T) = + <c>{type,LINE,map,[Rep(A_1), ..., Rep(A_k)]}</c>. + For Rep(A), see below.</item> + <item>If T is an operator type <c>T_1 Op T_2</c>, + where <c>Op</c> is a binary operator (this is an occurrence of + an expression that can be evaluated to an integer at compile + time), then + Rep(T) = <c>{op,LINE,Op,Rep(T_1),Rep(T_2)}</c>.</item> + <item>If T is an operator type <c>Op T_0</c>, where <c>Op</c> is a + unary operator (this is an occurrence of + an expression that can be evaluated to an integer at compile time), + then Rep(T) = <c>{op,LINE,Op,Rep(T_0)}</c>.</item> + <item>If T is <c>( T_0 )</c>, then Rep(T) = <c>Rep(T_0)</c>, + that is, parenthesized types cannot be distinguished from their + bodies.</item> + <item>If T is a predefined (or built-in) type <c>N(T_1, ..., T_k)</c>, + then Rep(T) = + <c>{type,LINE,N,[Rep(T_1), ..., Rep(T_k)]}</c>.</item> <item>If T is a record type <c>#Name{F_1, ..., F_k}</c>, where each <c>F_i</c> is a record field type, then Rep(T) = <c>{type,LINE,record,[Rep(Name),Rep(F_1), ..., Rep(F_k)]}</c>. - </item> - <item>If T is a record field type <c>Name :: Type</c>, - where <c>Type</c> is a type, then Rep(T) = - <c>{type,LINE,field_type,[Rep(Name),Rep(Type)]}</c>.</item> - <item>If T is a remote type <c>M:N(A_1, ..., A_k)</c>, where - each <c>A_i</c> is a type, then Rep(T) = - <c>{remote_type,LINE,[Rep(M),Rep(N),[Rep(A_1), ..., Rep(A_k)]]}</c>. + For Rep(F), see below.</item> + <item>If T is a remote type <c>M:N(T_1, ..., T_k)</c>, then Rep(T) = + <c>{remote_type,LINE,[Rep(M),Rep(N),[Rep(T_1), ..., Rep(T_k)]]}</c>. </item> <item>If T is a tuple type <c>tuple()</c>, then Rep(T) = <c>{type,LINE,tuple,any}</c>.</item> - <item>If T is a tuple type <c>{A_1, ..., A_k}</c>, where - each <c>A_i</c> is a type, then Rep(T) = - <c>{type,LINE,tuple,[Rep(A_1), ..., Rep(A_k)]}</c>.</item> - <item>If T is a type union <c>T_1 | ... | T_k</c>, - where each <c>T_i</c> is a type, then Rep(T) = + <item>If T is a tuple type <c>{T_1, ..., T_k}</c>, then Rep(T) = + <c>{type,LINE,tuple,[Rep(T_1), ..., Rep(T_k)]}</c>.</item> + <item>If T is a type union <c>T_1 | ... | T_k</c>, then Rep(T) = <c>{type,LINE,union,[Rep(T_1), ..., Rep(T_k)]}</c>.</item> <item>If T is a type variable <c>V</c>, then Rep(T) = <c>{var,LINE,A}</c>, where <c>A</c> is an atom with a printname consisting of the same characters as <c>V</c>. A type variable is any variable except underscore (<c>_</c>).</item> - <item>If T is a user-defined type <c>N(A_1, ..., A_k)</c>, - where each <c>A_i</c> is a type, then Rep(T) = - <c>{user_type,LINE,N,[Rep(A_1), ..., Rep(A_k)]}</c>.</item> - <item>If T is <c>( T_0 )</c>, then Rep(T) = <c>Rep(T_0)</c>, - that is, parenthesized types cannot be distinguished from their - bodies.</item> + <item>If T is a user-defined type <c>N(T_1, ..., T_k)</c>, + then Rep(T) = + <c>{user_type,LINE,N,[Rep(T_1), ..., Rep(T_k)]}</c>.</item> </list> <section> <title>Function Types</title> + <p>A function type Ft is one of the following alternatives:</p> <list type="bulleted"> <item>If Ft is a constrained function type <c>Ft_1 when Fc</c>, where <c>Ft_1</c> is a function type and <c>Fc</c> is a function constraint, then Rep(T) = - <c>{type,LINE,bounded_fun,[Rep(Ft_1),Rep(Fc)]}</c>.</item> - <item>If Ft is a function type <c>(A_1, ..., A_n) -> B</c>, - where each <c>A_i</c> and <c>B</c> are types, then - Rep(Ft) = <c>{type,LINE,'fun',[{type,LINE,product,[Rep(A_1), - ..., Rep(A_n)]},Rep(B)]}</c>.</item> + <c>{type,LINE,bounded_fun,[Rep(Ft_1),Rep(Fc)]}</c>. + For Rep(Fc), see below.</item> + <item>If Ft is a function type <c>(T_1, ..., T_n) -> T_0</c>, + where each <c>T_i</c> is a type, then + Rep(Ft) = <c>{type,LINE,'fun',[{type,LINE,product,[Rep(T_1), + ..., Rep(T_n)]},Rep(T_0)]}</c>.</item> </list> </section> @@ -587,6 +627,24 @@ </item> </list> </section> + + <section> + <title>Association Types</title> + <list type="bulleted"> + <item>If A is an association type <c>K => V</c>, where + <c>K</c> and <c>V</c> are types, then Rep(A) = + <c>{type,LINE,map_field_assoc,[Rep(K),Rep(V)]}</c>.</item> + </list> + </section> + + <section> + <title>Record Field Types</title> + <list type="bulleted"> + <item>If F is a record field type <c>Name :: Type</c>, + where <c>Type</c> is a type, then Rep(F) = + <c>{type,LINE,field_type,[Rep(Name),Rep(Type)]}</c>.</item> + </list> + </section> </section> <section> diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index b6fa4c254c..1c4a0056a7 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -382,6 +382,11 @@ similar to <c><![CDATA[code:add_pathsz/1]]></c>. See <seealso marker="kernel:code">code(3)</seealso>.</p> </item> + <tag><c><![CDATA[-path Dir1 Dir2 ...]]></c></tag> + <item> + <p>Replaces the path specified in the boot script. See + <seealso marker="sasl:script">script(4)</seealso>.</p> + </item> <tag><c><![CDATA[-remsh Node]]></c></tag> <item> <p>Starts Erlang with a remote shell connected to <c><![CDATA[Node]]></c>.</p> diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index cade732c56..241d4131d5 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -347,6 +347,16 @@ the driver does not handle sizes that overflow an <c>int</c> all will work as before.</p> </item> + <tag><marker id="time_measurement"/>Time Measurement</tag> + <item><p>Support for time measurement in drivers: + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + <item><seealso marker="#erl_drv_monotonic_time"><c>erl_drv_monotonic_time()</c></seealso></item> + <item><seealso marker="#erl_drv_time_offset"><c>erl_drv_time_offset()</c></seealso></item> + <item><seealso marker="#erl_drv_convert_time_unit"><c>erl_drv_convert_time_unit()</c></seealso></item> + </list></p> + </item> </taglist> </section> @@ -860,6 +870,24 @@ typedef struct ErlIOVec { <seealso marker="#erl_drv_tsd_get">erl_drv_tsd_get()</seealso>. </p> </item> + <tag><marker id="ErlDrvTime"/>ErlDrvTime</tag> + <item> + <p>A signed 64-bit integer type for representation of time.</p> + </item> + <tag><marker id="ErlDrvTimeUnit"/>ErlDrvTimeUnit</tag> + <item> + <p>An enumeration of time units supported by the driver API:</p> + <taglist> + <tag><c>ERL_DRV_SEC</c></tag> + <item><p>Seconds</p></item> + <tag><c>ERL_DRV_MSEC</c></tag> + <item><p>Milliseconds</p></item> + <tag><c>ERL_DRV_USEC</c></tag> + <item><p>Microseconds</p></item> + <tag><c>ERL_DRV_NSEC</c></tag> + <item><p>Nanoseconds</p></item> + </taglist> + </item> </taglist> </section> @@ -1023,6 +1051,11 @@ typedef struct ErlIOVec { <fsummary>Read a system timestamp</fsummary> <desc> <marker id="driver_get_now"></marker> + <warning><p><em>This function is deprecated! Do not use it!</em> + Use <seealso marker="#erl_drv_monotonic_time"><c>erl_drv_monotonic_time()</c></seealso> + (perhaps in combination with + <seealso marker="#erl_drv_time_offset"><c>erl_drv_time_offset()</c></seealso>) + instead.</p></warning> <p>This function reads a timestamp into the memory pointed to by the parameter <c>now</c>. See the description of <seealso marker="#ErlDrvNowData">ErlDrvNowData</seealso> for specification of its fields. </p> @@ -3042,6 +3075,86 @@ ERL_DRV_MAP int sz </desc> </func> + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_monotonic_time(ErlDrvTimeUnit time_unit)</nametext></name> + <fsummary>Get Erlang Monotonic Time</fsummary> + <desc> + <marker id="erl_drv_monotonic_time"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p> + Returns + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso>. Note that it is not uncommon with + negative values. + </p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_time_offset(ErlDrvTimeUnit time_unit)</nametext></name> + <fsummary>Get current Time Offset</fsummary> + <desc> + <marker id="erl_drv_time_offset"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Returns the current time offset between + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang monotonic time</seealso> + and + <seealso marker="time_correction#Erlang_System_Time">Erlang system time</seealso> + converted into the <c>time_unit</c> passed as argument.</p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlDrvTime</ret><nametext>erl_drv_convert_time_unit(ErlDrvTime val, ErlDrvTimeUnit from, ErlDrvTimeUnit to)</nametext></name> + <fsummary>Convert time unit of a time value</fsummary> + <desc> + <marker id="erl_drv_convert_time_unit"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>val</c></tag> + <item>Value to convert time unit for.</item> + <tag><c>from</c></tag> + <item>Time unit of <c>val</c>.</item> + <tag><c>to</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Converts the <c>val</c> value of time unit <c>from</c> to + the corresponding value of time unit <c>to</c>. The result is + rounded using the floor function.</p> + <p>Returns <c>ERL_DRV_TIME_ERROR</c> if called with an invalid + time unit argument.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlDrvTime"><c>ErlDrvTime</c></seealso></item> + <item><seealso marker="#ErlDrvTimeUnit"><c>ErlDrvTimeUnit</c></seealso></item> + </list> + </desc> + </func> + </funcs> <section> <title>SEE ALSO</title> diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 2d8706169f..420c9fea38 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -317,6 +317,17 @@ ok libraries might however fail if deprecated features are used. </p></item> + <tag><marker id="time_measurement"/>Time Measurement</tag> + <item><p>Support for time measurement in NIF libraries: + <list> + <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item> + <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item> + <item><seealso marker="#enif_monotonic_time"><c>enif_monotonic_time()</c></seealso></item> + <item><seealso marker="#enif_time_offset"><c>enif_time_offset()</c></seealso></item> + <item><seealso marker="#enif_convert_time_unit"><c>enif_convert_time_unit()</c></seealso></item> + </list></p> + </item> + <tag>Long-running NIFs</tag> <item><p><marker id="dirty_nifs"/>Native functions <seealso marker="#lengthy_work"> @@ -560,6 +571,25 @@ typedef enum { <item><p>A native signed 64-bit integer type.</p></item> <tag><marker id="ErlNifUInt64"/>ErlNifUInt64</tag> <item><p>A native unsigned 64-bit integer type.</p></item> + + <tag><marker id="ErlNifTime"/>ErlNifTime</tag> + <item> + <p>A signed 64-bit integer type for representation of time.</p> + </item> + <tag><marker id="ErlNifTimeUnit"/>ErlNifTimeUnit</tag> + <item> + <p>An enumeration of time units supported by the NIF API:</p> + <taglist> + <tag><c>ERL_NIF_SEC</c></tag> + <item><p>Seconds</p></item> + <tag><c>ERL_NIF_MSEC</c></tag> + <item><p>Milliseconds</p></item> + <tag><c>ERL_NIF_USEC</c></tag> + <item><p>Microseconds</p></item> + <tag><c>ERL_NIF_NSEC</c></tag> + <item><p>Nanoseconds</p></item> + </taglist> + </item> </taglist> </section> @@ -1486,6 +1516,88 @@ enif_map_iterator_destroy(env, &iter); <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_set">erl_drv_tsd_set</seealso>. </p></desc> </func> + + + <func> + <name><ret>ErlNifTime</ret><nametext>enif_monotonic_time(ErlNifTimeUnit time_unit)</nametext></name> + <fsummary>Get Erlang Monotonic Time</fsummary> + <desc> + <marker id="enif_monotonic_time"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p> + Returns + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso>. Note that it is not uncommon with + negative values. + </p> + <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item> + <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlNifTime</ret><nametext>enif_time_offset(ErlNifTimeUnit time_unit)</nametext></name> + <fsummary>Get current Time Offset</fsummary> + <desc> + <marker id="enif_time_offset"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>time_unit</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Returns the current time offset between + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang monotonic time</seealso> + and + <seealso marker="time_correction#Erlang_System_Time">Erlang system time</seealso> + converted into the <c>time_unit</c> passed as argument.</p> + <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid + time unit argument, or if called from a thread that is not a + scheduler thread.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item> + <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item> + </list> + </desc> + </func> + + <func> + <name><ret>ErlNifTime</ret><nametext>enif_convert_time_unit(ErlNifTime val, ErlNifTimeUnit from, ErlNifTimeUnit to)</nametext></name> + <fsummary>Convert time unit of a time value</fsummary> + <desc> + <marker id="enif_convert_time_unit"></marker> + <p>Arguments:</p> + <taglist> + <tag><c>val</c></tag> + <item>Value to convert time unit for.</item> + <tag><c>from</c></tag> + <item>Time unit of <c>val</c>.</item> + <tag><c>to</c></tag> + <item>Time unit of returned value.</item> + </taglist> + <p>Converts the <c>val</c> value of time unit <c>from</c> to + the corresponding value of time unit <c>to</c>. The result is + rounded using the floor function.</p> + <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid + time unit argument.</p> + <p>See also:</p> + <list> + <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item> + <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item> + </list> + </desc> + </func> + </funcs> <section> <title>SEE ALSO</title> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 72d08a03fe..803da382ed 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -131,6 +131,17 @@ </note> </item> + <tag><c>perf_counter</c></tag> + <item><p>Symbolic representation of the performance counter + time unit used by the Erlang runtime system.</p> + + <p>The <c>perf_counter</c> time unit behaves much in the same way + as the <c>native</c> time unit. That is it might differ inbetween + run-time restarts. You get values of this type by calling + <seealso marker="kernel:os#perf_counter/0"><c>os:perf_counter()</c></seealso> + </p> + </item> + </taglist> <p>The <c>time_unit/0</c> type may be extended. Use @@ -4642,6 +4653,17 @@ os_prompt% </pre> The content of <c><anno>GCInfo</anno></c> can be changed without prior notice.</p> </item> + <tag><c>{garbage_collection_info, <anno>GCInfo</anno>}</c></tag> + <item> + <p><c><anno>GCInfo</anno></c> is a list containing miscellaneous + detailed information about garbage collection for this process. + The content of <c><anno>GCInfo</anno></c> can be changed without + prior notice. + See <seealso marker="#gc_start">gc_start</seealso> in + <seealso marker="#trace/3">erlang:trace/3</seealso> for details about + what each item means. + </p> + </item> <tag><c>{group_leader, <anno>GroupLeader</anno>}</c></tag> <item> <p><c><anno>GroupLeader</anno></c> is group leader for the I/O of @@ -5848,6 +5870,146 @@ true</pre> <func> <name name="statistics" arity="1" clause_i="6"/> + <fsummary>Information about microstate accounting.</fsummary> + <desc> + <marker id="statistics_microstate_accounting"></marker> + <p> + Microstate accounting can be used to measure how much time the Erlang + runtime system spends doing various tasks. It is designed to be as + lightweight as possible, but there will be some overhead when this + is enabled. Microstate accounting is meant to be a profiling tool + to help figure out performance bottlenecks. + To <c>start</c>/<c>stop</c>/<c>reset</c> microstate_accounting you use + the system_flag + <seealso marker="#system_flag_microstate_accounting"> + <c>microstate_accounting</c></seealso>. + </p> + <p> + <c>erlang:statistics(microstate_accounting)</c> returns a list of maps + representing some of the OS threads within ERTS. Each map contains + <c>type</c> and <c>id</c> fields that can be used to identify what + thread it is, and also a counters field that contains data about how + much time has been spent in the various states.</p> + <pre> +> <input>erlang:statistics(microstate_accounting).</input> +[#{counters => #{aux => 1899182914, + check_io => 2605863602, + emulator => 45731880463, + gc => 1512206910, + other => 5421338456, + port => 221631, + sleep => 5150294100}, + id => 1, + type => scheduler}|...] + </pre> + <p>The time unit is the same as returned by + <seealso marker="kernel:os#perf_counter/0"> + <c>os:perf_counter/0</c></seealso>. + So to convert it to milliseconds you could do something like this:</p> + <pre> +lists:map( + fun(#{ counters := Cnt } = M) -> + MsCnt = maps:map(fun(_K, PerfCount) -> + erlang:convert_time_unit(PerfCount, perf_counter, 1000) + end, Cnt), + M#{ counters := MsCnt } + end, erlang:statistics(microstate_accounting)). + </pre> + <p> + It is important to note that these values are not guaranteed to be + the exact time spent in each state. This is because of various + optimisation done in order to keep the overhead as small as possible. + </p> + + <p>Currently the following <c><anno>MSAcc_Thread_Type</anno></c> are available:</p> + <taglist> + <tag><c>scheduler</c></tag> + <item>The main execution threads that do most of the work.</item> + <tag><c>async</c></tag><item>Async threads are used by various + linked-in drivers (mainly the file drivers) do offload non-cpu + intensive work.</item> + <tag><c>aux</c></tag><item>Takes care of any work that is not + specifically assigned to a scheduler.</item> + </taglist> + <p>Currently the following <c><anno>MSAcc_Thread_State</anno></c>s are available. + All states are exclusive, meaning that a thread cannot be in two states + at once. So if you add the numbers of all counters in a thread + you will get the total run-time for that thread.</p> + <taglist> + <tag><c>aux</c></tag> + <item>Time spent handling auxiliary jobs.</item> + <tag><c>check_io</c></tag> + <item>Time spent checking for new I/O events.</item> + <tag><c>emulator</c></tag> + <item>Time spent executing erlang processes.</item> + <tag><c>gc</c></tag> + <item>Time spent doing garbage collection. When extra states are + enabled this is the time spent doing non-fullsweep garbage + collections.</item> + <tag><c>other</c></tag> + <item>Time spent doing unaccounted things.</item> + <tag><c>port</c></tag> + <item>Time spent executing ports.</item> + <tag><c>sleep</c></tag> + <item>Time spent sleeping.</item> + </taglist> + <p>It is possible to add more fine grained <c><anno>MSAcc_Thread_State</anno></c>s + through configure. + (e.g. <c>./configure --with-microstate-accounting=extra</c>). + Enabling these states will cause a performance degradation when + microstate accounting is turned off and increase the overhead when + it is turned on.</p> + <taglist> + <tag><c>alloc</c></tag> + <item>Time spent managing memory. Without extra states this time is + spread out over all other states.</item> + <tag><c>bif</c></tag> + <item>Time spent in bifs. Without extra states this time is part of + the <c>emulator</c> state.</item> + <tag><c>busy_wait</c></tag> + <item>Time spent busy waiting. This is also the state where a + scheduler no longer reports that it is active when using + <seealso marker="#statistics_scheduler_wall_time"> + <c>erlang:statistics(scheduler_wall_time)</c></seealso>. + So if you add all other states but this and sleep and then divide that + by all time in the thread you should get something very similar to the + scheduler_wall_time fraction. Without extra states this time is part + of the <c>other</c> state.</item> + <tag><c>ets</c></tag> + <item>Time spent executing ETS bifs. Without extra states this time is + part of the <c>emulator</c> state.</item> + <tag><c>gc_full</c></tag> + <item>Time spent doing fullsweep garbage collection. Without extra + states this time is part of the <c>gc</c> state.</item> + <tag><c>nif</c></tag> + <item>Time spent in nifs. Without extra states this time is part of + the <c>emulator</c> state.</item> + <tag><c>send</c></tag> + <item>Time spent sending messages (processes only). Without extra + states this time is part of the <c>emulator</c> state.</item> + <tag><c>timers</c></tag> + <item>Time spent managing timers. Without extra states this time is + part of the <c>other</c> state.</item> + </taglist> + <p>There is a utility module called + <seealso marker="runtime_tools:msacc"><c>msacc</c></seealso> in + runtime_tools that can be used to more easily analyse these + statistics.</p> + + <p> + Returns <c>undefined</c> if the system flag + <seealso marker="#system_flag_microstate_accounting"> + <c>microstate_accounting</c></seealso> + is turned off. + </p> + <p>The list of thread information is unsorted and may appear in + different order between calls.</p> + <note><p>The threads and states are subject to change without any + prior notice.</p></note> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="7"/> <fsummary>Information about reductions.</fsummary> <desc> <marker id="statistics_reductions"></marker> @@ -5865,7 +6027,7 @@ true</pre> </func> <func> - <name name="statistics" arity="1" clause_i="7"/> + <name name="statistics" arity="1" clause_i="8"/> <fsummary>Information about the run-queues.</fsummary> <desc><marker id="statistics_run_queue"></marker> <p> @@ -5881,7 +6043,7 @@ true</pre> </func> <func> - <name name="statistics" arity="1" clause_i="8"/> + <name name="statistics" arity="1" clause_i="9"/> <fsummary>Information about the run-queue lengths.</fsummary> <desc><marker id="statistics_run_queue_lengths"></marker> <p> @@ -5901,7 +6063,7 @@ true</pre> </func> <func> - <name name="statistics" arity="1" clause_i="9"/> + <name name="statistics" arity="1" clause_i="10"/> <fsummary>Information about runtime.</fsummary> <desc> <p>Returns information about runtime, in milliseconds.</p> @@ -5916,7 +6078,7 @@ true</pre> </func> <func> - <name name="statistics" arity="1" clause_i="10"/> + <name name="statistics" arity="1" clause_i="11"/> <fsummary>Information about each schedulers work time.</fsummary> <desc> <marker id="statistics_scheduler_wall_time"></marker> @@ -5987,7 +6149,7 @@ ok </func> <func> - <name name="statistics" arity="1" clause_i="11"/> + <name name="statistics" arity="1" clause_i="12"/> <fsummary>Information about active processes and ports.</fsummary> <desc><marker id="statistics_total_active_tasks"></marker> <p> @@ -6005,7 +6167,7 @@ ok </func> <func> - <name name="statistics" arity="1" clause_i="12"/> + <name name="statistics" arity="1" clause_i="13"/> <fsummary>Information about the run-queue lengths.</fsummary> <desc><marker id="statistics_total_run_queue_lengths"></marker> <p> @@ -6024,7 +6186,7 @@ ok </func> <func> - <name name="statistics" arity="1" clause_i="13"/> + <name name="statistics" arity="1" clause_i="14"/> <fsummary>Information about wall clock.</fsummary> <desc> <p>Returns information about wall clock. <c>wall_clock</c> can @@ -6258,6 +6420,17 @@ ok <func> <name name="system_flag" arity="2" clause_i="5"/> + <fsummary>Set system flag microstate_accounting</fsummary> + <desc><p><marker id="system_flag_microstate_accounting"></marker> + Turns on/off microstate accounting measurements. By passing reset it is possible to reset + all counters to 0.</p> + <p>For more information see, + <seealso marker="#statistics_microstate_accounting">erlang:statistics(microstate_accounting)</seealso>. + </p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="6"/> <fsummary>Sets system flag <c>min_heap_size</c>.</fsummary> <desc> <p>Sets the default minimum heap size for processes. The size @@ -6272,7 +6445,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="6"/> + <name name="system_flag" arity="2" clause_i="7"/> <fsummary>Sets system flag <c>min_bin_vheap_size</c>.</fsummary> <desc> <p>Sets the default minimum binary virtual heap size for @@ -6289,7 +6462,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="7"/> + <name name="system_flag" arity="2" clause_i="8"/> <fsummary>Sets system flag <c>multi_scheduling</c>.</fsummary> <desc> <p><marker id="system_flag_multi_scheduling"></marker> @@ -6327,7 +6500,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="8"/> + <name name="system_flag" arity="2" clause_i="9"/> <fsummary>Sets system flag <c>scheduler_bind_type</c>.</fsummary> <type name="scheduler_bind_type"/> <desc> @@ -6445,7 +6618,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="9"/> + <name name="system_flag" arity="2" clause_i="10"/> <fsummary>Sets system flag <c>scheduler_wall_time</c>.</fsummary> <desc><p><marker id="system_flag_scheduler_wall_time"></marker> Turns on or off scheduler wall time measurements.</p> @@ -6455,7 +6628,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="10"/> + <name name="system_flag" arity="2" clause_i="11"/> <fsummary>Sets system flag <c>schedulers_online</c>.</fsummary> <desc> <p><marker id="system_flag_schedulers_online"></marker> @@ -6480,7 +6653,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="11"/> + <name name="system_flag" arity="2" clause_i="12"/> <fsummary>Sets system flag <c>trace_control_word</c>.</fsummary> <desc> <p>Sets the value of the node trace control word to @@ -7843,6 +8016,14 @@ ok <c>inactive</c>, and later <c>active</c> when the port callback returns.</p> </item> + <tag><c>monotonic_timestamp</c></tag> + <item> + <p>Timestamps in profile messages will use + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso>. The time-stamp (Ts) has the same + format and value as produced by + <c>erlang:monotonic_time(nano_seconds)</c>.</p> + </item> <tag><c>runnable_procs</c></tag> <item> <p>If a process is put into or removed from the run queue, a @@ -7863,6 +8044,25 @@ ok <c>{profile, scheduler, Id, State, NoScheds, Ts}</c>, is sent to <c><anno>ProfilerPid</anno></c>.</p> </item> + <tag><c>strict_monotonic_timestamp</c></tag> + <item> + <p>Timestamps in profile messages will consisting of + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso> and a monotonically increasing + integer. The time-stamp (Ts) has the same format and value + as produced by <c>{erlang:monotonic_time(nano_seconds), + erlang:unique_integer([monotonic])}</c>.</p> + </item> + <tag><c>timestamp</c></tag> + <item> + <p>Timestamps in profile messages will include a + time-stamp (Ts) that has the same form as returned by + <c>erlang:now()</c>. This is also the default if no + timestamp flag is given. If <c>cpu_timestamp</c> has + been enabled via <c>erlang:trace/3</c>, this will also + effect the timestamp produced in profiling messages + when <c>timestamp</c> flag is enabled.</p> + </item> </taglist> <note><p><c>erlang:system_profile</c> is considered experimental and its behavior can change in a future release.</p> @@ -8222,7 +8422,10 @@ timestamp() -> <tag><c>cpu_timestamp</c></tag> <item> <p>A global trace flag for the Erlang node that makes all - trace time-stamps to be in CPU time, not wall clock time. + trace time-stamps using the <c>timestamp</c> flag to be + in CPU time, not wall clock time. That is, <c>cpu_timestamp</c> + will not be used if <c>monotonic_timestamp</c>, or + <c>strict_monotonic_timestamp</c> is enabled. Only allowed with <c>PidSpec==all</c>. If the host machine OS does not support high-resolution CPU time measurements, <c>trace/3</c> exits with @@ -8230,6 +8433,26 @@ timestamp() -> not synchronize this value across cores, so be prepared that time might seem to go backwards when using this option.</p> </item> + <tag><c>monotonic_timestamp</c></tag> + <item> + <p>Includes an + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso> time-stamp in all trace messages. The + time-stamp (Ts) has the same format and value as produced by + <c>erlang:monotonic_time(nano_seconds)</c>. This flag overrides + the <c>cpu_timestamp</c> flag.</p> + </item> + <tag><c>strict_monotonic_timestamp</c></tag> + <item> + <p>Includes an timestamp consisting of + <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang + monotonic time</seealso> and a monotonically increasing + integer in all trace messages. The time-stamp (Ts) has the + same format and value as produced by + <c>{erlang:monotonic_time(nano_seconds), + erlang:unique_integer([monotonic])}</c>. This flag overrides + the <c>cpu_timestamp</c> flag.</p> + </item> <tag><c>arity</c></tag> <item> <p>Used with the <c>call</c> trace flag. @@ -8276,9 +8499,16 @@ timestamp() -> in the following list. <c>Pid</c> is the process identifier of the traced process in which the traced event has occurred. The third tuple element is the message tag.</p> - <p>If flag <c>timestamp</c> is given, the first tuple - element is <c>trace_ts</c> instead, and the time-stamp - is added last in the message tuple.</p> + <p>If flag <c>timestamp</c>, <c>strict_monotonic_timestamp</c>, or + <c>monotonic_timestamp</c> is given, the first tuple + element is <c>trace_ts</c> instead, and the time-stamp + is added as an extra element last in the message tuple. If + multiple timestamp flags are passed, <c>timestamp</c> has + precedence over <c>strict_monotonic_timestamp</c> which + in turn has precedence over <c>monotonic_timestamp</c>. All + timestamp flags are remembered, so if two are passed + and the one with highest precedence later is disabled + the other one will become active.</p> <marker id="trace_3_trace_messages"></marker> <taglist> <tag><c>{trace, Pid, 'receive', Msg}</c></tag> @@ -8373,14 +8603,14 @@ timestamp() -> <p>When <c>Pid</c> is scheduled to run. The process runs in function <c>{M, F, Arity}</c>. On some rare occasions, the current function cannot be determined, - then the last element <c>Arity</c> is <c>0</c>.</p> + then the last element is <c>0</c>.</p> </item> <tag><c>{trace, Pid, out, {M, F, Arity} | 0}</c></tag> <item> <p>When <c>Pid</c> is scheduled out. The process was running in function {M, F, Arity}. On some rare occasions, the current function cannot be determined, then the last - element <c>Arity</c> is <c>0</c>.</p> + element is <c>0</c>.</p> </item> <tag><c>{trace, Pid, gc_start, Info}</c></tag> <item> |