区块广播:

Yul 语言说明

Babete船员发布在 技术文档
 11108  0

Yul (先前被也被称为 JULIA 或 IULIA)是一种可以编译到各种不同后端的中间语言( |evm| 1.0,|evm| 1.5,而 eWASM 也在计划中)。
正因为如此,它被设计成为这三种平台的可用的共同标准。
它已经可以用于 Solidity 内部的“内联汇编”,并且未来版本的 Solidity 编译器甚至会将 Yul 用作中间语言。 为 Yul 构建高级的优化器阶段也将会很容易。

… note::

请注意,用于“内联汇编”的书写风格是不带类型的(所有的都是 ``u256``),内置函数与 |evm| 操作码相同。
有关详细信息,请参阅内联汇编文档。

Yul 的核心组件是函数,代码块,变量,字面量,for 循环,if 条件语句,switch 条件语句,表达式和变量赋值。

Yul 是强类型的,变量和字面量都需要通过前缀符号来指明类型。支持的类型有:boolu8s8u32s32
u64s64u128s128u256s256

Yul 本身甚至不提供操作符。如果目标平台是 |evm|,则操作码将作为内置函数提供,但如果后端平台发生了变化,则可以重新实现它们。
有关强制性的内置函数的列表,请参阅下面的章节。

以下示例程序假定 |evm| 操作码 muldivmo 是原生支持或可以作为函数用以计算指数的。

… code::

{
    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 循环代替递归来实现相同的功能。这里,我们需要 |evm| 操作码 lt (小于)和 add 可用。

… code::

{
    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 代码通常放置在一个 Yul 对象中,它将在下一节中介绍。

语法::

代码块 = '{' 语句* '}'
语句 =
    代码块 |
    函数定义 |
    变量声明 |
    赋值 |
    表达式 |
    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 语句)。

每个表达式都求值为零个或多个值。 标识符和字面量求值为一个值,函数调用求值为所调用函数的返回值。

在变量声明和赋值中,右侧表达式(如果存在)求值后,必须得出与左侧变量数量相等的值。
这是唯一允许求值出多个值的表达式。

那种同时又是语句的表达式(即在代码块的层次)求值结果必须只有零个值。

在其他所有情况中,表达式求值后必须仅有一个值。

continuebreak 语句只能用在循环体中,并且必须与循环处于同一个函数中(或者两者都必须在顶层)。

for 循环的条件部分的求值结果只能为一个值。

字面量不可以大于它们本身的类型。已定义的最大类型宽度为 256 比特。

作用域规则

Yul 中的作用域是与块(除了函数和 for 循环,如下所述)和所有引入新的标识符到作用域中的声明
FunctionDefinitionVariableDeclaration )紧密绑定的。

标识符在将其定义的块中可见(包括所有子节点和子块)。
作为例外,for 循环的 “init” 部分中(第一个块)定义的标识符在 for 循环的所有其他部分(但不在循环之外)中都是可见的。
在 for 循环的其他部分声明的标识符遵守常规的作用域语法规则。
函数的参数和返回参数在函数体中可见,并且它们的名称不能相同。

变量只能在声明后引用。 尤其是,变量不能在它们自己的变量声明的右边被引用。
函数可以在声明之前被引用(如果它们是可见的)。

Shadowing 是不被允许的,即是说,你不能在同名标识符已经可见的情况下又定义该标识符,即使它是不可访问的。

在函数内,不可能访问声明在函数外的变量。

形式规范

我们通过在 AST 的各个节点上提供重载的求值函数 E 来正式指定 Yul。
任何函数都可能有副作用,所以 E 接受两个状态对象和 AST 节点作为它的参数,并返回两个新的状态对象和数量可变的其他值。

这两个状态对象是全局状态对象(在 |evm| 的上下文中是 |memory|,|storage| 和区块链的状态)和本地状态对象(局部变量的状态,即 |evm| 中堆栈的某个段)。
如果 AST 节点是一个语句,E 将返回两个状态对象和一个用于 break 和 continue 语句的 “mode”。
如果 AST 节点是表达式,则 E 返回两个状态对象,并返回与表达式求值结果相同数量的值。

在这份高层次的描述中,并没有对全局状态的确切本质进行说明。
本地状态 L 是标识符 i 到值 v 的映射,表示为 L<i> = v
对于标识符 v, 我们用 $v 作为标识符的名字。

我们将为 AST 节点使用解构符号。

… code::

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, mode
E(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, mode
E(G, L, FunctionDefinition) =
    G, L, regular
E(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, regular
E(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, regular
E(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, break
E(G, L, continue: BreakContinue) =
    G, L, continue
E(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, regular
E(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 bytes
E(G, L, l: StringLiteral) = G, L, utf8EncodeLeftAligned(l),
    where utf8EncodeLeftAligned performs a utf8 encoding of l
    and aligns it left into 32 bytes
E(G, L, n: HexNumber) = G, L, hex(n)
    where hex is the hexadecimal decoding function
E(G, L, n: DecimalNumber) = G, L, dec(n),
    where dec is the decimal decoding function

类型转换函数

Yul 不支持隐式类型转换,因此存在提供显式转换的函数。
在将较大类型转换为较短类型时,如果发生溢出,则可能会发生运行时异常。

下列类型的“截取式”转换是允许的:

  • bool
  • u32
  • u64
  • u256
  • s256

这里的每种类型的转换函数都有一个格式为 <input_type>to<output_type>(x:<input_type>) -> y:<output_type> 的原型,
比如 u32tobool(x:u32) -> y:boolu256tou32(x:u256) -> y:u32s256tou256(x:s256) -> y:u256

… note::

``u32tobool(x:u32) -> y:bool`` 可以由 ``y := not(iszerou256(x))`` 实现,并且
``booltou32(x:bool) -> y:u32`` 可以由 ``switch x case true:bool { y := 1:u32 } case false:bool { y := 0:u32 }`` 实现

低级函数

以下函数必须可用:

±--------------------------------------------------------------------------------------------------------------+
| 逻辑操作 |
±--------------------------------------------±----------------------------------------------------------------+
| not(x:bool) -> z:bool | 逻辑非 |
±--------------------------------------------±----------------------------------------------------------------+
| and(x:bool, y:bool) -> z:bool | 逻辑与 |
±--------------------------------------------±----------------------------------------------------------------+
| or(x:bool, y:bool) -> z:bool | 逻辑或 |
±--------------------------------------------±----------------------------------------------------------------+
| xor(x:bool, y:bool) -> z:bool | 异或 |
±--------------------------------------------±----------------------------------------------------------------+
| 算术操作 |
±--------------------------------------------±----------------------------------------------------------------+
| addu256(x:u256, y:u256) -> z:u256 | x + y |
±--------------------------------------------±----------------------------------------------------------------+
| subu256(x:u256, y:u256) -> z:u256 | x - y |
±--------------------------------------------±----------------------------------------------------------------+
| mulu256(x:u256, y:u256) -> z:u256 | x * y |
±--------------------------------------------±----------------------------------------------------------------+
| divu256(x:u256, y:u256) -> z:u256 | x / y |
±--------------------------------------------±----------------------------------------------------------------+
| divs256(x:s256, y:s256) -> z:s256 | x / y, 有符号数用补码形式 |
±--------------------------------------------±----------------------------------------------------------------+
| modu256(x:u256, y:u256) -> z:u256 | x % y |
±--------------------------------------------±----------------------------------------------------------------+
| mods256(x:s256, y:s256) -> z:s256 | x % y, 有符号数用补码形式 |
±--------------------------------------------±----------------------------------------------------------------+
| signextendu256(i:u256, x:u256) -> z:u256 | 从第 (i*8+7) 位开始进行符号扩展,从最低符号位开始计算 |
±--------------------------------------------±----------------------------------------------------------------+
| expu256(x:u256, y:u256) -> z:u256 | x 的 y 次方 |
±--------------------------------------------±----------------------------------------------------------------+
| addmodu256(x:u256, y:u256, m:u256) -> z:u256| 任意精度的数学模运算 (x + y) % m |
±--------------------------------------------±----------------------------------------------------------------+
| mulmodu256(x:u256, y:u256, m:u256) -> z:u256| 任意精度的数学模运算 (x * y) % m |
±--------------------------------------------±----------------------------------------------------------------+
| ltu256(x:u256, y:u256) -> z:bool | 若 x < y 为 true, 否则为 false |
±--------------------------------------------±----------------------------------------------------------------+
| gtu256(x:u256, y:u256) -> z:bool | 若 x > y 为 true, 否则为 false |
±--------------------------------------------±----------------------------------------------------------------+
| sltu256(x:s256, y:s256) -> z:bool | 若 x < y 为 true, 否则为 false |
| | 有符号数用补码形式 |
±--------------------------------------------±----------------------------------------------------------------+
| sgtu256(x:s256, y:s256) -> z:bool | 若 x > y 为 true, 否则为 false |
| | 有符号数用补码形式 |
±--------------------------------------------±----------------------------------------------------------------+
| equ256(x:u256, y:u256) -> z:bool | 若 x == y 为 true, 否则为 false |
±--------------------------------------------±----------------------------------------------------------------+
| iszerou256(x:u256) -> z:bool | 若 x == 0 为 true, 否则为 false |
±--------------------------------------------±----------------------------------------------------------------+
| notu256(x:u256) -> z:u256 | ~x, 对 x 按位非 |
±--------------------------------------------±----------------------------------------------------------------+
| andu256(x:u256, y:u256) -> z:u256 | x 和 y 按位与 |
±--------------------------------------------±----------------------------------------------------------------+
| oru256(x:u256, y:u256) -> z:u256 | x 和 y 按位或 |
±--------------------------------------------±----------------------------------------------------------------+
| xoru256(x:u256, y:u256) -> z:u256 | x 和 y 按位异或 |
±--------------------------------------------±----------------------------------------------------------------+
| shlu256(x:u256, y:u256) -> z:u256 | 将 x 逻辑左移 y 位 |
±--------------------------------------------±----------------------------------------------------------------+
| shru256(x:u256, y:u256) -> z:u256 | 将 x 逻辑右移 y 位 |
±--------------------------------------------±----------------------------------------------------------------+
| saru256(x:u256, y:u256) -> z:u256 | 将 x 算术右移 y 位 |
±--------------------------------------------±----------------------------------------------------------------+
| byte(n:u256, x:u256) -> v:u256 | x 的第 n 字节,这里的索引位置是从 0 开始的; |
| | 能否用 and256(shr256(n, x), 0xff) 来替换它, |
| | 并使它在 EVM 后端之外被优化呢? |
±--------------------------------------------±----------------------------------------------------------------+
| 内存和存储 |
±--------------------------------------------±----------------------------------------------------------------+
| mload(p:u256) -> v:u256 | mem[p…(p+32)) |
±--------------------------------------------±----------------------------------------------------------------+
| mstore(p:u256, v:u256) | mem[p…(p+32)) := v |
±--------------------------------------------±----------------------------------------------------------------+
| mstore8(p:u256, v:u256) | mem := v & 0xff - 仅修改单个字节 |
±--------------------------------------------±----------------------------------------------------------------+
| sload(p:u256) -> v:u256 | storage |
±--------------------------------------------±----------------------------------------------------------------+
| sstore(p:u256, v:u256) | storage := v |
±--------------------------------------------±----------------------------------------------------------------+
| msize() -> size:u256 | 内存的大小, 即已访问过的内存的最大下标, |
| | 因为内存扩展的限制(只能按字进行扩展) |
| | 返回值永远都是 32 字节的倍数 |
±--------------------------------------------±----------------------------------------------------------------+
| 执行控制 |
±--------------------------------------------±----------------------------------------------------------------+
| create(v:u256, p:u256, s:u256) | 以 mem[p…(p+s)) 上的代码创建一个新合约,发送 |
| | v 个 wei,并返回一个新的地址 |
±--------------------------------------------±----------------------------------------------------------------+
| call(g:u256, a:u256, v:u256, in:u256, | 调用地址 a 上的合约,以 mem[in…(in+insize)) 作为输入 |
| insize:u256, out:u256, | 一并发送 g gas 和 v wei ,以 mem[out…(out+outsize)) |
| outsize:u256) | 作为输出空间。若错误,返回 0 (比如,gas 用光 |
| -> r:u256 | 成功,返回 1 |
±--------------------------------------------±----------------------------------------------------------------+
| callcode(g:u256, a:u256, v:u256, in:u256, | 相当于 call 但仅仅使用地址 a 上的代码, |
| insize:u256, out:u256, | 而留在当前合约的上下文当中 |
| outsize:u256) -> r:u256 | |
±--------------------------------------------±----------------------------------------------------------------+
| delegatecall(g:u256, a:u256, in:u256, | 相当于 callcode, |
| insize:u256, out:u256, | 但同时保留 caller |
| outsize:u256) -> r:u256 | 和 callvalue |
±--------------------------------------------±----------------------------------------------------------------+
| abort() | 终止 (相当于EVM上的非法指令) |
±--------------------------------------------±----------------------------------------------------------------+
| return(p:u256, s:u256) | 终止执行,返回 mem[p…(p+s)) 上的数据 |
±--------------------------------------------±----------------------------------------------------------------+
| revert(p:u256, s:u256) | 终止执行,恢复状态变更,返回 mem[p…(p+s)) 上的数据 |
±--------------------------------------------±----------------------------------------------------------------+
| selfdestruct(a:u256) | 终止执行,销毁当前合约,并且将余额发送到地址 a |
±--------------------------------------------±----------------------------------------------------------------+
| log0(p:u256, s:u256) | 用 mem[p…(p+s)] 上的数据产生日志,但没有 topic |
±--------------------------------------------±----------------------------------------------------------------+
| log1(p:u256, s:u256, t1:u256) | 用 mem[p…(p+s)] 上的数据和 topic t1 产生日志 |
±--------------------------------------------±----------------------------------------------------------------+
| log2(p:u256, s:u256, t1:u256, t2:u256) | 用 mem[p…(p+s)] 上的数据和 topic t1,t2 产生日志 |
±--------------------------------------------±----------------------------------------------------------------+
| log3(p:u256, s:u256, t1:u256, t2:u256, | 用 mem[p…(p+s)] 上的数据和 topic t1,t2,t3 产生日志 |
| t3:u256) | |
±--------------------------------------------±----------------------------------------------------------------+
| log4(p:u256, s:u256, t1:u256, t2:u256, | 用 mem[p…(p+s)] 上的数据和 topic t1,t2,t3,t4 |
| t3:u256, t4:u256) | 产生日志 |
±--------------------------------------------±----------------------------------------------------------------+
| 状态查询 |
±--------------------------------------------±----------------------------------------------------------------+
| blockcoinbase() -> address:u256 | 当前的矿工 |
±--------------------------------------------±----------------------------------------------------------------+
| blockdifficulty() -> difficulty:u256 | 当前区块的难度 |
±--------------------------------------------±----------------------------------------------------------------+
| blockgaslimit() -> limit:u256 | 当前区块的区块 gas 限制 |
±--------------------------------------------±----------------------------------------------------------------+
| blockhash(b:u256) -> hash:u256 | 区块号为 b 的区块的哈希, |
| | 仅可用于最近的 256 个区块,不包含当前区块 |
±--------------------------------------------±----------------------------------------------------------------+
| blocknumber() -> block:u256 | 当前区块号 |
±--------------------------------------------±----------------------------------------------------------------+
| blocktimestamp() -> timestamp:u256 | 自 epoch 开始的,当前块的时间戳,以秒为单位 |
±--------------------------------------------±----------------------------------------------------------------+
| txorigin() -> address:u256 | 交易的发送方 |
±--------------------------------------------±----------------------------------------------------------------+
| txgasprice() -> price:u256 | 交易中的 gas 价格 |
±--------------------------------------------±----------------------------------------------------------------+
| gasleft() -> gas:u256 | 还可用于执行的 gas |
±--------------------------------------------±----------------------------------------------------------------+
| balance(a:u256) -> v:u256 | 地址 a 上的 wei 余额 |
±--------------------------------------------±----------------------------------------------------------------+
| this() -> address:u256 | 当前合约/执行上下文的地址 |
±--------------------------------------------±----------------------------------------------------------------+
| caller() -> address:u256 | 调用的发送方 (不包含委托调用) |
±--------------------------------------------±----------------------------------------------------------------+
| callvalue() -> v:u256 | 与当前调用一起发送的 wei |
±--------------------------------------------±----------------------------------------------------------------+
| calldataload(p:u256) -> v:u256 | 从 position p 开始的 calldata (32 字节) |
±--------------------------------------------±----------------------------------------------------------------+
| calldatasize() -> v:u256 | 以字节为单位的 calldata 的大小 |
±--------------------------------------------±----------------------------------------------------------------+
| calldatacopy(t:u256, f:u256, s:u256) | 从位置为 f 的 calldata 中,拷贝 s 字节到内存位置 t |
±--------------------------------------------±----------------------------------------------------------------+
| codesize() -> size:u256 | 当前合约/执行上下文的代码大小 |
±--------------------------------------------±----------------------------------------------------------------+
| codecopy(t:u256, f:u256, s:u256) | 从 code 位置 f 拷贝 s 字节到内存位置 t |
±--------------------------------------------±----------------------------------------------------------------+
| extcodesize(a:u256) -> size:u256 | 地址 a 上的代码大小 |
±--------------------------------------------±----------------------------------------------------------------+
| extcodecopy(a:u256, t:u256, f:u256, s:u256) | 相当于 codecopy(t, f, s),但从地址 a 获取代码 |
±--------------------------------------------±----------------------------------------------------------------+
| 其他 |
±--------------------------------------------±----------------------------------------------------------------+
| discard(unused:bool) | 丢弃值 |
±--------------------------------------------±----------------------------------------------------------------+
| discardu256(unused:u256) | 丢弃值 |
±--------------------------------------------±----------------------------------------------------------------+
| splitu256tou64(x:u256) -> (x1:u64, x2:u64, | 将一个 u256 拆分为四个 u64 |
| x3:u64, x4:u64) | |
±--------------------------------------------±----------------------------------------------------------------+
| combineu64tou256(x1:u64, x2:u64, x3:u64, | 将四个 u64 组合为一个 u256 |
| x4:u64) -> (x:u256) | |
±--------------------------------------------±----------------------------------------------------------------+
| keccak256(p:u256, s:u256) -> v:u256 | keccak(mem[p…(p+s))) |
±--------------------------------------------±----------------------------------------------------------------+

后端

后端或目标负责将 Yul 翻译到特定字节码。 每个后端都可以暴露以后端名称为前缀的函数。 我们为两个建议的后端保留 evm_ewasm_ 前缀。

后端: EVM

目标 |evm| 将具有所有用 evm_ 前缀暴露的 |evm| 底层操作码。

后端: “EVM 1.5”

TBD

后端: eWASM

TBD

Yul 对象说明

语法::

顶层对象 = '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"
        }
    }
}
  • 正序
  • 最新
帖子暂无回复,回帖抢沙发
登录 账号发表你的看法,还没有账号?立即免费 注册