=head1 NAME

OSTGrammar -- A grammar for transforming an abstract syntax tree to an
opcode syntax tree.

=head1 SYNOPSYS

  .sub _main :main
      load_bytecode 'OSTGrammar.pir'
      .local pmc grammar
       grammar = new 'OSTGrammar'

      # Construct the "OST"
      load_bytecode "languages/cardinal/src/POST.pir"
      .local pmc ostbuilder
      ostbuilder = grammar.apply(match)
      .local pmc ost
      ost = ostbuilder.get('result')

      end
  .end

=head1 DESCRIPTION


=cut

grammar Cardinal::OSTGrammar is TGE::Grammar;

transform root (ROOT) :language('PIR') {
    .local pmc ops
    .local pmc post
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local pmc subcollector
    subcollector = new 'Cardinal::POST::Sub'
    subcollector.init('node'=>node)
    self.'post_scope_stack'(subcollector)
    $P0 = new .Undef
    self.'past_scope_stack'($P0)

#hll statement
    .local pmc dumper
    dumper = new 'Cardinal::POST::Raw'
    dumper.'init'('node'=>node, 'raw'=>".include 'library/dumper.pir'")
    .local pmc hll
    hll = new 'Cardinal::POST::Raw'
    hll.'init'('node'=>node, 'raw'=>".HLL 'Ruby', 'ruby_group'")

#__onload
    .local pmc load
    load = new 'Cardinal::POST::Sub'
    load.'init'('node'=>node, 'name'=>'__onload', 'adverbs'=>':load')

#traverse AST
    post = tree.'get'('post', node)

#BEGIN BLOCKS
    .local pmc BEGIN_blocks
    BEGIN_blocks = new 'Cardinal::POST::Ops'
    BEGIN_blocks.'init'('node'=>node)
    .local pmc iter
    .local pmc blocks 
    blocks = self.'push_BEGIN_block'()
    iter = new .Iterator, blocks
  iter_loop:
    unless iter, iter_end
      shift $P1, iter
      BEGIN_blocks.'add_child'($P1)
      goto iter_loop
  iter_end:

#END BLOCKS
    .local pmc END_blocks
    END_blocks = new 'Cardinal::POST::Ops'
    END_blocks.'init'('node'=>node)
    blocks = self.'push_END_block'()
    iter = new .Iterator, blocks
    set iter, .ITERATE_FROM_END
  iter_loop1:
    unless iter, iter_end1
      pop $P1, iter
      END_blocks.'add_child'($P1)
      goto iter_loop1
  iter_end1:

#build main
    .local pmc main
    main = new 'Cardinal::POST::Sub'
    main.'init'('node'=>node, 'name'=>'main', 'adverbs'=>':main')

    .local pmc call_op
    $S0 = node.'name'()

    call_op = new 'Cardinal::POST::Call'
    call_op.'init'('node'=>node, 'name'=>$S0)

    main.'add_child'(BEGIN_blocks)
    .local pmc includes
    includes = new 'Cardinal::POST::Op'
    includes.'init'("'languages/cardinal/src/builtins_gen.pir'", 'node'=>node, 'name'=>'load_bytecode')
    main.'add_child'(includes)
    includes = new 'Cardinal::POST::Op'
    includes.'init'("'languages/cardinal/runtime/cardinallib.pbc'", 'node'=>node, 'name'=>'load_bytecode')
    main.'add_child'(includes)
    main.'add_child'(call_op)
    main.'add_child'(END_blocks)

#top level subs
    .local pmc subs
    subs = subcollector.'subs'()

#namespaces/classes
    .local pmc namespaces
    namespaces = self.'push_namespace'()
   
#build up top level ops 
    #ops.'add_child'(dumper)
    ops.'add_child'(hll)
    ops.'add_child'(main)
    ops.'add_child'(load)
    ops.'append_children'(subs)
    ops.'append_children'(namespaces)
    .return (ops)
}

transform post (Cardinal::PAST::Sub) :language('PIR') {
    .local string name, blocktype
    name = node.'name'()
    blocktype = node.'blocktype'()
    if name > '' goto with_name
    name = concat '_', blocktype
    name = node.'unique'(name)
  with_name:
    .local pmc outerpost, outerpast

    .local pmc post
    post = new 'Cardinal::POST::Sub'
    post.'init'('node'=>node, 'name'=>name, 'subtype'=>blocktype)

    .local pmc iter
    iter = node.'child_iter'()
  iter_loop:
    unless iter goto iter_end
    .local pmc cpast, cpost
    cpast = shift iter
    cpost = tree.'get'('post', cpast)
    post.'add_child'(cpost)
    goto iter_loop
  iter_end:

    .local pmc value
    value = cpost.'value'()
    value = clone value
    post.'value'(value)
    
    .return (post)
}

transform post (Cardinal::PAST::Block) :language('PIR') {
    .local string name
    .local string blocktype
    name = node.'name'()

    blocktype = node.'blocktype'()
    if name > '' goto with_name
    name = concat '_', blocktype
    name = node.'unique'(name)
  with_name:

    .local string adverbs
    adverbs = ''
    ne blocktype, 'method', not_method
    adverbs = ':method'
  not_method:

    .local pmc outerpost, outerpast
    outerpost = self.'post_scope_stack'()
    outerpast = self.'past_scope_stack'()

    .local pmc post
    post = new 'Cardinal::POST::Sub'
    post.'init'('node'=>node, 'name'=>name, 'outer'=>outerpost, 'subtype'=>blocktype, 'adverbs'=>adverbs)
    
    self.'post_scope_stack'(post)
    self.'past_scope_stack'(node)

    .local pmc iter
    iter = node.'child_iter'()
  iter_loop:
    unless iter goto iter_end
    .local pmc cpast, cpost
    cpast = shift iter
    cpost = tree.'get'('post', cpast)
    post.'add_child'(cpost)
    goto iter_loop
  iter_end:

    .local pmc value
    value = cpost.'value'()
    value = clone value
    post.'value'(value)

    self.'post_scope_stack'(outerpost)
    self.'past_scope_stack'(outerpast)

    outerpost.'push_sub'(post)
    $P0 = post.'subs'()
    outerpost.'append_subs'($P0)
    
    .local pmc call_op
    call_op = new 'Cardinal::POST::Call'
    call_op.'init'('node'=>node, 'name'=>name)

    unless blocktype == 'BEGIN' goto not_begin
    self.'push_BEGIN_block'(call_op)
  not_begin:
    unless blocktype == 'END' goto begin
    self.'push_END_block'(call_op)
  begin:
    if blocktype == 'begin' goto call_block
    if blocktype == 'immediate' goto call_block
    goto end
    
  call_block:
    .return(call_op)
  end:
    $P0 = new 'Cardinal::POST::NOP'
    $P0.'init'('node'=>node)
    .return ($P0)
}

