寫在前面:HiBlock區塊鏈社區成立了翻譯小組,翻譯區塊鏈相關的技術文檔及資料,本文爲Solidity文檔翻譯的第九部分《Yul語言及對象說明》,特發佈出來邀請solidity愛好者、開發者作公開的審校,您能夠添加微信baobaotalk_com,驗證輸入「solidity」,而後將您的意見和建議發送給咱們,也能夠在文末「留言」區留言,有效的建議咱們會採納及合併進下一版本,同時將送一份小禮物給您以示感謝。後端
Yul (先前被也被稱爲 JULIA 或 IULIA)是一種能夠編譯到各類不一樣後端的中間語言( 以太坊虛擬機Ethereum Virtual Machine(EVM) 1.0,以太坊虛擬機Ethereum Virtual Machine(EVM) 1.5,而 eWASM 也在計劃中)。 正由於如此,它被設計成爲這三種平臺的可用的共同標準。 它已經能夠用於 Solidity 內部的「內聯彙編」,而且將來版本的 Solidity 編譯器甚至會將 Yul 用做中間語言。 爲 Yul 構建高級的優化器階段也將會很容易。安全
Yul 的核心組件是函數,代碼塊,變量,字面量,for 循環,if 條件語句,switch 條件語句,表達式和變量賦值。微信
Yul 是強類型的,變量和字面量都須要經過前綴符號來指明類型。支持的類型有:bool, u8, s8, u32, s32, u64, s64, u128, s128, u256 和 s256。ide
Yul 自己甚至不提供操做符。若是目標平臺是 以太坊虛擬機Ethereum Virtual Machine(EVM),則操做碼將做爲內置函數提供,但若是後端平臺發生了變化,則能夠從新實現它們。 有關強制性的內置函數的列表,請參閱下面的章節。函數
如下示例程序假定 以太坊虛擬機Ethereum Virtual Machine(EVM) 操做碼 mul,div 和 mo 是原生支持或能夠做爲函數用以計算指數的。oop
{ function power(base:u256, exponent:u256) -> result:u256 { switch exponent case 0:u256 { result := 1:u256 } case 1:u256 { result := base } default: { result := power(mul(base, base), div(exponent, 2:u256)) switch mod(exponent, 2:u256) case 1:u256 { result := mul(base, result) } } } } 也可用 for 循環代替遞歸來實現相同的功能。這裏,咱們須要 以太坊虛擬機Ethereum Virtual Machine(EVM) 操做碼 lt(小於)和 add 可用。 { function power(base:u256, exponent:u256) -> result:u256 { result := 1:u256 for { let i := 0:u256 } lt(i, exponent) { i := add(i, 1:u256) } { result := mul(result, base) } } }
本章介紹 Yul 代碼。Yul 代碼一般放置在一個 Yul 對象中,它將在下一節中介紹。post
語法:學習
代碼塊 = '{' 語句* '}' 語句 = 代碼塊 | 函數定義 | 變量聲明 | 賦值 | 表達式 | Switch | For 循環 | 循環中斷 函數定義 = 'function' 標識符 '(' 帶類型的標識符列表? ')' ( '->' 帶類型的標識符列表 )? 代碼塊 變量聲明 = 'let' 帶類型的標識符列表 ( ':=' 表達式 )? 賦值 = 標識符列表 ':=' 表達式 表達式 = 函數調用 | 標識符 | 字面量 If 條件語句 = 'if' 表達式 代碼塊 Switch 條件語句 = 'switch' 表達式 Case* ( 'default' 代碼塊 )? Case = 'case' 字面量 代碼塊 For 循環 = 'for' 代碼塊 表達式 代碼塊 代碼塊 循環中斷 = 'break' | 'continue' 函數調用 = 標識符 '(' ( 表達式 ( ',' 表達式 )* )? ')' 標識符 = [a-zA-Z_$] [a-zA-Z_0-9]* 標識符列表 = 標識符 ( ',' 標識符)* 類型名 = 標識符 | 內置的類型名 內置的類型名 = 'bool' | [us] ( '8' | '32' | '64' | '128' | '256' ) 帶類型的標識符列表 = 標識符 ':' 類型名 ( ',' 標識符 ':' 類型名 )* 字面量 = (數字字面量 | 字符串字面量 | 十六進制字面量 | True字面量 | False字面量) ':' 類型名 數字字面量 = 十六進制數字 | 十進制數字 十六進制字面量 = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')字符串字面量 = '"' ([^"\r\n\\] | '\\' .)* '"' True字面量 = 'true' False字面量 = 'false' 十六進制數字 = '0x' [0-9a-fA-F]+ 十進制數字 = [0-9]+
語法層面的限制區塊鏈
Switches 必須至少有一個 case(包括 default )。 若是表達式的全部可能值都被覆蓋了,那麼不該該容許使用 default (即帶 bool 表達式的 switch 語句同時具備 true case 和 false case 的狀況下不該再有 default 語句)。優化
每一個表達式都求值爲零個或多個值。 標識符和字面量求值爲一個值,函數調用求值爲所調用函數的返回值。
在變量聲明和賦值中,右側表達式(若是存在)求值後,必須得出與左側變量數量相等的值。 這是惟一容許求值出多個值的表達式。
那種同時又是語句的表達式(即在代碼塊的層次)求值結果必須只有零個值。
在其餘全部狀況中,表達式求值後必須僅有一個值。
continue 和 break 語句只能用在循環體中,而且必須與循環處於同一個函數中(或者二者都必須在頂層)。
for 循環的條件部分的求值結果只能爲一個值。
字面量不能夠大於它們自己的類型。已定義的最大類型寬度爲 256 比特。
做用域規則
Yul 中的做用域是與塊(除了函數和 for 循環,以下所述)和全部引入新的標識符到做用域中的聲明 ( FunctionDefinition ,VariableDeclaration )緊密綁定的。
標識符在將其定義的塊中可見(包括全部子節點和子塊)。 做爲例外,for 循環的 「init」 部分中(第一個塊)定義的標識符在 for 循環的全部其餘部分(但不在循環以外)中都是可見的。 在 for 循環的其餘部分聲明的標識符遵照常規的做用域語法規則。 函數的參數和返回參數在函數體中可見,而且它們的名稱不能相同。
變量只能在聲明後引用。 尤爲是,變量不能在它們本身的變量聲明的右邊被引用。 函數能夠在聲明以前被引用(若是它們是可見的)。
Shadowing 是不被容許的,便是說,你不能在同名標識符已經可見的狀況下又定義該標識符,即便它是不可訪問的。
在函數內,不可能訪問聲明在函數外的變量。
形式規範
咱們經過在 AST 的各個節點上提供重載的求值函數 E 來正式指定 Yul。 任何函數均可能有反作用,因此 E 接受兩個狀態對象和 AST 節點做爲它的參數,並返回兩個新的狀態對象和數量可變的其餘值。
這兩個狀態對象是全局狀態對象(在 以太坊虛擬機Ethereum Virtual Machine(EVM) 的上下文中是 內存memory,存儲storage 和區塊鏈的狀態)和本地狀態對象(局部變量的狀態,即 以太坊虛擬機Ethereum Virtual Machine(EVM) 中堆棧的某個段)。 若是 AST 節點是一個語句,E 將返回兩個狀態對象和一個用於 break 和 continue 語句的 「mode」。 若是 AST 節點是表達式,則 E 返回兩個狀態對象,並返回與表達式求值結果相同數量的值。
在這份高層次的描述中,並無對全局狀態的確切本質進行說明。 本地狀態 L 是標識符 i 到值 v 的映射,表示爲 L[i] = v。 對於標識符 v, 咱們用 $v 做爲標識符的名字。
咱們將爲 AST 節點使用解構符號。
E(G, L, <{St1, ..., Stn}>: Block) = let G1, L1, mode = E(G, L, St1, ..., Stn) let L2 be a restriction of L1 to the identifiers of L G1, L2, modeE(G, L, St1, ..., Stn: Statement) = if n is zero: G, L, regular else: let G1, L1, mode = E(G, L, St1) if mode is regular then E(G1, L1, St2, ..., Stn) otherwise G1, L1, modeE(G, L, FunctionDefinition) = G, L, regularE(G, L, <let var1, ..., varn := rhs>: VariableDeclaration) = E(G, L, <var1, ..., varn := rhs>: Assignment)E(G, L, <let var1, ..., varn>: VariableDeclaration) = let L1 be a copy of L where L1[$vari] = 0 for i = 1, ..., n G, L1, regularE(G, L, <var1, ..., varn := rhs>: Assignment) = let G1, L1, v1, ..., vn = E(G, L, rhs) let L2 be a copy of L1 where L2[$vari] = vi for i = 1, ..., n G, L2, regularE(G, L, <for { i1, ..., in } condition post body>: ForLoop) = if n >= 1: let G1, L1, mode = E(G, L, i1, ..., in) // 因爲語法限制,mode 必須是規則的 let G2, L2, mode = E(G1, L1, for {} condition post body) // 因爲語法限制,mode 必須是規則的 let L3 be the restriction of L2 to only variables of L G2, L3, regular else: let G1, L1, v = E(G, L, condition) if v is false: G1, L1, regular else: let G2, L2, mode = E(G1, L, body) if mode is break: G2, L2, regular else: G3, L3, mode = E(G2, L2, post) E(G3, L3, for {} condition post body)E(G, L, break: BreakContinue) = G, L, breakE(G, L, continue: BreakContinue) = G, L, continueE(G, L, <if condition body>: If) = let G0, L0, v = E(G, L, condition) if v is true: E(G0, L0, body) else: G0, L0, regularE(G, L, <switch condition case l1:t1 st1 ... case ln:tn stn>: Switch) = E(G, L, switch condition case l1:t1 st1 ... case ln:tn stn default {})E(G, L, <switch condition case l1:t1 st1 ... case ln:tn stn default st'>: Switch) = let G0, L0, v = E(G, L, condition) // i = 1 .. n // 對字面量求值,上下文無關 let _, _, v1 = E(G0, L0, l1) ... let _, _, vn = E(G0, L0, ln) if there exists smallest i such that vi = v: E(G0, L0, sti) else: E(G0, L0, st')E(G, L, <name>: Identifier) = G, L, L[$name]E(G, L, <fname(arg1, ..., argn)>: FunctionCall) = G1, L1, vn = E(G, L, argn) ... G(n-1), L(n-1), v2 = E(G(n-2), L(n-2), arg2) Gn, Ln, v1 = E(G(n-1), L(n-1), arg1) Let <function fname (param1, ..., paramn) -> ret1, ..., retm block> be the function of name $fname visible at the point of the call. Let L' be a new local state such that L'[$parami] = vi and L'[$reti] = 0 for all i. Let G'', L'', mode = E(Gn, L', block) G'', Ln, L''[$ret1], ..., L''[$retm]E(G, L, l: HexLiteral) = G, L, hexString(l), where hexString decodes l from hex and left-aligns it into 32 bytesE(G, L, l: StringLiteral) = G, L, utf8EncodeLeftAligned(l), where utf8EncodeLeftAligned performs a utf8 encoding of l and aligns it left into 32 bytesE(G, L, n: HexNumber) = G, L, hex(n) where hex is the hexadecimal decoding functionE(G, L, n: DecimalNumber) = G, L, dec(n), where dec is the decimal decoding function
類型轉換函數
Yul 不支持隱式類型轉換,所以存在提供顯式轉換的函數。 在將較大類型轉換爲較短類型時,若是發生溢出,則可能會發生運行時異常。
下列類型的「截取式」轉換是容許的:
bool
u32
u64
u256
s256
低級函數
如下函數必須可用:
後端
後端或目標負責將 Yul 翻譯到特定字節碼。 每一個後端均可以暴露之後端名稱爲前綴的函數。 咱們爲兩個建議的後端保留 evm_ 和 ewasm_ 前綴。
後端: EVM
目標 以太坊虛擬機Ethereum Virtual Machine(EVM) 將具備全部用 evm_ 前綴暴露的 以太坊虛擬機Ethereum Virtual Machine(EVM) 底層操做碼。
後端: "EVM 1.5"
TBD
後端: eWASM
TBD
語法:
頂層對象 = 'object' '{' 代碼? ( 對象 | 數據 )* '}' 對象 = 'object' 字符串字面量 '{' 代碼? ( 對象 | 數據 )* '}' 代碼 = 'code' 代碼塊 數據 = 'data' 字符串字面量 十六進制字面量 十六進制字面量 = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'') 字符串字面量 = '"' ([^"\r\n\\] | '\\' .)* '"'
在上面,代碼塊 指的是前一章中解釋的 Yul 代碼語法中的 代碼塊。
Yul 對象示例以下:
..code: // 代碼由單個對象組成。 單個 「code」 節點是對象的代碼。// 每一個(其餘)命名的對象或數據部分都被序列化// 並可供特殊內置函數:datacopy / dataoffset / datasize 用於訪問object { code { let size = datasize("runtime") let offset = allocate(size) // 這裏,對於 eWASM 變爲一個內存到內存的拷貝,對於 EVM 則至關於 codecopy datacopy(dataoffset("runtime"), offset, size) // 這是一個構造函數,而且運行時代碼會被返回 return(offset, size) } data "Table2" hex"4123" object "runtime" { code { // 運行時代碼 let size = datasize("Contract2") let offset = allocate(size) // 這裏,對於 eWASM 變爲一個內存到內存的拷貝,對於 EVM 則至關於 codecopy datacopy(dataoffset("Contract2"), offset, size) // 構造函數參數是一個數字 0x1234 mstore(add(offset, size), 0x1234) create(offset, add(size, 32)) } // 內嵌對象。使用場景是,外層是一個工廠合約,而 Contract2 將是由工廠生成的代碼 object "Contract2" { code { // 代碼在這 ... } object "runtime" { code { // 代碼在這 ... } } data "Table1" hex"4123" } } }
延伸閱讀:智能合約-Solidity官方文檔(1)
根據例子學習Solidity-Solidity官方文檔(3)
深刻理解Solidity之源文件及合約結構——Solidity中文文檔(4)
應用二進制接口(ABI) 說明——Solidity中文文檔(7)
點擊「閱讀原文」便可查看完整中文文檔
注:本文爲solidity翻譯的第九部分****《Yul語言及對象說明》,特發佈出來邀請solidity愛好者、開發者作公開的審校,您能夠添加微信baobaotalk_com,驗證輸入「solidity」,而後將您的意見和建議發送給咱們,也可在文末「留言」區留言,或經過原文連接訪問咱們的Github。有效的建議咱們會收納並及時改進,同時將送一份小禮物給您以示感謝。
本文內容來源於HiBlock區塊鏈社區翻譯小組,感謝全體譯者的辛苦工做。點擊「閱讀原文」便可查看完整中文文檔。
線上課程推薦
線上課程:《8小時區塊鏈智能合約開發實踐》
培訓講師:《白話區塊鏈》做者 蔣勇
課程原價:999元,現價 399元
更多福利: