Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is Solidity's Yul?

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains "what is the Yul of Solidity". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what is the Yul of Solidity".

Yul (formerly known as JULIA or IULIA) is an intermediate language that can be compiled to a variety of different backends (Ethernet virtual machine Ethereum Virtual Machine (EVM) 1.0, Ethernet virtual machine Ethereum Virtual Machine (EVM) 1.5, and eWASM is also planned). Because of this, it is designed to be a common standard for these three platforms. It can already be used for "inline assembly" within Solidity, and future versions of Solidity compilers will even use Yul as an intermediate language. It will also be easy to build an advanced optimizer phase for Yul.

The core components of Yul are functions, code blocks, variables, literals, for loops, if conditional statements, switch conditional statements, expressions, and variable assignments.

Yul is strongly typed, and both variables and literals need to be indicated by prefix symbols. Supported types are: bool, U8, S8, U32, S32, U64, S64, U128, s128, U256 and s256.

Yul itself doesn't even provide operators. If the target platform is the Ethernet Square virtual machine Ethereum Virtual Machine (EVM), the opcodes will be provided as built-in functions, but if the back-end platform changes, they can be reimplemented. For a list of mandatory built-in functions, see the following section.

The following example program assumes that the ethersquare virtual machine Ethereum Virtual Machine (EVM) opcodes mul,div and mo are natively supported or can be used as functions to calculate exponents.

{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)} can also use for loops instead of recursion to achieve the same function. Here, we need the Ethernet Square virtual machine Ethereum Virtual Machine (EVM) opcode lt (less than) and add available. {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)} 1Yul language description

This chapter introduces the Yul code. The Yul code is usually placed in a Yul object, which is described in the next section.

Syntax:

Code block ='{'statement *'} 'statement = code block | function definition | variable declaration | assignment | expression | Switch | For loop | Loop interrupt function definition =' function' identifier'('list of identifiers with types?)' ('- > 'list of identifiers with types)? Code block variable declaration = 'let' a list of identifiers with types (': = 'expression)? Assignment = list of identifiers': = 'expression expression = function call | Identifier | literal If conditional statement =' if' expression code block Switch conditional statement = 'switch' expression Case* (' default' code block)? Case = 'case' literal code block For loop =' for' code block expression code block Loop break = 'break' |' continue' function call = identifier'(expression (' 'expression) *)?') 'Identifier = [a Murz Amurz Zhuan $] [a-zA-Z_0-9] * list of identifiers = identifier (' 'identifier) * type name = identifier | built-in type name built-in type name =' bool' | [us] ('8' |'32'|'64'| '128' |' 256') list of identifiers with type = identifier': 'type name (' 'identifier': 'type name) * literal = (numeric literals | string literals | hexadecimal literals | True literals | False literals)': 'type name numerals = hexadecimal digits | decimal digits hexadecimal literals =' hex' ('"([0-9a-fA-F] {2}) *'|'\' ([0-9a-fA-F] {2}) *'\') string literals ='"([^"\ r\ n\\] |'\\'.) *'"'True literals =' true'False literals = 'false' hexadecimal digits =' 0x' [0-9a-fA-F] + decimal digits = [0-9] +

Grammatical limitations

Switches must have at least one case (including default). Default should not be allowed if all possible values of the expression are overridden (that is, switch statements with bool expressions should no longer have default statements if they have both true case and false case).

Each expression evaluates to zero or more values. Identifiers and literals are evaluated as one value, and function calls are evaluated as the return value of the called function.

In variable declarations and assignments, after the expression on the right (if any) is evaluated, you must get a value equal to the number of variables on the left. This is the only expression that allows multiple values to be evaluated.

The expression that is also a statement (that is, at the level of the code block) must only evaluate to zero values.

In all other cases, the expression must be evaluated with only one value.

The continue and break statements can only be used in the body of the loop and must be in the same function as the loop (or both must be at the top level).

The conditional part of the for loop can only be evaluated to one value.

Literals cannot be greater than their own type. The maximum defined type width is 256 bits.

Scope rule

Scopes in Yul are tightly bound to blocks (except functions and for loops, as described below) and all declarations (FunctionDefinition, VariableDeclaration) that introduce new identifiers into the scope.

The identifier is visible in the block in which it is defined (including all child nodes and sub-blocks). As an exception, the identifiers defined in the "init" section of the for loop (the first block) are visible in all other parts of the for loop (but not outside the loop). Identifiers declared in other parts of the for loop follow the general scope syntax rules. The parameters and return parameters of the function are visible in the function body, and their names cannot be the same.