transform post (Cardinal::PAST::Class) :language('PIR') {
    .local pmc classpath
    .local pmc namespace
    .local pmc ops

    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    classpath = node.'class_path'()
    $P0 = classpath.'children'()

    namespace = new 'Cardinal::POST::Namespace'
    namespace.'init'('node'=>node, 'name'=>$P0)
    self.'push_namespace'(namespace)
    
    .local string class_name
    .local string classbodyname
    .local string blocktype
    class_name = classpath.'class_name'()

    blocktype = node.'blocktype'()
    classbodyname .= class_name
    classbodyname .= '_body'

    .local pmc outerpost, outerpast
    outerpost = self.'post_scope_stack'()
    outerpast = self.'past_scope_stack'()

    .local pmc post
    post = new 'Cardinal::POST::Sub'
    post.'init'('node'=>node, 'name'=>classbodyname, 'outer'=>outerpost, 'subtype'=>'class_body')
    
    self.'post_scope_stack'(post)
    self.'past_scope_stack'(node)

    #register new class in parent namespace
    .local pmc getclass_op
    .local pmc subclass_op
    .local pmc set_hll_global_op
    getclass_op = new 'Cardinal::POST::Op'
    getclass_op.'init'(getclass_op, "'RubyClass'", 'node'=>node, 'name'=>'getclass')
    post.'add_child'(getclass_op)
    $S0 = concat "'", class_name
    $S0 .= "'"
    subclass_op = new 'Cardinal::POST::Op'
    subclass_op.'init'(subclass_op, getclass_op, $S0, 'node'=>node, 'name'=>'subclass')
    post.'add_child'(subclass_op)

    set_hll_global_op = new 'Cardinal::POST::Op'
    set_hll_global_op.'init'($S0, subclass_op, 'node'=>node, 'name'=>'set_hll_global')
    post.'add_child'(set_hll_global_op)

    .local pmc iter
    iter = node.'child_iter'()
  iter_loop:
    unless iter goto iter_end
    .local pmc cpast, cpost
    cpast = shift iter
    cpost = tree.'get'('post', cpast)
    post.'add_child'(cpost)
    goto iter_loop
  iter_end:

    .local pmc value
    value = cpost.'value'()
    value = clone value
    post.'value'(value)

    self.'post_scope_stack'(outerpost)
    self.'past_scope_stack'(outerpast)
    
    .local pmc body_call_ops
    body_call_ops = new 'Cardinal::POST::Ops'
    body_call_ops.'init'('node'=>node)
    $P0 = new 'Cardinal::POST::NamespaceLookup'
    $P0 .'init'('node'=>node, 'namespace'=>namespace, 'item'=>classbodyname)
    $P1 = $P0.'value'()
    body_call_ops.'add_child'($P0)
    $P0 = new 'Cardinal::POST::Op'
    $S0 = $P1
    $S0 .= "()"
    $P0 .'init'('node'=>node, 'name'=>$S0)
    body_call_ops.'add_child'($P0)

    namespace.'add_child'(post)
    $P0 = post.'subs'()
    namespace.'append_children'($P0)
    .return (body_call_ops)
}

transform post (Cardinal::PAST::Stmts) :language('PIR') {
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local pmc iter
    iter = node.'child_iter'()
  iter_loop:
    unless iter, iter_end         # while (entries) ...
    $P0 = shift iter
    $P1 = tree.get('post', $P0)
    ops.'add_child'($P1)
    goto iter_loop
  iter_end:
    $P1 = $P1.'value'()
    ops.'value'($P1)
    .return (ops)
}

transform post (Cardinal::PAST::Rescue_Stmt) :language('PIR') {
    .local pmc op
    .local pmc ops
    .local pmc handlerlabel, posthandlerlabel

    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    handlerlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'exception_handler')
    posthandlerlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'post_exception_handler')

    op = new 'Cardinal::POST::Op'
    op.'init'('node'=>node, 'name'=>'push_eh')
    op.'add_child'(handlerlabel)
    ops.'add_child'(op)
    
    $P0 = node.'try_stmt'()
    $P0 = tree.get('post', $P0)
    ops.'add_child'($P0)
    
    op = new 'Cardinal::POST::Op'
    op.'init'('node'=>node, 'name'=>'clear_eh')
    ops.'add_child'(op)
    
    op = new 'Cardinal::POST::Op'
    op.'init'('node'=>node, 'name'=>'goto')
    op.'add_child'(posthandlerlabel)
    ops.'add_child'(op)
    
    ops.'add_child'(handlerlabel)
    $P0 = node.'rescue_stmt'()
    $P0 = tree.get('post', $P0)
    ops.'add_child'($P0)
    ops.'add_child'(posthandlerlabel)

    .return (ops)
}

transform post (Cardinal::PAST::Stmt) :language('PIR') {
    .local pmc past
    .local pmc post
    past = node[0]
    post = tree.get('post', past)
    .return (post)
}

transform post (Cardinal::PAST::Exp) :language('PIR') {
    .local pmc past
    .local pmc post
    past = node[0]
    post = tree.get('post', past)
    .return (post)
}

transform post (Cardinal::PAST::Op) :language('PIR') {
    .local string opname
    .local string pasttype
    .local pmc optable
    .local pmc optoken
    
    opname = node.'name'()
    #optable = get_hll_global [ 'Cardinal'; 'Grammar' ], '$optable'
    optable = get_root_global [ 'parrot'; 'Cardinal::Grammar' ], '$optable'
    optoken = optable[opname]
    if_null optoken, no_optoken
    unless optoken goto no_optoken
    pasttype = optoken['pasttype']
  no_optoken:
    if pasttype > '' goto dispatch_post
    pasttype = 'simple'
  dispatch_post:
    .return tree.get(pasttype, node)
}

