檢視原始碼 抽象格式
本節描述 Erlang 程式的語法樹以 Erlang 項表示的標準方式。此表示法稱為抽象格式。處理此類語法樹的函式為 compile:forms/1,2
,以及以下模組中的函式:
這些函式也用作語法轉換的輸入和輸出,請參閱 compile
模組。
我們使用函式 Rep
來表示從 Erlang 原始建構 C
到其抽象格式表示法 R
的映射,並寫為 R = Rep(C)
。
本節中的 ANNO
一詞代表註解,除其他事項外,表示建構在原始檔中發生的行號。詳情請參閱 erl_anno
。同一建構中的數個 ANNO
實例可以表示不同的註解。
由於運算子本身不是項,因此當下面提到運算子時,運算子的表示法應視為一個原子,其列印名稱與運算子的字元相同。
模組宣告和形式
模組宣告由一系列形式組成,這些形式可以是函式宣告或屬性。
- 如果 D 是由形式
F_1
、...、F_k
組成的模組宣告,則 Rep(D) =[Rep(F_1), ..., Rep(F_k)]
。 - 如果 F 是屬性
-export([Fun_1/A_1, ..., Fun_k/A_k])
,則 Rep(F) ={attribute,ANNO,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}
。 - 如果 F 是屬性
-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])
,則 Rep(F) ={attribute,ANNO,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}
。 - 如果 F 是屬性
-module(Mod)
,則 Rep(F) ={attribute,ANNO,module,Mod}
。 - 如果 F 是屬性
-file(File,Line)
,則 Rep(F) ={attribute,ANNO,file,{File,Line}}
。 - 如果 F 是函式宣告
Name Fc_1 ; ... ; Name Fc_k
,其中每個Fc_i
都是一個函式子句,具有相同長度Arity
的模式序列,則 Rep(F) ={function,ANNO,Name,Arity,[Rep(Fc_1), ...,Rep(Fc_k)]}
。 - 如果 F 是函式規格
-Spec Name Ft_1; ...; Ft_k
,其中Spec
是原子spec
或原子callback
,且每個Ft_i
都是一個可能受限制的函式類型,具有相同長度Arity
的引數序列,則 Rep(F) ={attribute,ANNO,Spec,{{Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}
。 - 如果 F 是函式規格
-spec Mod:Name Ft_1; ...; Ft_k
,其中每個Ft_i
都是一個可能受限制的函式類型,具有相同長度Arity
的引數序列,則 Rep(F) ={attribute,ANNO,spec,{{Mod,Name,Arity},[Rep(Ft_1), ..., Rep(Ft_k)]}}
。 - 如果 F 是記錄宣告
-record(Name,{V_1, ..., V_k})
,其中每個V_i
都是一個記錄欄位,則 Rep(F) ={attribute,ANNO,record,{Name,[Rep(V_1), ..., Rep(V_k)]}}
。關於 Rep(V),請參閱下文。 - 如果 F 是類型宣告
-Type Name(V_1, ..., V_k) :: T
,其中Type
是原子type
或原子opaque
,每個V_i
都是一個類型變數,且T
是一個類型,則 Rep(F) ={attribute,ANNO,Type,{Name,Rep(T),[Rep(V_1), ..., Rep(V_k)]}}
。 - 如果 F 是萬用屬性
-A(T)
,則 Rep(F) ={attribute,ANNO,A,T}
。
記錄欄位
記錄宣告中的每個欄位都可以具有可選的、明確的預設初始化運算式和可選的類型。
- 如果 V 是
A
,則 Rep(V) ={record_field,ANNO,Rep(A)}
。 - 如果 V 是
A = E
,其中E
是一個運算式,則 Rep(V) ={record_field,ANNO,Rep(A),Rep(E)}
。 - 如果 V 是
A :: T
,其中T
是一個類型,則 Rep(V) ={typed_record_field,{record_field,ANNO,Rep(A)},Rep(T)}
。 - 如果 V 是
A = E :: T
,其中E
是一個運算式,且T
是一個類型,則 Rep(V) ={typed_record_field,{record_field,ANNO,Rep(A),Rep(E)},Rep(T)}
。
語法分析錯誤和檔案結尾的表示法
除了形式的表示法之外,表示模組宣告的清單(由 epp
和 erl_parse
中的函式傳回)可以包含以下內容:
- 元組
{error,E}
和{warning,W}
,表示語法錯誤的形式和警告。 {eof,LOCATION}
,表示在剖析完整形式之前遇到的串流結尾。LOCATION
一詞代表位置,表示原始檔中最後一行的行號,以及可能在該行中的最後一欄的欄號。詳情請參閱erl_anno
。
關於這些值的更多詳細資訊,請參閱 erl_parse
中的 form_info/0
類型。
原子文字
有五種原子文字,它們在模式、運算式和防護中以相同的方式表示:
- 如果 L 是原子文字,則 Rep(L) =
{atom,ANNO,L}
。 - 如果 L 是字元文字,則 Rep(L) =
{char,ANNO,L}
。 - 如果 L 是浮點文字,則 Rep(L) =
{float,ANNO,L}
。 - 如果 L 是整數文字,則 Rep(L) =
{integer,ANNO,L}
。 - 如果 L 是由字元
C_1
、...、C_k
組成的字串文字,則 Rep(L) ={string,ANNO,[C_1, ..., C_k]}
。
請注意,負整數和浮點文字不會以此形式出現;它們會被剖析為一元否定運算子的應用。
模式
如果 Ps 是一系列模式 P_1, ..., P_k
,則 Rep(Ps) = [Rep(P_1), ..., Rep(P_k)]
。此類序列作為函式或 fun 的引數清單出現。
個別模式的表示方式如下:
- 如果 P 是原子文字
L
,則 Rep(P) = Rep(L)。 - 如果 P 是位元串模式
<<P_1:Size_1/TSL_1, ..., P_k:Size_k/TSL_k>>
,其中每個Size_i
都是可以評估為整數的運算式,且每個TSL_i
都是類型指定器清單,則 Rep(P) ={bin,ANNO,[{bin_element,ANNO,Rep(P_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,ANNO,Rep(P_k),Rep(Size_k),Rep(TSL_k)}]}
。關於 Rep(TSL),請參閱下文。省略的Size_i
由default
表示。省略的TSL_i
由default
表示。 - 如果 P 是複合模式
P_1 = P_2
,則 Rep(P) ={match,ANNO,Rep(P_1),Rep(P_2)}
。 如果 P 是 cons 模式
[P_h | P_t]
,則 Rep(P) ={cons,ANNO,Rep(P_h),Rep(P_t)}
。- 如果 P 是映射模式
#{A_1, ..., A_k}
,其中每個A_i
都是一個關聯P_i_1 := P_i_2
,則 Rep(P) ={map,ANNO,[Rep(A_1), ..., Rep(A_k)]}
。關於 Rep(A),請參閱下文。 - 如果 P 是 nil 模式
[]
,則 Rep(P) ={nil,ANNO}
。 - 如果 P 是運算子模式
P_1 Op P_2
,其中Op
是二元運算子(這是在字串文字或字元清單上應用++
的情況,或是在編譯時可評估為數字的運算式),則 Rep(P) ={op,ANNO,Op,Rep(P_1),Rep(P_2)}
。 - 如果 P 是運算子模式
Op P_0
,其中Op
是一元運算子(這是在編譯時可評估為數字的運算式),則 Rep(P) ={op,ANNO,Op,Rep(P_0)}
。 - 如果 P 是括號模式
( P_0 )
,則 Rep(P) =Rep(P_0)
,也就是說,括號模式無法與其主體區分。 - 如果 P 是記錄欄位索引模式
#Name.Field
,其中Field
是原子,則 Rep(P) ={record_index,ANNO,Name,Rep(Field)}
。 - 如果 P 是記錄模式
#Name{Field_1=P_1, ..., Field_k=P_k}
,其中每個Field_i
都是原子或_
,則 Rep(P) ={record,ANNO,Name,[{record_field,ANNO,Rep(Field_1),Rep(P_1)}, ..., {record_field,ANNO,Rep(Field_k),Rep(P_k)}]}
。 - 如果 P 是元組模式
{P_1, ..., P_k}
,則 Rep(P) ={tuple,ANNO,[Rep(P_1), ..., Rep(P_k)]}
。 - 如果 P 是通用模式
_
,則 Rep(P) ={var,ANNO,'_'}
。 - 如果 P 是變數模式
V
,則 Rep(P) ={var,ANNO,A}
,其中 A 是一個原子,其列印名稱與V
的字元相同。
請注意,每個模式都具有與某些運算式相同的原始形式,並且以與對應運算式相同的方式表示。
運算式
主體 B 是一個非空的運算式序列 E_1, ..., E_k
,且 Rep(B) = [Rep(E_1), ..., Rep(E_k)]
。
運算式 E 是以下其中之一:
- 如果 E 是原子文字
L
,則 Rep(E) = Rep(L)。 - 如果 E 是位元串理解
<<E_0 || Q_1, ..., Q_k>>
,其中每個Q_i
都是一個限定詞,則 Rep(E) ={bc,ANNO,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}
。關於 Rep(Q),請參閱下文。 - 如果 E 是位元串建構子
<<E_1:Size_1/TSL_1, ..., E_k:Size_k/TSL_k>>
,其中每個Size_i
都是一個運算式,且每個TSL_i
都是類型指定器清單,則 Rep(E) ={bin,ANNO,[{bin_element,ANNO,Rep(E_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,ANNO,Rep(E_k),Rep(Size_k),Rep(TSL_k)}]}
。關於 Rep(TSL),請參閱下文。省略的Size_i
由default
表示。省略的TSL_i
由default
表示。 - 如果 E 是區塊運算式
begin B end
,其中B
是一個主體,則 Rep(E) ={block,ANNO,Rep(B)}
。 - 如果 E 是 case 運算式
case E_0 of Cc_1 ; ... ; Cc_k end
,其中E_0
是一個運算式,且每個Cc_i
都是 case 子句,則 Rep(E) ={'case',ANNO,Rep(E_0),[Rep(Cc_1), ..., Rep(Cc_k)]}
。 - 如果 E 是 catch 運算式
catch E_0
,則 Rep(E) ={'catch',ANNO,Rep(E_0)}
。 如果 E 是 cons 骨架
[E_h | E_t]
,則 Rep(E) ={cons,ANNO,Rep(E_h),Rep(E_t)}
。- 如果 E 是一個 fun 表達式
fun Name/Arity
,則 Rep(E) ={'fun',ANNO,{function,Name,Arity}}
。 - 如果 E 是一個 fun 表達式
fun Module:Name/Arity
,則 Rep(E) ={'fun',ANNO,{function,Rep(Module),Rep(Name),Rep(Arity)}}
。 - 如果 E 是一個 fun 表達式
fun Fc_1 ; ... ; Fc_k end
,其中每個Fc_i
都是一個函數子句,則 Rep(E) ={'fun',ANNO,{clauses,[Rep(Fc_1), ..., Rep(Fc_k)]}}
。 - 如果 E 是一個 fun 表達式
fun Name Fc_1 ; ... ; Name Fc_k end
,其中Name
是一個變數,且每個Fc_i
都是一個函數子句,則 Rep(E) ={named_fun,ANNO,Name,[Rep(Fc_1), ..., Rep(Fc_k)]}
。 - 如果 E 是一個函數呼叫
E_0(E_1, ..., E_k)
,則 Rep(E) ={call,ANNO,Rep(E_0),[Rep(E_1), ..., Rep(E_k)]}
。 - 如果 E 是一個函數呼叫
E_m:E_0(E_1, ..., E_k)
,則 Rep(E) ={call,ANNO,{remote,ANNO,Rep(E_m),Rep(E_0)},[Rep(E_1), ..., Rep(E_k)]}
。 - 如果 E 是一個 if 表達式
if Ic_1 ; ... ; Ic_k end
,其中每個Ic_i
都是一個 if 子句,則 Rep(E) ={'if',ANNO,[Rep(Ic_1), ..., Rep(Ic_k)]}
。 - 如果 E 是一個列表推導式
[E_0 || Q_1, ..., Q_k]
,其中每個Q_i
都是一個限定詞,則 Rep(E) ={lc,ANNO,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}
。關於 Rep(Q),請參閱下方。 - 如果 E 是一個映射推導式
#{E_0 || Q_1, ..., Q_k}
,其中E_0
是一個關聯K => V
,且每個Q_i
都是一個限定詞,則 Rep(E) ={mc,ANNO,Rep(E_0),[Rep(Q_1), ..., Rep(Q_k)]}
。關於 Rep(E_0) 和 Rep(Q),請參閱下方。 - 如果 E 是一個映射創建
#{A_1, ..., A_k}
,其中每個A_i
都是一個關聯E_i_1 => E_i_2
,則 Rep(E) ={map,ANNO,[Rep(A_1), ..., Rep(A_k)]}
。關於 Rep(A),請參閱下方。 - 如果 E 是一個映射更新
E_0#{A_1, ..., A_k}
,其中每個A_i
都是一個關聯E_i_1 => E_i_2
或E_i_1 := E_i_2
,則 Rep(E) ={map,ANNO,Rep(E_0),[Rep(A_1), ..., Rep(A_k)]}
。關於 Rep(A),請參閱下方。 - 如果 E 是一個匹配運算符表達式
P = E_0
,其中P
是一個模式,則 Rep(E) ={match,ANNO,Rep(P),Rep(E_0)}
。 - 如果 E 是一個條件匹配運算符表達式
P ?= E_0
,其中P
是一個模式,則 Rep(E) ={maybe_match,ANNO,Rep(P),Rep(E_0)}
。 - 如果 E 是一個 maybe 表達式
maybe B end
,其中B
是一個主體,則 Rep(E) ={'maybe',ANNO,Rep(B)}
。 - 如果 E 是一個 maybe 表達式
maybe B else Ec_1 ; ... ; Ec_k end
,其中B
是一個主體,且每個Ec_i
都是一個 else 子句,則 Rep(E) ={'maybe',ANNO,Rep(B),{'else',ANNO,[Rep(Ec_1), ..., Rep(Ec_k)]}}
。 - 如果 E 是 nil,
[]
,則 Rep(E) ={nil,ANNO}
。 - 如果 E 是一個運算符表達式
E_1 Op E_2
,其中Op
是一個二元運算符,而不是匹配運算符=
,則 Rep(E) ={op,ANNO,Op,Rep(E_1),Rep(E_2)}
。 - 如果 E 是一個運算符表達式
Op E_0
,其中Op
是一個一元運算符,則 Rep(E) ={op,ANNO,Op,Rep(E_0)}
。 - 如果 E 是一個加括號的表達式
( E_0 )
,則 Rep(E) =Rep(E_0)
,也就是說,加括號的表達式無法與其主體區分開來。 - 如果 E 是一個 receive 表達式
receive Cc_1 ; ... ; Cc_k end
,其中每個Cc_i
都是一個 case 子句,則 Rep(E) ={'receive',ANNO,[Rep(Cc_1), ..., Rep(Cc_k)]}
。 - 如果 E 是一個 receive 表達式
receive Cc_1 ; ... ; Cc_k after E_0 -> B_t end
,其中每個Cc_i
都是一個 case 子句,E_0
是一個表達式,且B_t
是一個主體,則 Rep(E) ={'receive',ANNO,[Rep(Cc_1), ..., Rep(Cc_k)],Rep(E_0),Rep(B_t)}
。 - 如果 E 是一個 record 創建
#Name{Field_1=E_1, ..., Field_k=E_k}
,其中每個Field_i
都是一個原子或_
,則 Rep(E) ={record,ANNO,Name,[{record_field,ANNO,Rep(Field_1),Rep(E_1)}, ..., {record_field,ANNO,Rep(Field_k),Rep(E_k)}]}
。 - 如果 E 是一個 record 字段訪問
E_0#Name.Field
,其中Field
是一個原子,則 Rep(E) ={record_field,ANNO,Rep(E_0),Name,Rep(Field)}
。 - 如果 E 是一個 record 字段索引
#Name.Field
,其中Field
是一個原子,則 Rep(E) ={record_index,ANNO,Name,Rep(Field)}
。 - 如果 E 是一個 record 更新
E_0#Name{Field_1=E_1, ..., Field_k=E_k}
,其中每個Field_i
都是一個原子,則 Rep(E) ={record,ANNO,Rep(E_0),Name,[{record_field,ANNO,Rep(Field_1),Rep(E_1)}, ..., {record_field,ANNO,Rep(Field_k),Rep(E_k)}]}
。 - 如果 E 是一個元組骨架
{E_1, ..., E_k}
,則 Rep(E) ={tuple,ANNO,[Rep(E_1), ..., Rep(E_k)]}
。 - 如果 E 是一個 try 表達式
try B catch Tc_1 ; ... ; Tc_k end
,其中B
是一個主體,且每個Tc_i
都是一個 catch 子句,則 Rep(E) ={'try',ANNO,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],[]}
。 - 如果 E 是一個 try 表達式
try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n end
,其中B
是一個主體,每個Cc_i
都是一個 case 子句,且每個Tc_j
都是一個 catch 子句,則 Rep(E) ={'try',ANNO,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],[]}
。 - 如果 E 是一個 try 表達式
try B after A end
,其中B
和A
都是主體,則 Rep(E) ={'try',ANNO,Rep(B),[],[],Rep(A)}
。 - 如果 E 是一個 try 表達式
try B of Cc_1 ; ... ; Cc_k after A end
,其中B
和A
都是主體,且每個Cc_i
都是一個 case 子句,則 Rep(E) ={'try',ANNO,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[],Rep(A)}
。 - 如果 E 是一個 try 表達式
try B catch Tc_1 ; ... ; Tc_k after A end
,其中B
和A
都是主體,且每個Tc_i
都是一個 catch 子句,則 Rep(E) ={'try',ANNO,Rep(B),[],[Rep(Tc_1), ..., Rep(Tc_k)],Rep(A)}
。 - 如果 E 是一個 try 表達式
try B of Cc_1 ; ... ; Cc_k catch Tc_1 ; ... ; Tc_n after A end
,其中B
和A
都是主體,每個Cc_i
都是一個 case 子句,且每個Tc_j
都是一個 catch 子句,則 Rep(E) ={'try',ANNO,Rep(B),[Rep(Cc_1), ..., Rep(Cc_k)],[Rep(Tc_1), ..., Rep(Tc_n)],Rep(A)}
。 - 如果 E 是一個變數
V
,則 Rep(E) ={var,ANNO,A}
,其中A
是一個原子,其列印名稱與V
的字元相同。
限定詞
限定詞 Q 是以下其中之一
- 如果 Q 是一個篩選器
E
,其中E
是一個表達式,則 Rep(Q) =Rep(E)
。 - 如果 Q 是一個列表產生器
P <- E
,其中P
是一個模式,且E
是一個表達式,則 Rep(Q) ={generate,ANNO,Rep(P),Rep(E)}
。 - 如果 Q 是一個位元字串產生器
P <= E
,其中P
是一個模式,且E
是一個表達式,則 Rep(Q) ={b_generate,ANNO,Rep(P),Rep(E)}
。 - 如果 Q 是一個映射產生器
P <- E
,其中P
是一個關聯模式P_1 := P_2
,且E
是一個表達式,則 Rep(Q) ={m_generate,ANNO,Rep(P),Rep(E)}
。關於 Rep(P),請參閱下方。
位元字串元素類型規範
位元字串元素的類型規範列表 TSL 是一系列的類型規範 TS_1 - ... - TS_k
,且 Rep(TSL) = [Rep(TS_1), ..., Rep(TS_k)]
。
- 如果 TS 是一個類型規範
A
,其中A
是一個原子,則 Rep(TS) =A
。 - 如果 TS 是一個類型規範
A:Value
,其中A
是一個原子,且Value
是一個整數,則 Rep(TS) ={A,Value}
。
關聯
關聯 A 是以下其中之一
- 如果 A 是一個關聯
K => V
,則 Rep(A) ={map_field_assoc,ANNO,Rep(K),Rep(V)}
。 - 如果 A 是一個關聯
K := V
,則 Rep(A) ={map_field_exact,ANNO,Rep(K),Rep(V)}
。
子句
有函數子句、if 子句、case 子句和 catch 子句。
子句 C 是以下其中之一
- 如果 C 是一個 case 子句
P -> B
,其中P
是一個模式,且B
是一個主體,則 Rep(C) ={clause,ANNO,[Rep(P)],[],Rep(B)}
。 - 如果 C 是一個 case 子句
P when Gs -> B
,其中P
是一個模式,Gs
是一個守衛序列,且B
是一個主體,則 Rep(C) ={clause,ANNO,[Rep(P)],Rep(Gs),Rep(B)}
。 - 如果 C 是一個 catch 子句
P -> B
,其中P
是一個模式,而B
是一個主體,則 Rep(C) ={clause,ANNO,[Rep({throw,P,_})],[],Rep(B)}
,也就是說,帶有明確的例外類別throw
和帶有或不帶有明確的堆疊追蹤變數_
的 catch 子句,無法與不帶明確例外類別和不帶明確堆疊追蹤變數的 catch 子句區分開來。 - 如果 C 是一個 catch 子句
X : P -> B
,其中X
是一個原子文字或變數模式,P
是一個模式,而B
是一個主體,則 Rep(C) ={clause,ANNO,[Rep({X,P,_})],[],Rep(B)}
,也就是說,帶有明確的例外類別和帶有明確堆疊追蹤變數_
的 catch 子句,無法與帶有明確例外類別和不帶明確堆疊追蹤變數的 catch 子句區分開來。 - 如果 C 是一個 catch 子句
X : P : S -> B
,其中X
是一個原子文字或變數模式,P
是一個模式,S
是一個變數,而B
是一個主體,則 Rep(C) ={clause,ANNO,[Rep({X,P,S})],[],Rep(B)}
。 - 如果 C 是一個 catch 子句
P when Gs -> B
,其中P
是一個模式,Gs
是一個守衛序列,而B
是一個主體,則 Rep(C) ={clause,ANNO,[Rep({throw,P,_})],Rep(Gs),Rep(B)}
,也就是說,帶有明確的例外類別throw
和帶有或不帶有明確的堆疊追蹤變數_
的 catch 子句,無法與不帶明確例外類別和不帶明確堆疊追蹤變數的 catch 子句區分開來。 - 如果 C 是一個 catch 子句
X : P when Gs -> B
,其中X
是一個原子文字或變數模式,P
是一個模式,Gs
是一個守衛序列,而B
是一個主體,則 Rep(C) ={clause,ANNO,[Rep({X,P,_})],Rep(Gs),Rep(B)}
,也就是說,帶有明確例外類別和帶有明確堆疊追蹤變數_
的 catch 子句,無法與帶有明確例外類別和不帶明確堆疊追蹤變數的 catch 子句區分開來。 - 如果 C 是一個 catch 子句
X : P : S when Gs -> B
,其中X
是一個原子文字或變數模式,P
是一個模式,Gs
是一個守衛序列,S
是一個變數,而B
是一個主體,則 Rep(C) ={clause,ANNO,[Rep({X,P,S})],Rep(Gs),Rep(B)}
。 - 如果 C 是一個函數子句
( Ps ) -> B
,其中Ps
是一個模式序列,而B
是一個主體,則 Rep(C) ={clause,ANNO,Rep(Ps),[],Rep(B)}
。 - 如果 C 是一個函數子句
( Ps ) when Gs -> B
,其中Ps
是一個模式序列,Gs
是一個守衛序列,而B
是一個主體,則 Rep(C) ={clause,ANNO,Rep(Ps),Rep(Gs),Rep(B)}
。 - 如果 C 是一個 if 子句
Gs -> B
,其中Gs
是一個守衛序列,而B
是一個主體,則 Rep(C) ={clause,ANNO,[],Rep(Gs),Rep(B)}
。
守衛
一個守衛序列 Gs 是一連串的守衛 G_1; ...; G_k
,而 Rep(Gs) = [Rep(G_1), ..., Rep(G_k)]
。如果守衛序列為空,則 Rep(Gs) = []
。
一個守衛 G 是一個非空的守衛測試序列 Gt_1, ..., Gt_k
,而 Rep(G) = [Rep(Gt_1), ..., Rep(Gt_k)]
。
一個守衛測試 Gt 是以下其中一種
- 如果 Gt 是一個原子文字
L
,則 Rep(Gt) = Rep(L)。 - 如果 Gt 是一個位元字串建構子
<<Gt_1:Size_1/TSL_1, ..., Gt_k:Size_k/TSL_k>>
,其中每個Size_i
是一個守衛測試,而每個TSL_i
是一個類型指定符列表,則 Rep(Gt) ={bin,ANNO,[{bin_element,ANNO,Rep(Gt_1),Rep(Size_1),Rep(TSL_1)}, ..., {bin_element,ANNO,Rep(Gt_k),Rep(Size_k),Rep(TSL_k)}]}
。關於 Rep(TSL),請參閱上方說明。省略的Size_i
會以default
表示。省略的TSL_i
會以default
表示。 如果 Gt 是一個 cons 骨架
[Gt_h | Gt_t]
,則 Rep(Gt) ={cons,ANNO,Rep(Gt_h),Rep(Gt_t)}
。- 如果 Gt 是一個函數呼叫
A(Gt_1, ..., Gt_k)
,其中A
是一個原子,則 Rep(Gt) ={call,ANNO,Rep(A),[Rep(Gt_1), ..., Rep(Gt_k)]}
。 - 如果 Gt 是一個函數呼叫
A_m:A(Gt_1, ..., Gt_k)
,其中A_m
是原子erlang
,而A
是一個原子或運算子,則 Rep(Gt) ={call,ANNO,{remote,ANNO,Rep(A_m),Rep(A)},[Rep(Gt_1), ..., Rep(Gt_k)]}
。 - 如果 Gt 是一個 map 建立
#{A_1, ..., A_k}
,其中每個A_i
是一個關聯Gt_i_1 => Gt_i_2
,則 Rep(Gt) ={map,ANNO,[Rep(A_1), ..., Rep(A_k)]}
。關於 Rep(A),請參閱上方說明。 - 如果 Gt 是一個 map 更新
Gt_0#{A_1, ..., A_k}
,其中每個A_i
是一個關聯Gt_i_1 => Gt_i_2
或Gt_i_1 := Gt_i_2
,則 Rep(Gt) ={map,ANNO,Rep(Gt_0),[Rep(A_1), ..., Rep(A_k)]}
。關於 Rep(A),請參閱上方說明。 - 如果 Gt 是 nil,
[]
,則 Rep(Gt) ={nil,ANNO}
。 - 如果 Gt 是一個運算子守衛測試
Gt_1 Op Gt_2
,其中Op
是一個二元運算子,而非比對運算子=
,則 Rep(Gt) ={op,ANNO,Op,Rep(Gt_1),Rep(Gt_2)}
。 - 如果 Gt 是一個運算子守衛測試
Op Gt_0
,其中Op
是一個一元運算子,則 Rep(Gt) ={op,ANNO,Op,Rep(Gt_0)}
。 - 如果 Gt 是一個帶括號的守衛測試
( Gt_0 )
,則 Rep(Gt) =Rep(Gt_0)
,也就是說,帶括號的守衛測試無法與其主體區分開來。 - 如果 Gt 是一個記錄建立
#Name{Field_1=Gt_1, ..., Field_k=Gt_k}
,其中每個Field_i
是一個原子或_
,則 Rep(Gt) ={record,ANNO,Name,[{record_field,ANNO,Rep(Field_1),Rep(Gt_1)}, ..., {record_field,ANNO,Rep(Field_k),Rep(Gt_k)}]}
。 - 如果 Gt 是一個記錄欄位存取
Gt_0#Name.Field
,其中Field
是一個原子,則 Rep(Gt) ={record_field,ANNO,Rep(Gt_0),Name,Rep(Field)}
。 - 如果 Gt 是一個記錄欄位索引
#Name.Field
,其中Field
是一個原子,則 Rep(Gt) ={record_index,ANNO,Name,Rep(Field)}
。 - 如果 Gt 是一個元組骨架
{Gt_1, ..., Gt_k}
,則 Rep(Gt) ={tuple,ANNO,[Rep(Gt_1), ..., Rep(Gt_k)]}
。 - 如果 Gt 是一個變數模式
V
,則 Rep(Gt) ={var,ANNO,A}
,其中 A 是一個原子,其列印名稱由與V
相同的字元組成。
請注意,每個守衛測試都具有與某些表達式相同的原始形式,並且以與對應表達式相同的方式表示。
類型
- 如果 T 是一個已註解的類型
A :: T_0
,其中A
是一個變數,則 Rep(T) ={ann_type,ANNO,[Rep(A),Rep(T_0)]}
。 - 如果 T 是一個原子、一個字元或一個整數文字 L,則 Rep(T) = Rep(L)。
- 如果 T 是一個位元字串類型
<<_:M,_:_*N>>
,其中M
和N
是單例整數類型,則 Rep(T) ={type,ANNO,binary,[Rep(M),Rep(N)]}
。 - 如果 T 是空的列表類型
[]
,則 Rep(T) ={type,ANNO,nil,[]}
,也就是說,空的列表類型[]
無法與預定義的類型nil/0
區分開來。 - 如果 T 是一個 fun 類型
fun()
,則 Rep(T) ={type,ANNO,'fun',[]}
。 - 如果 T 是一個 fun 類型
fun((...) -> T_0)
,則 Rep(T) ={type,ANNO,'fun',[{type,ANNO,any},Rep(T_0)]}
。 - 如果 T 是一個 fun 類型
fun(Ft)
,其中Ft
是一個函數類型,則 Rep(T) =Rep(Ft)
。關於 Rep(Ft),請參閱下方說明。 - 如果 T 是一個整數範圍類型
L .. H
,其中L
和H
是單例整數類型,則 Rep(T) ={type,ANNO,range,[Rep(L),Rep(H)]}
。 - 如果 T 是一個 map 類型
map/0
,則 Rep(T) ={type,ANNO,map,any}
。 - 如果 T 是一個 map 類型
#{A_1, ..., A_k}
,其中每個A_i
是一個關聯類型,則 Rep(T) ={type,ANNO,map,[Rep(A_1), ..., Rep(A_k)]}
。關於 Rep(A),請參閱下方說明。 - 如果 T 是一個運算子類型
T_1 Op T_2
,其中Op
是一個二元運算子(這是可以在編譯時評估為整數的表達式的出現),則 Rep(T) ={op,ANNO,Op,Rep(T_1),Rep(T_2)}
。 - 如果 T 是一個運算子類型
Op T_0
,其中Op
是一個一元運算子(這是可以在編譯時評估為整數的表達式的出現),則 Rep(T) ={op,ANNO,Op,Rep(T_0)}
。 - 如果 T 是
( T_0 )
,則 Rep(T) =Rep(T_0)
,也就是說,帶括號的類型無法與其主體區分開來。 - 如果 T 是一個預定義(或內建)類型
N(T_1, ..., T_k)
,則 Rep(T) ={type,ANNO,N,[Rep(T_1), ..., Rep(T_k)]}
。 - 如果 T 是一個記錄類型
#Name{F_1, ..., F_k}
,其中每個F_i
是一個記錄欄位類型,則 Rep(T) ={type,ANNO,record,[Rep(Name),Rep(F_1), ..., Rep(F_k)]}
。關於 Rep(F),請參閱下方說明。 - 如果 T 是一個遠端類型
M:N(T_1, ..., T_k)
,則 Rep(T) ={remote_type,ANNO,[Rep(M),Rep(N),[Rep(T_1), ..., Rep(T_k)]]}
。 - 如果 T 是一個元組類型
tuple/0
,則 Rep(T) ={type,ANNO,tuple,any}
。 - 如果 T 是一個元組類型
{T_1, ..., T_k}
,則 Rep(T) ={type,ANNO,tuple,[Rep(T_1), ..., Rep(T_k)]}
。 如果 T 是一個類型聯合
T_1 | ... | T_k
,則 Rep(T) ={type,ANNO,union,[Rep(T_1), ..., Rep(T_k)]}
。- 如果 T 是一個類型變數
V
,則 Rep(T) ={var,ANNO,A}
,其中A
是一個原子,其列印名稱由與V
相同的字元組成。類型變數是任何變數,底線 (_
) 除外。 - 如果 T 是一個使用者定義的類型
N(T_1, ..., T_k)
,則 Rep(T) ={user_type,ANNO,N,[Rep(T_1), ..., Rep(T_k)]}
。
函數類型
一個函數類型 Ft 是以下其中一種
- 如果 Ft 是一個受限的函數類型
Ft_1 when Fc
,其中Ft_1
是一個函數類型,而Fc
是一個函數約束,則 Rep(T) ={type,ANNO,bounded_fun,[Rep(Ft_1),Rep(Fc)]}
。關於 Rep(Fc),請參閱下方說明。 - 如果 Ft 是一個函數類型
(T_1, ..., T_n) -> T_0
,其中每個T_i
是一個類型,則 Rep(Ft) ={type,ANNO,'fun',[{type,ANNO,product,[Rep(T_1), ..., Rep(T_n)]},Rep(T_0)]}
。
函數約束
函數約束 Fc 是一個非空的約束序列 C_1, ..., C_k
,且 Rep(Fc) = [Rep(C_1), ..., Rep(C_k)]
。
- 若 C 是一個約束
V :: T
,其中V
是一個型別變數,而T
是一個型別,則 Rep(C) ={type,ANNO,constraint,[{atom,ANNO,is_subtype},[Rep(V),Rep(T)]]}
。
關聯型別
- 若 A 是一個關聯型別
K => V
,其中K
和V
是型別,則 Rep(A) ={type,ANNO,map_field_assoc,[Rep(K),Rep(V)]}
。 - 若 A 是一個關聯型別
K := V
,其中K
和V
是型別,則 Rep(A) ={type,ANNO,map_field_exact,[Rep(K),Rep(V)]}
。
記錄欄位型別
- 若 F 是一個記錄欄位型別
Name :: Type
,其中Type
是一個型別,則 Rep(F) ={type,ANNO,field_type,[Rep(Name),Rep(Type)]}
。
預處理後的抽象格式
可以為編譯器指定編譯選項 debug_info
,將抽象程式碼儲存在 Beam 檔案中的 abstract_code
區塊(用於除錯目的)。
從 Erlang/OTP R9C 開始,abstract_code
區塊包含 {raw_abstract_v1,AbstractCode}
,其中 AbstractCode
是本節描述的抽象程式碼。
在 R9C 之前的 OTP 版本中,經過更多處理的抽象程式碼會儲存在 Beam 檔案中。元組的第一個元素會是 abstract_v1
(在 OTP R7B 中) 或 abstract_v2
(在 OTP R8B 中)。