Variables can only be referenced after declaration. In particular, variables cannot be referenced to the right of their own variable declarations. Functions can be referenced before declaration (if they are visible).

Shadowing is not allowed, that is, you cannot define an identifier with the same name if it is already visible, even if it is inaccessible.

Within a function, it is not possible to access variables declared outside the function.

Formal norm

We formally specify the AST by providing an overloaded evaluation function E on each node of the Yul. Any function can have side effects, so E takes two state objects and an AST node as its parameters and returns two new state objects and a variable number of other values.

These two state objects are the global state object (in the context of the Ethernet virtual machine Ethereum Virtual Machine (EVM) is the memory memory, which stores the state of the storage and the blockchain) and the local state object (the state of the local variable, that is, a segment of the stack in the Ethernet virtual machine Ethereum Virtual Machine (EVM)). If the AST node is a statement, E returns two state objects and a "mode" for break and continue statements. If the AST node is an expression, E returns two state objects and returns the same number of values as the result of the expression evaluation.

In this high-level description, the exact nature of the global state is not explained. The local state L is a mapping of identifier I to value v, expressed as L [I] = v. For identifier v, we use $v as the name of the identifier.

We will use deconstruction symbols for AST nodes.

E (G, L,: 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,: VariableDeclaration) = E (G, L,: Assignment) E (G, L,: VariableDeclaration) = let L1 be a copy of L where L1 [$vari] = 0 for I = 1,..., n G, L1, regularE (G, L,: 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,: ForLoop) = if n > = 1: let G1, L1, mode = E (G, L, i1,..., in) / / due to syntax restrictions Mode must be regular let G2, L2, mode = E (G1, L1, for {} condition post body) / / due to syntax restrictions Mode must be regular 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) = let G0, L0, v = E (G, L, condition) if v is true: e (G0, L0, body) else: G0, L0, regularE (G, L) : Switch) = E (G, L, switch condition case l1:t1 st1... Case ln:tn stn default {}) E (G, L, 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 Globe, block, mode = E (Gn, lump, block) Globe, Ln, Lang'[$ret1],..., lump'[$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

Type conversion function

Yul does not support implicit type conversions, so there are functions that provide explicit conversions. If an overflow occurs when converting a larger type to a shorter type, a run-time exception may occur.

The following types of "interceptive" conversions are allowed:

Bool

U32

U64

U256

S256

Low-level function

The following functions must be available:

Back end

The backend or target is responsible for translating the Yul into a specific bytecode. Each backend can expose functions with subsequent end names called prefixes. We keep the evm_ and ewasm_ prefixes for the two suggested backends.

Backend: EVM

The target Ethernet Square virtual machine Ethereum Virtual Machine (EVM) will have all the underlying opcodes of the Ethernet Square virtual machine Ethereum Virtual Machine (EVM) exposed with the evm_ prefix.

Backend: "EVM 1.5"

TBD

Backend: eWASM

TBD

2Yul object description

Syntax:

Top-level object = 'object'' {'code? (object | data) *'} 'object =' object' string literal'{'code? (object | data) *'} 'code =' code' code block data = 'data' string literals hexadecimal literals =' hex' ('"'([0-9a-fA-F] {2}) *'|'\'([0-9a-fA-F] {2}) *'\') string literals ='"'( [^ "\ r\ n\] |'\'.) *''

Above, the code block refers to the code block in the Yul code syntax explained in the previous chapter.

An example of a Yul object is as follows:

.. the code:// code consists of a single object. A single "code" node is the code of the object. / / each (other) named object or data part is serialized / / and is available for special built-in functions: datacopy / dataoffset / datasize is used to access object {code {let size = datasize ("runtime") let offset = allocate (size) / / here, for eWASM becomes a memory-to-memory copy For EVM, it is equivalent to codecopy datacopy (dataoffset ("runtime"), offset, size) / / this is a constructor And the runtime code will be returned return (offset, size)} data "Table2" hex "4123" object "runtime" {code {/ / Runtime code let size = datasize ("Contract2") let offset = allocate (size) / / here, for eWASM becomes a memory-to-memory copy For EVM, it is equivalent to codecopy datacopy (dataoffset ("Contract2"), offset, size) / / the constructor argument is a digital 0x1234 mstore (add (offset, size), 0x1234) create (offset, add (size, 32))} / / embedded object. The usage scenario is that the outer layer is a factory contract. And Contract2 will be the factory-generated code object "Contract2" {code {/ / code here.} object "runtime" {code {/ / code here.}} data "Table1 "hex" 4123 "} Thank you for reading The above is the content of "what is the Yul of Solidity". After the study of this article, I believe you have a deeper understanding of what the Yul of Solidity is, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report