grammar ABC::PAST::Grammar is TGE::Grammar;

transform past (ROOT) :language('PIR') {
    node = node['program']
    .local pmc past
    past = new 'PAST::Block'
    past.'init'('node'=>node, 'name'=>'anon')
    .local pmc cnode, cpast
    cnode = node['statement_list']
    cpast = tree.'get'('past', cnode, 'ABC::Grammar::statement_list')
    past.'push'(cpast)
    .return (past)
}


transform past (ABC::Grammar::statement) :language('PIR') {
  if_statement:
    $P0 = node['if_statement']
    if null $P0 goto while_statement
    .return tree.'get'('past', $P0, 'ABC::Grammar::if_statement')
  while_statement:
    $P0 = node['while_statement']
    if null $P0 goto compound_statement
    .return tree.'get'('past', $P0, 'ABC::Grammar::while_statement')
  compound_statement:
    $P0 = node['compound_statement']
    if null $P0 goto for_statement
    $P0 = $P0['statement_list']
    .return tree.'get'('past', $P0, 'ABC::Grammar::statement_list')
  for_statement:
    $P0 = node['for_statement']
    if null $P0 goto expression
    .return tree.'get'('past', $P0, 'ABC::Grammar::for_statement')
  expression:
    $P0 = node['expression']
    if null $P0 goto handle_string
    .local pmc past
    past = tree.'get'('past', $P0, 'ABC::Grammar::expression')
    ##   if the statement isn't an assignment, we assign to last and
    ##   print the resulting number
    $I0 = isa past, 'PAST::Op'
    if $I0 == 0 goto say_result
    $S0 = past.'pasttype'()
    if $S0 == 'assign' goto end
  say_result:
    $P0 = past.'new'('PAST::Var', 'name'=>'last', 'islvalue'=>1)
    past = past.'new'('PAST::Op', $P0, past, 'pasttype'=>'assign', 'islvalue'=>1)
    past = past.'new'('PAST::Op', past, 'name'=>'saynum')
    goto end
  handle_string:
    $P0 = node['string']
    .local string val
    val = $P0
    .local pmc code
    code = new 'PGE::CodeString'
    ( val ) = code.'escape'( val )
    .local pmc vpast
    vpast = new 'PAST::Val'
    vpast.init( 'name' => val, 'vtype' => '.Undef' )
    past = new 'PAST::Op'
    past.'init'(vpast, 'node'=> $P0, 'pirop'=>'print')
  end:
    .return (past)
}


transform past (ABC::Grammar::if_statement) :language('PIR') {
    .local pmc exprnode, thennode, elsenode
    exprnode = node['expression']
    $P0 = node['statement']
    thennode = $P0[0]
    elsenode = $P0[1]

    .local pmc past
    past = new 'PAST::Op'
    past.'init'('node'=>node, 'pasttype'=>'if')
    .local pmc exprpast, thenpast, elsepast
    exprpast = tree.'get'('past', exprnode, 'ABC::Grammar::expression')
    past.'push'(exprpast)
    thenpast = tree.'get'('past', thennode, 'ABC::Grammar::statement')
    past.'push'(thenpast)
    $I0 = defined elsenode
    if $I0 == 0 goto done_else
    elsepast = tree.'get'('past', elsenode, 'ABC::Grammar::statement')
    past.'push'(elsepast)
  done_else:
    .return (past)
}


transform past (ABC::Grammar::while_statement) :language('PIR') {
    .local pmc exprnode, stmtnode
    exprnode = node['expression']
    stmtnode = node['statement']

    .local pmc past, exprpast, stmtpast
    past = new 'PAST::Op'
    past.'init'('node'=>node, 'pasttype'=>'while')
    exprpast = tree.'get'('past', exprnode, 'ABC::Grammar::expression')
    past.'push'(exprpast)
    stmtpast = tree.'get'('past', stmtnode, 'ABC::Grammar::statement')
    past.'push'(stmtpast)
    .return (past)
}

# the for statement is build using the while pasttype
# according to the rule:
# for ( A ; B ; C ) { D } => A; while ( B ) { D; C; }
transform past (ABC::Grammar::for_statement) :language('PIR') {
    .local pmc expr1node, expr2node, expr3node, stmtnode
    $P0 = node['expression']
    expr1node = $P0[0]
    expr2node = $P0[1]
    expr3node = $P0[2]
    stmtnode = node['statement']

    .local pmc bpast, wpast, past, expr1past, expr2past, expr3past, stmtpast

    # build node for stmt+iterator
    bpast = new 'PAST::Stmts'
    bpast.'init'('node'=>node)
    stmtpast = tree.'get'('past', stmtnode, 'ABC::Grammar::statement')
    bpast.'push'(stmtpast)
    expr3past = tree.'get'('past', expr3node, 'ABC::Grammar::expression')
    bpast.'push'(expr3past)

    # build node for looping
    wpast = new 'PAST::Op'
    wpast.'init'('node'=>node, 'pasttype'=>'while')
    expr2past = tree.'get'('past', expr2node, 'ABC::Grammar::expression')
    wpast.'push'(expr2past)
    wpast.'push'(bpast)

    # build node for 'for' statement
    past = new 'PAST::Stmts'
    past.'init'('node'=>node)
    expr1past = tree.'get'('past', expr1node, 'ABC::Grammar::expression')
    past.'push'(expr1past)
    past.'push'(wpast)

    .return (past)
}


transform past (ABC::Grammar::statement_list) :language('PIR') {
    .local pmc past
    past = new 'PAST::Stmts'
    past.'init'('node'=>node)

    .local pmc iter
    $P0 = node['statement']
    if null $P0 goto iter_end
    iter = new .Iterator, $P0
  iter_loop:
    unless iter goto iter_end
    .local pmc cnode, cpast
    cnode = shift iter
    cpast = tree.'get'('past', cnode, 'ABC::Grammar::statement')
    past.'push'(cpast)
    goto iter_loop
  iter_end:
    .return (past)
}


transform past (ABC::Grammar::expression) :language('PIR') {
    $P0 = node['expr']
    .return tree.'get'('past', $P0, 'ABC::Grammar::expr')
}


transform past (ABC::Grammar::expr) :language('PIR') {
    .local string type
    type = node['type']
    if type == 'term:' goto past_term

    .local pmc optable, optok
    .local string pasttype, pirop, returns
    .local int islvalue
    optable = get_hll_global [ 'ABC::Grammar' ], '$optable'
    optok = optable[type]
    pasttype = optok['past']
    pirop = optok['pirop']
    returns = optok['returns']
    islvalue = optok['lvalue']

    .local pmc past, iter
    past = new 'PAST::Op'
    past.'init'('node'=>node, 'name'=>type, 'pasttype'=>pasttype, 'pirop'=>pirop, 'returns'=>returns)

    $P0 = node.'get_array'()
    if null $P0 goto iter_end
    iter = new .Iterator, $P0
    unless iter goto iter_end
    $P0[0;'islvalue'] = islvalue
  iter_loop:
    .local pmc cnode, cpast
    cnode = shift iter
    cpast = tree.'get'('past', cnode, 'ABC::Grammar::expr')
    if null cpast goto iter_loop
    past.'push'(cpast)
    if iter goto iter_loop
  iter_end:
    .return (past)

  past_term:
    .return tree.'get'('past_term', node, 'ABC::Grammar::expr')
}


transform past_term (ABC::Grammar::expr) :language('PIR') {
    .local pmc past
    $P0 = node['array']
    unless null $P0 goto term_array
    $P0 = node['call']
    unless null $P0 goto term_call
    $P0 = node['ident']
    unless null $P0 goto term_ident
    $P0 = node['float']
    unless null $P0 goto term_float

  term_integer:
    past = new 'PAST::Val'
    past.'init'('node'=>node, 'vtype'=>'.Integer', 'name'=>node, 'ctype'=>'i+')
    .return (past)

  term_float:
    past = new 'PAST::Val'
    past.'init'('node'=>node, 'vtype'=>'.Float', 'name'=>node, 'ctype'=>'n+')
    .return (past)

  term_ident:
    .local string name
    name = node['ident']
    .local int islvalue
    islvalue = node['islvalue']
    past = new 'PAST::Var'
    past.'init'('node'=>node, 'name'=>name, 'viviself'=>'.Integer', 'islvalue'=>islvalue)
    .return (past)

  term_array:
    .local string name
    name = node['ident']
    name = concat name, '_array'
    .local int islvalue
    islvalue = node['islvalue']
    .local pmc exprnode, exprpast, basepast
    exprnode = node['expression'; 0]
    exprpast = tree.'get'('past', exprnode, 'ABC::Grammar::expression')
    basepast = exprpast.'new'('PAST::Var', 'node'=>node, 'name'=>name)
    past = exprpast.'new'('PAST::Var', basepast, exprpast, 'node'=>node, 'scope'=>'keyed', 'viviself'=>'.Integer', 'islvalue'=>islvalue)
    unless islvalue goto term_array_end
    basepast.'islvalue'(islvalue)
    basepast.'viviself'('.ResizablePMCArray')
  term_array_end:
    .return (past)

  term_call:
    .local pmc exprnode, exprpast
    name = node['ident']
    exprnode = node['expression'; 0]
    exprpast = tree.'get'('past', exprnode, 'ABC::Grammar::expression')
    past = exprpast.'new'('PAST::Op', exprpast, 'node'=>node, 'name'=>name, 'pasttype'=>'call')
    .return (past)
}