transform postname (Cardinal::PAST::Op) :language('PIR') {
    .local string opname
    .local string postname
    .local pmc optable
    .local pmc optoken
    
    opname = node.'name'()
    #optable = get_hll_global [ 'Cardinal'; 'Grammar' ], '$optable'
    optable = get_root_global [ 'parrot'; 'Cardinal::Grammar' ], '$optable'
    optoken = optable[opname]
  
    if_null optoken, no_optoken
    unless optoken goto no_optoken
    postname = optoken['post']
  no_optoken:
    if postname > '' goto end
    postname = concat "'", opname 
    postname .= "'"
  end:
    .return (postname)
}

transform simple (Cardinal::PAST::Op) :language('PIR') {
    .local pmc ops
    .local string opname
    .local string postname
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)
    opname = node.'name'()
    postname = tree.'get'('postname', node)

    .local pmc iter
    .local pmc arglist
    iter = node.'child_iter'()
    arglist = new .ResizablePMCArray

  iter_loop:
    unless iter goto iter_end
    .local pmc past
    .local pmc post
    past = shift iter
    $I0 = defined past
    unless $I0 goto iter_loop
    post = tree.'get'('post', past)
    ops.'add_child'(post)
    push arglist, post
    goto iter_loop

  iter_end:

    .local pmc optable
    .local pmc optoken
    .local string opreturn

    #optable = get_hll_global [ 'Cardinal'; 'Grammar' ], '$optable'
    optable = get_root_global [ 'parrot'; 'Cardinal::Grammar' ], '$optable'
    optoken = optable[opname]
    if_null optoken, without_opreturn
    unless optoken goto without_opreturn
    opreturn = optoken['returns']

    #$P0 = get_hll_global ['Cardinal'], 'CardinalParrotClassMap'
    $P0 = get_root_global ['parrot'; 'Cardinal'], 'CardinalParrotClassMap'
    unless $P0 goto without_opreturn
    opreturn = $P0[opreturn]
    if_null optoken, without_opreturn
    unless opreturn goto without_opreturn
  without_opreturn:
    opreturn = '.Undef'
  with_opreturn:
    ops.'add_child_new'('Cardinal::POST::Op', ops, opreturn, 'name'=>'new')
    ops.'add_child_new'('Cardinal::POST::Op', ops, arglist :flat, 'name'=>postname)
    .return (ops)
}

transform assign (Cardinal::PAST::Op) :language('PIR') {
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local pmc iter, lpast, rpast
    .local pmc lpost, rpost

    iter = node.'child_iter'()
    lpast = shift iter
    rpast = shift iter
    lpost = tree.'get'('post', lpast)
    lpost.'islvalue'(1)
    rpost = tree.'get'('post', rpast)
    ops.'add_child'(lpost)
    ops.'add_child'(rpost)
    ops.'add_child_new'('Cardinal::POST::Assign', lpost, rpost, 'name'=>'assign')

    #return value 
    .local string value
    value = rpost.'value'()
    ops.'value'(value)
    .return (ops)
}

transform cond (Cardinal::PAST::Op) :language('PIR') {
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local pmc exprpast, thenpast, elsepast
    .local pmc exprpost, thenpost, elsepost
    exprpast = node[0]
    thenpast = node[1]
    elsepast = node[2]

    .local pmc thenlabel, endlabel
    thenlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'if_then')
    endlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'if_end')

    exprpost = tree.'get'('post', exprpast)
    ops.'add_child'(exprpost)
    ops.'add_child_new'('Cardinal::POST::Op', exprpost, thenlabel, 'name'=>'if')
    
    elsepost = exprpost
    $I0 = defined elsepast
    unless $I0 goto cond_no_else
    elsepost = tree.'get'('post', elsepast)
    ops.'add_child'(elsepost)
  cond_no_else:
    ops.'add_child_new'('Cardinal::POST::Op', ops, elsepost, 'name'=>'set')
    ops.'add_child_new'('Cardinal::POST::Op', endlabel, 'name'=>'goto')
    ops.'add_child'(thenlabel)

    thenpost = exprpost
    $I0 = defined thenpast
    unless $I0 goto cond_no_then
    thenpost = tree.'get'('post', thenpast)
    ops.'add_child'(thenpost)
  cond_no_then:
    ops.'add_child_new'('Cardinal::POST::Op', ops, thenpost, 'name'=>'set')
    ops.'add_child'(endlabel)
    .return (ops)
}

