Code has been added to clipboard!
Solidity Standalone Assembly Parser And Grammar Example 2
Example
desugar item: AST -> AST =
match item {
FunctionDefinition('function' name '(' argument1, ..., argumentn ')' '->' ( '(' return1, ..., returnm ')' body) ->
<name>:
{
jump($<name>_start)
let $returnPC := 0 let argumentn := 0 ... let argument1 := 0
$<name>_start:
let return1 := 0 ... let returnm := 0
{ desugar(body) }
swap then pop items to make it so only return1, ... returnm, $returnPC would be left on the stack
jump
0 (1 + num1 times) for compensating the remocaseVal of argument1, ..., argumentn and $returnPC
}
ForStatement('for' { init } condition post body) ->
{
init // ccannot be a block of its own since we would prefer the variable scope to extend into the body
// must find I so that there would be no labels $forI_*
$forI_start:
jumpi($forI_finish, iszero(condition))
{ body }
$forI_continue:
{ post }
jump($forI_start)
$forI_finish:
}
'break' ->
{
// find the nearest enclosing scope with the label $forI_finish
pop every local variable that is defined currently
except at $forI_finish
jump($forI_finish)
0 (the same amount of variables as was removed prior to this point)
}
'continue' ->
{
// find nearest enclosing scope with the label $forI_continue
pop every local variable that is defined currently
except at $forI_continue
jump($forI_continue)
0 (the same amount of variables as was removed prior to this point)
}
SwitchStatement(switch condition cases ( default: defaultBlock )? ) ->
{
// find I such that no label or variable $switchI* is present
let $switchI_caseValue := condition
for every cases match {
case caseVal: -> jumpi($switchI_caseJ, eq($switchI_caseValue, caseVal))
}
if default block is there: ->
{ defaultBlock jump($switchI_finish) }
for each of cases match {
case caseVal: { body } -> $switchI_caseJ: { body jump($switchI_finish) }
}
$switchI_finish:
}
FunctionalExpression( identifier(argument1, argument2, ..., argumentn) ) ->
{
if identifier is function <name> with num1 arguments and num2 return caseValues ->
{
// find I such that $funcallI_* is non-existent
$funcallI_returnurn argumentn ... argument2 argument1 jump(<name>)
pop (num1 + 1 times)
if the context of the current contract is `let (id1, ..., idm) := f(...)` ->
let id1 := 0 ... let idm := 0
$funcallI_returnurn:
else ->
0 (num2 times)
$funcallI_returnurn:
functional expression which would lead to the function call
gets turned into a statement stream
}
else -> desugar(node's children)
}
default node ->
desugar(node's children)
}