
grammar ASTGrammar is TGE::Grammar;


# past (ROOT)
#
# Transform the 'program' rule into a PAST::Block.
#
transform past (ROOT) :language('PIR') { 
    .local pmc past
		past = new 'PAST::Block'
		#past.'init'('node'=>node)
		past.'init'('node'=>node, 'blocktype'=>'immediate', 'name'=>'anon')            
        
    .local pmc childnode, childpast
    childnode = node['program']
    childpast = tree.'get'('past', childnode, 'PIR::Grammar::program')
		past.'push'(childpast)    
    .return (past)  
    #.return (childpast)
}

# past (PIR::Grammar::program)
#
# Store each of the compilation units into a PAST::Stmts node.
#
transform past (PIR::Grammar::program) :language('PIR') {
    .local pmc past
    past = new 'PAST::Stmts'
    past.'init'('node'=>node)

    .local pmc iter
    $P0 = node['compilation_unit']
    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, 'PIR::Grammar::compilation_unit')
    past.'push'(cpast)
    goto iter_loop
  iter_end:
    .return (past)
}

# past (PIR::Grammar::compilation_unit)
#
# Call the appropiate transform rule depending on the type of compilation unit.
#
transform past (PIR::Grammar::compilation_unit) :language('PIR') {
  global_def:
    $P0 = node['global_def']
    if null $P0 goto sub_def
    .return tree.'get'('past', $P0, 'PIR::Grammar::global_def')
  sub_def:
    $P0 = node['sub_def']
    if null $P0 goto const_def
    .return tree.'get'('past', $P0, 'PIR::Grammar::sub_def')
  const_def:
    $P0 = node['const_def']
    if null $P0 goto macro_def
    .return tree.'get'('past', $P0, 'PIR::Grammar::const_def')
  macro_def:
    $P0 = node['macro_def']
    if null $P0 goto pragma
    .return tree.'get'('past', $P0, 'PIR::Grammar::macro_def')
  pragma:
  	$P0 = node['pragma']
    if null $P0 goto emit
    .return tree.'get'('past', $P0, 'PIR::Grammar::pragma')
  emit:  
    $P0 = node['emit']
    if null $P0 goto const_def
    .return tree.'get'('past', $P0, 'PIR::Grammar::emit') 
}

transform past (PIR::Grammar::global_def) :language('PIR') {

}

# past (PIR::Grammar::sub_def)
#
# Transform a sub_def into a PAST::Block node.
#
transform past (PIR::Grammar::sub_def) :language('PIR') {		
		
		.local pmc past
  	past = new 'PAST::Block'
  	
  	.local string name
    name = node['sub_id']
    past.'init'('node'=>node, 'name'=> name, 'blocktype'=>'sub')
    
    .local pmc pnode, pragma
    pnode = node['sub_pragmas']
    if null pnode goto skip_pragma
 		pragma = tree.'get'('past', pnode, 'PIR::Grammar::sub_pragma') 		
    past.'pragma'(pragma)
  skip_pragma:
    
    .local pmc child           
    $P1 = node['body']
    child = tree.'get'('past', $P1, 'PIR::Grammar::body')
    past.'push'(child)
    .return (past)
}

#transform past (PIR::Grammar::sub_pragmas) {
#		
#}

transform past (PIR::Grammar::sub_pragma) {
		.local pmc past		
		past = node[':main'] ### mmm why does *this* work for all pragmas??
		if null past goto skip
		.return (past)		
	skip:
		.return ()
}

transform past (PIR::Grammar::const_def) :language('PIR') {
	.local pmc past
	past = new 'PASM::Op'
	# FIX:
	past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.const')	
	.return (past)
}

transform past (PIR::Grammar::macro_def) :language('PIR') {

}

transform past (PIR::Grammar::pragma) :language('PIR') {
		.local pmc past
		
	include_pragma:
		$P0 = node['include']
		if null $P0 goto n_op_pragma
		#past = new 'PAST::Op'	
		#past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.include')	
		.return tree.'get'('past', $P0, 'PIR::Grammar::include')
		#.return (past)
	n_op_pragma:
		$P0 = node['new_operators']
		if null $P0 goto loadlib_pragma
		past = new 'PAST::Op'	
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.include')	
		.return (past)
	loadlib_pragma:
		$P0 = node['loadlib']
		if null $P0 goto namespace_pragma
		past = new 'PAST::Op'	
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.include')	
		.return (past)
	namespace_pragma:
		$P0 = node['namespace']
		if null $P0 goto hll_map_pragma
		past = new 'PAST::Op'	
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.include')	
		.return (past)
	hll_map_pragma:
		$P0 = node['hll_mapping']
		if null $P0 goto hll_spec_pragma
		past = new 'PAST::Op'	
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.include')	
		.return (past)
	hll_spec_pragma:
		$P0 = node['hll_specifier']
		if null $P0 goto source_pragma
		past = new 'PAST::Op'	
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.include')	
		.return (past)
	source_pragma:
		$P0 = node['source_info']
		if null $P0 goto unknown
		past = new 'PAST::Op'	
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.include')	
		.return (past)
	
	unknown:
		printerr "unknown pragma in tree transformation\n"
		.local pmc iter, obj
		iter = new .Iterator, node
	loop:		
		unless iter goto endloop
		obj = shift iter
		printerr obj	
		printerr "\n"
		goto loop
	endloop:	
		
		end
	
}

transform past (PIR::Grammar::include) :language('PIR') {
		.local pmc past
		
		.local pmc strn, strp
		strn = node['string_constant']
		strp = tree.'get'('past', strn, 'PIR::Grammar::string_constant')
				
		past = new 'PAST::Op'
		past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>".include %0")
		past.'push'(strp)
		.return (past)
}

transform past (PIR::Grammar::emit) :language('PIR') {
		.local pmc past, startop, endop
		past = new 'PAST::Block'
		past.'init'('node'=>node)
		
		#startop = new 'PAST::Op'
		#startop.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'.emit')
		#past.'push'(startop)
		
		#endop = new 'PAST::Op'
		#endop.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'.eom')
		#past.'push'(endop)
		
		.return (past)	
}


# past (PIR::Grammar::body)
#
# Store each of the instructions in a body node in a PAST::Stmts node.
#
transform past (PIR::Grammar::body) :language('PIR') {		
    .local pmc past
    past = new 'PAST::Stmts'
    past.'init'('node'=>node)		
				
    .local pmc iter
    .local pmc cnode, cpast
    
    # process the parameter declarations
    $P0 = node['param_decl']
    if null $P0 goto iter_param_end
    iter = new .Iterator, $P0    
  iter_param_loop:
  	unless iter goto iter_param_end
  	cnode = shift iter
    cpast = tree.'get'('past', cnode, 'PIR::Grammar::param_decl')
    past.'push'(cpast)
    goto iter_param_loop
  iter_param_end:  
    
    # process the instructions
    $P0 = node['labeled_pir_instr']
    if null $P0 goto iter_instr_end
    iter = new .Iterator, $P0
  iter_instr_loop:
    unless iter goto iter_instr_end
    
    cnode = shift iter
    cpast = tree.'get'('past', cnode, 'PIR::Grammar::labeled_pir_instr')
    past.'push'(cpast)
    goto iter_instr_loop
  iter_instr_end:
    .return (past)	
}

transform past (PIR::Grammar::param_decl) :language('PIR') {
		.local pmc past
		past = new 'PAST::Op'
		
		$P0 = node['id']		
		if null $P0 goto get_reg
		.local pmc idpast, typepast, typenode
		idpast = tree.'get'('past', $P0, 'PIR::Grammar::id')
		typenode = node['type']
		typepast = tree.'get'('past', typenode, 'PIR::Grammar::type')
		
		past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>".param %0 %1")	
		past.'push'(typepast)
		past.'push'(idpast)
		goto done
		
	get_reg:		
		.local pmc regnode, regpast
		regnode = node['reg']		
		regpast = tree.'get'('past', regnode, 'PIR::Grammar::reg')		
		past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>".param %0")	
		past.'push'(regpast)
		
	done:					
		.return (past)
}

  
transform past (PIR::Grammar::local_decl) :language('PIR') {
		.local pmc past, cnode
		past = new 'PAST::Op'
		$P0 = node['type']
		cnode = tree.'get'('past', $P0, 'PIR::Grammar::type')
		past.'push'(cnode)
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.local')
		.return (past)	
}



transform past (PIR::Grammar::lexical_decl) :language('PIR') {
		.local pmc past
		past = new 'PAST::Op'
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.lex')
		.return (past)	
}

transform past (PIR::Grammar::const_def) :language('PIR') {
		.local pmc past
		past = new 'PAST::Op'
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.const')
		.return (past)	
}

transform past (PIR::Grammar::assignment_stat) :language('PIR') {
		.local pmc past, lhs
		past = new 'PAST::Var'
		lhs = node['target']
		if null lhs goto others
		past.'init'('node'=>lhs, 'name'=>lhs, 'scope'=>'lexical', 'islvalue'=>1)		
	  
	  .return (past)
	others:
}