transform loop (Cardinal::PAST::Op) :language('PIR') {
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local string opname
    .local string newopname
    opname = node.'name'()
    newopname = 'unless'
    unless opname == 'until' goto its_a_while
    newopname = 'if'
    its_a_while:

    .local pmc exprpast, bodypast
    .local pmc exprpost, bodypost
    exprpast = node[0]
    bodypast = node[1]

    .local pmc looplabel, loopendlabel
    looplabel = ops.'new'('Cardinal::POST::Label', 'name'=>'loop')
    loopendlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'loop_end')

    ops.'add_child'(looplabel)
    exprpost = tree.'get'('post', exprpast)
    ops.'add_child'(exprpost)
    ops.'add_child_new'('Cardinal::POST::Op', exprpost, loopendlabel, 'name'=>newopname)

    bodypost = tree.'get'('post', bodypast)
    ops.'add_child'(bodypost)
    ops.'add_child_new'('Cardinal::POST::Op', looplabel, 'name'=>'goto')
    ops.'add_child'(loopendlabel)
    .return (ops)
}

transform post (Cardinal::PAST::WhileUntil) :language('PIR') {
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local string opname
    .local string newopname
    opname = node.'name'()
    newopname = 'unless'
    unless opname == 'until' goto its_a_while
    newopname = 'if'
    its_a_while:

    .local pmc testpast, bodypast
    .local pmc testpost, bodypost
    testpast = node[0]
    bodypast = node[1]

    .local pmc looplabel, loopendlabel
    looplabel = ops.'new'('Cardinal::POST::Label', 'name'=>'loop')
    loopendlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'loop_end')

    ops.'add_child'(looplabel)
    testpost = tree.'get'('post', testpast)
    ops.'add_child'(testpost)
    ops.'add_child_new'('Cardinal::POST::Op', testpost, loopendlabel, 'name'=>newopname)

    bodypost = tree.'get'('post', bodypast)
    ops.'add_child'(bodypost)
    ops.'add_child_new'('Cardinal::POST::Op', looplabel, 'name'=>'goto')
    ops.'add_child'(loopendlabel)
    .return (ops)
}

transform post (Cardinal::PAST::For) :language('PIR') {
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local pmc varpast, expressionpast, bodypast
    .local pmc varpost, expressionpost, bodypost
    varpast = node[0]
    expressionpast = node[1]
    bodypast = node[2]

    .local pmc looplabel, loopendlabel
    looplabel = ops.'new'('Cardinal::POST::Label', 'name'=>'loop')
    loopendlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'loop_end')
    
    varpost = tree.'get'('post', varpast)
    varpost.'islvalue'(1)

    $P0 = node.'unique'('iter')
    $S0 = $P0
    $S0 = concat '    .local pmc ', $S0
    .local pmc itervar
    itervar = new 'Cardinal::POST::Raw'
    itervar.'init'('node'=>node, 'raw'=>$S0)
    ops.'add_child'(itervar)

    expressionpost = tree.'get'('post', expressionpast)
    ops.'add_child'(expressionpost)
    $P1 = expressionpost.'value'()
    ops.'add_child_new'('Cardinal::POST::Op', $P0, '.Iterator', $P1, 'name'=>'new')
    ops.'add_child_new'('Cardinal::POST::Op', $P0, '0', 'name'=>'set')

    ops.'add_child'(looplabel)
    ops.'add_child_new'('Cardinal::POST::Op', $P0, loopendlabel, 'name'=>'unless')
    ops.'add_child'(varpost)
    ops.'add_child_new'('Cardinal::POST::Op', varpost, $P0, 'name'=>'shift')

    bodypost = tree.'get'('post', bodypast)
    ops.'add_child'(bodypost)
    ops.'add_child_new'('Cardinal::POST::Op', looplabel, 'name'=>'goto')
    ops.'add_child'(loopendlabel)
    .return (ops)
}

