Merge pull request #3220 from ethereum/IuliaIf

If statement for Iulia / Inline Assembly
This commit is contained in:
chriseth
2017-11-27 09:02:46 -05:00
committed by GitHub
19 changed files with 163 additions and 11 deletions
+21 -3
View File
@@ -26,6 +26,7 @@ arising when writing manual assembly by the following features:
* access to external variables: ``function f(uint x) { assembly { x := sub(x, 1) } }``
* labels: ``let x := 10 repeat: x := sub(x, 1) jumpi(repeat, eq(x, 0))``
* loops: ``for { let i := 0 } lt(i, x) { i := add(i, 1) } { y := mul(2, y) }``
* if statements: ``if slt(x, 0) { x := sub(0, x) }``
* switch statements: ``switch x case 0 { y := mul(x, 2) } default { y := 0 }``
* function calls: ``function f(x) -> y { switch x case 0 { y := 1 } default { y := mul(x, f(sub(x, 1))) } }``
@@ -400,7 +401,7 @@ Labels
Another problem in EVM assembly is that ``jump`` and ``jumpi`` use absolute addresses
which can change easily. Solidity inline assembly provides labels to make the use of
jumps easier. Note that labels are a low-level feature and it is possible to write
efficient assembly without labels, just using assembly functions, loops and switch instructions
efficient assembly without labels, just using assembly functions, loops, if and switch instructions
(see below). The following code computes an element in the Fibonacci series.
.. code::
@@ -523,6 +524,21 @@ is performed by replacing the variable's value on the stack by the new value.
=: v // instruction style assignment, puts the result of sload(10) into v
}
If
--
The if statement can be used for conditionally executing code.
There is no "else" part, consider using "switch" (see below) if
you need multiple alternatives.
.. code::
{
if eq(value, 0) { revert(0, 0) }
}
The curly braces for the body are required.
Switch
------
@@ -622,7 +638,7 @@ Things to Avoid
---------------
Inline assembly might have a quite high-level look, but it actually is extremely
low-level. Function calls, loops and switches are converted by simple
low-level. Function calls, loops, ifs and switches are converted by simple
rewriting rules and after that, the only thing the assembler does for you is re-arranging
functional-style opcodes, managing jump labels, counting stack height for
variable access and removing stack slots for assembly-local variables when the end
@@ -669,7 +685,7 @@ for the Solidity compiler. In this form, it tries to achieve several goals:
3. Control flow should be easy to detect to help in formal verification and optimization.
In order to achieve the first and last goal, assembly provides high-level constructs
like ``for`` loops, ``switch`` statements and function calls. It should be possible
like ``for`` loops, ``if`` and ``switch`` statements and function calls. It should be possible
to write assembly programs that do not make use of explicit ``SWAP``, ``DUP``,
``JUMP`` and ``JUMPI`` statements, because the first two obfuscate the data flow
and the last two obfuscate control flow. Furthermore, functional statements of
@@ -875,6 +891,7 @@ Grammar::
FunctionalAssemblyAssignment |
AssemblyAssignment |
LabelDefinition |
AssemblyIf |
AssemblySwitch |
AssemblyFunctionDefinition |
AssemblyFor |
@@ -891,6 +908,7 @@ Grammar::
IdentifierList = Identifier ( ',' Identifier)*
AssemblyAssignment = '=:' Identifier
LabelDefinition = Identifier ':'
AssemblyIf = 'if' FunctionalAssemblyExpression AssemblyBlock
AssemblySwitch = 'switch' FunctionalAssemblyExpression AssemblyCase*
( 'default' AssemblyBlock )?
AssemblyCase = 'case' FunctionalAssemblyExpression AssemblyBlock
+10 -2
View File
@@ -15,7 +15,7 @@ future versions of the Solidity compiler will even use JULIA as intermediate
language. It should also be easy to build high-level optimizer stages for JULIA.
The core components of JULIA are functions, blocks, variables, literals,
for-loops, switch-statements, expressions and assignments to variables.
for-loops, if-statements, switch-statements, expressions and assignments to variables.
JULIA is typed, both variables and literals must specify the type with postfix
notation. The supported types are ``bool``, ``u8``, ``s8``, ``u32``, ``s32``,
@@ -88,6 +88,8 @@ Grammar::
IdentifierList ':=' Expression
Expression =
FunctionCall | Identifier | Literal
If =
'if' Expression Block
Switch =
'switch' Expression Case* ( 'default' Block )?
Case =
@@ -248,8 +250,14 @@ We will use a destructuring notation for the AST nodes.
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 {})
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