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)
}