transform xor (Cardinal::PAST::Op) :language('PIR') {
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local pmc endlabel, falselabel
    falselabel = ops.'new'('Cardinal::POST::Label', 'name'=>'xor_false')
    endlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'xor_end')

    .local pmc iter, apast, apost, i, t, u
    i = ops.unique('$I')
    t = ops.unique('$I')
    u = ops.unique('$I')
    iter = node.'child_iter'()
    apast = shift iter
    apost = tree.'get'('post', apast)
    ops.'add_child'(apost)
    ops.'add_child_new'('Cardinal::POST::Op', ops, apost, 'name'=>'set')
    ops.'add_child_new'('Cardinal::POST::Op', t, apost, 'name'=>'istrue')
  inner_child:
    .local pmc bpast, bpost
    bpast = shift iter
    bpost = tree.'get'('post', bpast)
    ops.'add_child'(bpost)
    ops.'add_child_new'('Cardinal::POST::Op', u, bpost, 'name'=>'istrue')
    ops.'add_child_new'('Cardinal::POST::Op', i, t, u, 'name'=>'and')
    ops.'add_child_new'('Cardinal::POST::Op', i, falselabel, 'name'=>'if')
    unless iter goto last_child
    .local pmc s
    s = ops.'new'('Cardinal::POST::Label', 'name'=>'xor_skip')
    ops.'add_child_new'('Cardinal::POST::Op', t, s, 'name'=>'if')
    ops.'add_child_new'('Cardinal::POST::Op', ops, bpost, 'name'=>'set')
    ops.'add_child_new'('Cardinal::POST::Op', t, u, 'name'=>'set')
    ops.'add_child'(s)
    goto inner_child
  last_child:
    ops.'add_child_new'('Cardinal::POST::Op', t, endlabel, 'name'=>'if')
    ops.'add_child_new'('Cardinal::POST::Op', ops, bpost, 'name'=>'set')
    ops.'add_child_new'('Cardinal::POST::Op', endlabel, 'name'=>'goto')
    ops.'add_child'(falselabel)
    ops.'add_child_new'('Cardinal::POST::Op', ops, '.Undef', 'name'=>'new')
    ops.'add_child'(endlabel)
    .return (ops)
}


transform chain (Cardinal::PAST::Op) :language('PIR') {
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)

    .local string opname, pasttype
    .local pmc optable, optok
    #optable = get_hll_global [ 'Cardinal'; 'Grammar' ], '$optable'
    optable = get_root_global [ 'parrot'; 'Cardinal::Grammar' ], '$optable'

    .local pmc childrenlist
    childrenlist = new .ResizablePMCArray
  chain_loop:
    $I0 = isa node, 'Cardinal::PAST::Op'
    if $I0 == 0 goto chain_end
    opname = node.'name'()
    optok = optable[opname]
    pasttype = optok['pasttype']
    if pasttype != 'chain' goto chain_end
    push childrenlist, node
    node = node[0]
    goto chain_loop
  chain_end:

    .local pmc endlabel, apast, apost
    node = pop childrenlist
    endlabel = ops.'new'('Cardinal::POST::Label', 'name'=>'chain_end')
    apast = node[0]
    apost = tree.'get'('post', apast)
    ops.'add_child'(apost)

  childrenlist_loop:
    .local pmc bpast, bpost
    .local string postname
    bpast = node[1]
    bpost = tree.'get'('post', bpast)
    postname = tree.'get'('postname', node)
    ops.'add_child'(bpost)
    ops.'add_child_new'('Cardinal::POST::Op', ops, apost, bpost, 'name'=>postname)
    unless childrenlist goto childrenlist_end
    ops.'add_child_new'('Cardinal::POST::Op', ops, endlabel, 'name'=>'unless')
    apost = bpost
    node = pop childrenlist
    goto childrenlist_loop
  childrenlist_end:
    ops.'add_child'(endlabel)
    .return (ops)
}