transform past (PIR::Grammar::open_namespace) :language('PIR') {
		.local pmc past	
		past = new 'PAST::Op'	
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.namespace')		
		.return (past)
}

transform past (PIR::Grammar::close_namespace) :language('PIR') {
		.local pmc past
		past = new 'PAST::Op'
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.endnamespace')	
		.return (past)
}
  
transform past (PIR::Grammar::return_stat) :language('PIR') {
		.local pmc past, begin_ret, end_ret
		past = new 'PAST::Stmts'
		
		begin_ret = new 'PAST::Op'
		begin_ret.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.pcc_begin_return')
		past.'push'(begin_ret)
		end_ret = new 'PAST::Op'
		end_ret.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.pcc_end_return')
		past.'push'(end_ret)
		
		.return (past)	
}

transform past (PIR::Grammar::sub_invocation) :language('PIR') {
		.local pmc past, op_begin, op_call, op_end
		past = new 'PAST::Stmts'
		op_begin = new 'PAST::Op'
		op_begin.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.pcc_begin')
		past.'push'(op_begin)
		
		op_call = new 'PAST::Op'
		op_call.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.pcc_call')
		past.'push'(op_call)
		
		op_end = new 'PAST::Op'
		op_end.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.pcc_end')
		past.'push'(op_end)
		
		.return (past)
	
}

transform past (PIR::Grammar::macro_invocation) :language('PIR') {
	
}

transform past (PIR::Grammar::globalconst_def) :language('PIR') {
		.local pmc past
		past = new 'PAST::Op'
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'.globalconst')
		.return (past)
}

transform past (PIR::Grammar::conditional_stat) :language('PIR') {
		.local pmc past, expr, exprnode, gotolabel, block
		expr = node['conditional_expr']
		gotolabel = node['id']
		
		past = new 'PAST::Op'					
		$P0 = node['if']
		if null $P0 goto unless_stat		
		
	if_stat:	
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'if')
		goto do_body			
		
	unless_stat:
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'unless')
	
		# now handle common stuff
	do_body:	
		#exprnode = tree.'get'('past', expr, 'PIR::Grammar::conditional_expr')
		#past.'push'(exprnode)
		#past.'push'(gotolabel)
		.return (past)		
}

transform past (PIR::Grammar::conditional_expr) :language('PIR') {
		.local pmc past
		past = node['simple_expr']
		.return (past)
}

transform past (PIR::Grammar::jump_stat) :language('PIR') {
	.local pmc past
	past = new 'PAST::Op'
	past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'goto')	
	.return (past)
}

transform past (PIR::Grammar::source_info) :language('PIR') {
		.local pmc past
		past = new 'PAST::Op'
		past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'#line')
		.return (past)	      
}       
        
        
transform past (PIR::Grammar::instr) :language('PIR') {		
		$P0 = node['pir_instr']
		if null $P0 goto pasm_instr
	pir_instr:
		.return tree.'get'('past', $P0, 'PIR::Grammar::pir_instr')
	pasm_instr:	
		$P0 = node['pasm_instr']
		.return tree.'get'('past', $P0, 'PIR::Grammar::pasm_instr')
}

transform past (PIR::Grammar::labeled_pir_instr) :language('PIR') {
		$P0 = node['instr']
		if null $P0 goto end
		.return tree.'get'('past', $P0, 'PIR::Grammar::instr')
	end:
}


