=head1 NAME

PIRGrammar -- A grammar for transforming an opcode syntax tree to PIR.

=head1 SYNOPSYS

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

      # Build the PIR output
      .local pmc pirbuilder
      pirbuilder = grammar.apply(match)
      .local pmc pir
      pir = pirbuilder.get('result')

      end
  .end

=head1 DESCRIPTION


=cut

grammar Cardinal::PIRGrammar is TGE::Grammar;

transform root (Cardinal::POST::Ops) :language('PIR') {
    .local pmc code
    $P0 = tree.get('pir', node)
    .return ($P0)
}

transform pir (Cardinal::POST::Op) :language('PIR') {
    $P0 = node.'pir'(self)
    .return ($P0)
}

transform pir (Cardinal::POST::NOP) :language('PIR') {
    .return ('')
}

transform pir (Cardinal::POST::Label) :language('PIR') {
    .local string code
    .local string value
    value = node.'value'()
    code = '  '
    code .= value
    code .= ":\n"
    .return (code)
}

transform pir (Cardinal::POST::Var) :language('PIR') {
    .local string name
    .local string scope
    .local string value
    .local pmc code
    .local pmc block
    .local int islvalue
    name = node.'name'()
    scope = node.'scope'()
    value = node.'value'()
    islvalue = node.'islvalue'()
    block = self.'top_scope_stack'()
    code = new 'PGE::CodeString'

    if scope == 'lexical' goto generate_lexical
    if scope == 'parameter' goto generate_parameter
    if scope == 'global' goto generate_global
    if scope == 'instance' goto generate_instance
    if scope == 'class' goto generate_class
    goto generate_find

  generate_parameter:
    .local pmc prologue
    .local string pname
    pname = node.'paramname'()
    prologue = block.'prologue'()
    prologue.'emit'("    .param pmc %0", pname)
    code.'emit'("    .lex '%0', %1", name, value)
    code.'emit'("    %0 = %1", value, pname)
    goto end

  generate_lexical:
    code.'emit'("    .lex '%0', %1", name, value)
    goto end
  generate_global:
    if islvalue goto end
    code.'emit'("    %0 = get_hll_global '%1'", value, name)
    goto end
  generate_find:
    if islvalue goto end
    code.'emit'("    %0 = find_name '%1'", value, name)
    goto end
  generate_instance:
    if islvalue goto end
    code.'emit'("    %0 = getattribute self, '%1'", value, name)
    goto end
  generate_class:
    if islvalue goto end
    code.'emit'("    %0 = self.'_get_class_var'('%1')", value, name)
    goto end
  end:
    .return (code)
}

transform pir (Cardinal::POST::Ops) :language('PIR') {
    .local pmc code
    .local pmc iter

    code = new 'PGE::CodeString'
    iter = node.'child_iter'()
  iter_loop:
    unless iter goto iter_end
    $P0 = shift iter
    $P1 = tree.'get'('pir', $P0)
    code .= $P1
    goto iter_loop
  iter_end:
    .return (code)
}

transform pir (Cardinal::POST::Assign) :language('PIR') {
    .local pmc lnode
    .local pmc rnode
    .local pmc rvalue
    lnode = node[0]
    rnode = node[1]
    
    .local pmc name, value, scope, xvalue, code, varhash, block
    name = lnode.'name'()
    value = lnode.'value'()
    scope = lnode.'scope'()
    rvalue = rnode.'value'()
    code = new 'PGE::CodeString'
    block = self.'top_scope_stack'()
    varhash = block.'varhash'()
    $I0 = exists varhash[name]
    if $I0 goto with_varhash_name
    varhash[name] = lnode
  with_varhash_name:
    if scope == 'outerpackage' goto store_package
    if scope == 'package' goto store_package
    if scope == 'global' goto store_package
    if scope == 'instance' goto store_instance
    if scope == 'class' goto store_class
  store_lexical:
    code.'emit'("    store_lex '%0', %1", name, rvalue)
    .return (code)
  store_package:
    code.'emit'("    set_hll_global '%0', %1", name, rvalue)
    .return (code)
  store_instance:
    code.'emit'("    self.'_store_instance_var'('%0', %1) ", name, rvalue)
    .return (code)
  store_class:
    code.'emit'("    self.'_store_class_var'('%0', %1)", name, rvalue)
    .return (code)
}

transform pir (Cardinal::POST::Call) :language('PIR') {
    .local pmc code
    .local string sub_name
    .local string args
    sub_name = node.'name'()
    args = ""
    code = new 'PGE::CodeString'
    code.'emit'("    '%0'(%1)", sub_name, args)
    .return (code)
}

transform pir (Cardinal::POST::Raw) :language('PIR') {
    .local pmc code
    $P1 = node.'raw'()
    code = new 'PGE::CodeString'
    code.'emit'("%0", $P1)
    .return (code)
    }

transform pir (Cardinal::POST::Namespace) :language('PIR') {
    .local pmc code
    .local pmc iter

    code = new 'PGE::CodeString'
    code .= "\n.namespace [ "
    $S0 = node.'get_pir_name'()
    code .= $S0
    code .= " ]\n"

    iter = node.'child_iter'()
  iter_loop:
    unless iter goto iter_end
    $P0 = shift iter
    $P1 = tree.'get'('pir', $P0)
    code .= $P1
    goto iter_loop
  iter_end:

    .return (code)
}

transform pir (Cardinal::POST::NamespaceLookup) :language('PIR') {
    $P0 = node.'pir'(self)
    .return ($P0)
}

transform pir (Cardinal::POST::Sub) :language('PIR') {
    .local pmc prologue
    .local pmc varhash
    prologue = new 'PGE::CodeString'
    node.'prologue'(prologue)
    varhash = new .Hash
    node.'varhash'(varhash)

    .local string name
    .local string outerattr
    .local pmc outer
    name = node.'name'()
    outer = node.'outer'()
    outerattr = ''
    $I0 = defined outer
    unless $I0 goto with_outerattr
    outerattr = outer.'name'()
    eq outerattr, '', with_outerattr
    outerattr = concat ":outer('", outerattr
    outerattr = concat outerattr, "')"
  with_outerattr:

    .local string adverbs
    adverbs = node.'adverbs'()
    prologue.'emit'("\n.sub '%0' %1 %2", name, outerattr, adverbs)
    
    .local pmc subcode_parts
    .local pmc iter
    subcode_parts = new 'PGE::CodeString'
    iter = node.'child_iter'()

    self.'push_scope_stack'(node)
  iter_loop:
    unless iter goto iter_end
    $P0 = shift iter
    $P1 = tree.'get'('pir', $P0)
    subcode_parts .= $P1
    goto iter_loop
  iter_end:
    self.'pop_scope_stack'()

    .local string value
    value = node.'value'()
    prologue = node.'prologue'()

    .local pmc subcode
    subcode = new 'PGE::CodeString'
    subcode .= prologue
    subcode .= subcode_parts
    subcode.'emit'("    .return (%0)\n.end\n", value)
    
    .return (subcode)
}

=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