transform post (Cardinal::PAST::Val) :language('PIR') {
    .local string val
    .local string valtype
    .local string objtype
    val = node.'name'()
    valtype = node.'valtype'()
    unless valtype == 'String' goto n1
    #objtype = '.RubyString'
    objtype = '.String'
    goto with_objtype
    n1:
    unless valtype == 'Integer' goto n2
    #objtype = '.RubyInteger'
    objtype = '.Integer'
    goto with_val
    n2:
    unless valtype == 'Float' goto n3
    #objtype = '.RubyFloat'
    objtype = '.Float'
    goto with_val
    n3:
    objtype = '.Undef'

  with_objtype:
    val = escape val
    val = concat '"', val
    val = concat val, '"'

    #unicode check    
    $I0 = index val, '\x'
    unless $I0 > 0 goto with_val
    val = concat 'unicode:', val

  with_val:
    .local pmc ops
    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)
    ops.'add_child_new'('Cardinal::POST::Op', ops, objtype, 'name'=>'new')
    $P0 = ops.'new'('Cardinal::POST::Val', 'valtype'=>valtype, 'value'=>val)
    ops.'add_child_new'('Cardinal::POST::Op', ops, $P0, 'name'=>'assign')
    .return (ops)
}

transform post (Cardinal::PAST::Var) :language('PIR') {
    .local string name
    .local string scope
    .local pmc post
    name = node.'name'()
    scope = node.'scope'()
    post = new 'Cardinal::POST::Var'
    post.'init'('node'=>node, 'name'=>name, 'scope'=>scope)
    .return (post)
}

transform post (Cardinal::PAST::PositionalParameter) :language('PIR') {
    .local string name
    .local string type
    .local pmc post
    name = node.'name'()
    type = node.'type'()
    post = new 'Cardinal::POST::Var'
    post.'init'('node'=>node, 'name'=>name, 'scope'=>'parameter')
    .return (post)
}

transform post (Cardinal::PAST::OptionalParameter) :language('PIR') {
    .local string name
    .local pmc default_value 
    .local pmc post
    name = node.'name'()
    default_value = node.'default_value'()
    post = new 'Cardinal::POST::Var'
    post.'init'('node'=>node, 'name'=>name, 'scope'=>'parameter')
    .return (post)
}

transform post (Cardinal::PAST::RestParameter) :language('PIR') {
    .local string name
    .local pmc post
    name = node.'name'()
    post = new 'Cardinal::POST::Var'
    post.'init'('node'=>node, 'name'=>name, 'scope'=>'parameter')
    .return (post)
}

transform post (Cardinal::PAST::BlockParameter) :language('PIR') {
    .local string name
    .local pmc post
    name = node.'name'()
    post = new 'Cardinal::POST::Var'
    post.'init'('node'=>node, 'name'=>name, 'scope'=>'parameter')
    .return (post)
}

transform post (Cardinal::PAST::FunctionCall) :language('PIR') {
    .local string name
    .local pmc post
    name = node.'name'()
    post = new 'Cardinal::POST::Call'
    post.'init'('node'=>node, 'name'=>name)
    .return (post)
}

transform post (Cardinal::PAST::MethodCall) :language('PIR') {
    .local pmc obj
    .local pmc opost
    .local pmc ops
    .local pmc post
    .local pmc call


    ops = new 'Cardinal::POST::Ops'
    ops.'init'('node'=>node)
    
    obj = node[0]
    opost = tree.'get'('post', obj)
    ops.'add_child'(opost)

    $P0 = node[1]
    $S1 = $P0

    $S0 = ops.'value'()
    $S0 .= ' = '
    $S2 = opost.'value'()
    $S0 .= $S2
    $S0 .= '.'
    $S0 .= "'"
    $S0 .= $S1 
    $S0 .= "'"
    $S0 .= '()'

    call = new 'Cardinal::POST::Op'
    call.'init'('node'=>node, 'name'=>$S0)
    ops.'add_child'(call)
    .return (ops)
}

=head1 LICENSE

Copyright (C) 2006, The Perl Foundation.

This is free software; you may redistribute it and/or modify
it under the same terms as Parrot.

=head1 AUTHOR

Kevin Tew <tewk@tewk.com>

=cut