# past (PIR::Grammar::pir_instr)
#
# Return the transformed tree of a PIR instruction.
#
transform past (PIR::Grammar::pir_instr) :language('PIR') {
	local_decl:
		$P0 = node['local_decl']
		if null $P0 goto lexical_decl
		.return tree.'get'('past', $P0, 'PIR::Grammar::local_decl')
	lexical_decl:
		$P0 = node['lexical_decl']
		if null $P0 goto const_def
		.return tree.'get'('past', $P0, 'PIR::Grammar::lexical_decl')
	const_def:
		$P0 = node['const_def']
		if null $P0 goto globalconst_def
		.return tree.'get'('past', $P0, 'PIR::Grammar::const_def')	
	globalconst_def:
		$P0 = node['globalconst_def']
		if null $P0 goto conditional_stat
		.return tree.'get'('past', $P0, 'PIR::Grammar::globalconst_def')	
	conditional_stat:	
		$P0 = node['conditional_stat']
		if null $P0 goto assignment_stat
		.return tree.'get'('past', $P0, 'PIR::Grammar::conditional_stat')	
	assignment_stat:
		$P0 = node['assignment_stat']
		if null $P0 goto open_namespace
		.return tree.'get'('past', $P0, 'PIR::Grammar::assignment_stat')
	open_namespace:
		$P0 = node['open_namespace']
		if null $P0 goto close_namespace
		.return tree.'get'('past', $P0, 'PIR::Grammar::open_namespace')
	close_namespace:
		$P0 = node['close_namespace']
		if null $P0 goto return_stat
		.return tree.'get'('past', $P0, 'PIR::Grammar::close_namespace')	
	return_stat:
		$P0 = node['return_stat']
		if null $P0 goto sub_invocation
		.return tree.'get'('past', $P0, 'PIR::Grammar::return_stat')		
	sub_invocation:
		$P0 = node['sub_invocation']
		if null $P0 goto macro_invocation
		.return tree.'get'('past', $P0, 'PIR::Grammar::sub_invocation')
	macro_invocation:
		$P0 = node['macro_invocation']
		if null $P0 goto unknown
		.return tree.'get'('past', $P0, 'PIR::Grammar::macro_invocation')
	unknown:
		printerr "Error in Tree Transform!\n"
}


# past (PIR::Grammar::pasm_instr)
#
# Create a PAST::Op node that represents the PASM instruction
#
transform past (PIR::Grammar::pasm_instr) :language('PIR') {
	.local pmc past	
	past = new 'PAST::Op'
	# FIX: set the correct pirop
	past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>node)
	.return (past)
}



transform past (PIR::Grammar::simple_expr) :language('PIR') {   
		.local pmc past
  int_constant:
   	$P0 = node['int_constant']
    if null $P0 goto float_constant
    past = new 'PAST::Val'
    past.'init'('node'=>node, 'vtype'=>'.Integer', 'name'=>node, 'ctype'=>'i+')
    .return (past)
  float_constant:
  	$P0 = node['float_constant']
    if null $P0 goto string_constant
    past = new 'PAST::Val'
    past.'init'('node'=>node, 'vtype'=>'.Float', 'name'=>node, 'ctype'=>'n+')
    .return (past)    
  string_constant:
  	$P0 = node['string_constant']
    if null $P0 goto target
		.return tree.'get'('past', $P0, 'PIR::Grammar::string_constant')
  target:    
    $P0 = node['target']
    .return tree.'get'('past', $P0, 'PIR::Grammar::target')     
}

transform past (PIR::Grammar::target) :language('PIR') {

}

transform past (PIR::Grammar::id) :language('PIR') {
		.local pmc past	
		past = new 'PAST::Val'
		past.'init'('node'=>node, 'name'=>node, 'ctype'=>'~')
		.return (past)
}

transform past (PIR::Grammar::type) :language('PIR') {
		.local pmc past
		past = new 'PAST::Val'
		past.'init'('node'=>node, 'name'=>node)
		.return (past)
}

transform past (PIR::Grammar::string_constant) :language('PIR') {
	stringsingle:
		$P0 = node['stringsingle']
		if null $P0 goto stringdouble
		.return tree.'get'('past', $P0, 'PIR::Grammar::stringsingle')
 	stringdouble:
 		$P0 = node['stringsingle']		
		.return tree.'get'('past', $P0, 'PIR::Grammar::stringdouble')
}

transform past (PIR::Grammar::stringdouble) :language('PIR') {
    .local pmc result
    result = new 'PAST::Val'
    
    .local string value
    # Check if this is a string match
    $I0 = defined node["PGE::Text::bracketed"]
    if $I0 goto bracketed_value
    value = node
    goto no_bracketed_value
  bracketed_value:
    value = node["PGE::Text::bracketed"]
  no_bracketed_value:

    # NOTE: Will have to come back and handle interpolation properly.
    # Currently have no way to distinguish between single quoted and
    # double quoted strings.
    result.'init'('node'=>node, 'vtype'=>'.String', 'name'=>value)
    .return (result)
}

transform past (PIR::Grammar::stringsingle) :language('PIR') {
    .local pmc result  		
    result = new 'PAST::Val'
 
    .local string value
    # Check if this is a string match
    $I0 = defined node["PGE::Text::bracketed"]
    if $I0 goto bracketed_value 
    value = node
    goto no_bracketed_value
  bracketed_value:
    value = node["PGE::Text::bracketed"] 		
  no_bracketed_value: 
    result.'init'('node'=>node, 'vtype'=>'.String', 'name'=>value) 
 		.return (result)
}
