# -*- Mode: Python; tab-width: 4 -*-

import kjParseBuild
import string

grammar = """
	exp ::
	@R r_exp_1			:: exp >> int
	@R r_exp_2			:: exp >> varref
	@R r_exp_3			:: exp >> operator operands
	@R r_exp_4			:: exp >> if exp then exp else exp
	@R r_exp_5			:: exp >> let decl_list in exp
	@R r_operator_1		:: operator >> varref
	@R r_operator_2		:: operator >> ( exp )
	@R r_operands_1		:: operands >> ( )
	@R r_operands_2		:: operands >> ( operand_list )
	@R r_operand_list_1	:: operand_list >> operand
	@R r_operand_list_2	:: operand_list >> operand_list , operand
	@R r_operand		:: operand >> exp
	@R r_varref			:: varref >> var
	@R r_decl_list_1	:: decl_list >> decl
	@R r_decl_list_2	:: decl_list >> decl_list ; decl
	@R r_decl			:: decl >> var = exp
"""

int_regex = "\(-\)?[0-9]+"
var_regex = "[A-Za-z_+*-][A-Za-z0-9+*-]*"

def int_interp (str):
	return string.atoi (str)

def identity (str):
	return str

def build_grammar():
	g = kjParseBuild.NullCGrammar()
	g.Addterm ("int", int_regex, int_interp)
	g.Addterm ("var", var_regex, identity)
	g.Keywords ("if then else let in")
	g.punct ("(),;=")
	g.Nonterms ("exp operator operands operand_list operand varref decl_list decl")
	g.Declarerules (grammar)
	g.Compile()
	return g

def bind_rules (g):

	def r_exp_1 (list, context):
		return ['lit', list[0]]

	def r_exp_2 (list, context):
		return list[0]

	def r_exp_3 (list, context):
		return ['app', list[0], list[1]]

	def r_exp_4 (list, context):
		return ['conditional', list[1], list[3], list[5]]

	def r_exp_5 (list, context):
		return ['let', list[1], list[3]]

	def r_operator_1 (list, context):
		return list[0]

	def r_operator_2 (list, context):
		return list[1]

	def r_operands_1 (list, context):
		return []
	
	def r_operands_2 (list, context):
		return list[1]

	def r_operand_list_1 (list, context):
		return [list[0]]

	def r_operand_list_2 (list, context):
		return list[0] + [list[2]]
						  
	def r_operand (list, context):
		return list[0]

	def r_varref (list, context):
		return ['varref', list[0]]

	def r_decl_list_1 (list, context):
		return [list[0]]

	def r_decl_list_2 (list, context):
		return list[0] + [list[2]]

	def r_decl (list, context):
		return ['decl', list[0], list[2]]

	for n,f in (
		("r_exp_1",				r_exp_1),
		("r_exp_2",				r_exp_2),
		("r_exp_3",				r_exp_3),
		("r_exp_4",				r_exp_4),
		("r_exp_5",				r_exp_5),
		("r_operator_1",		r_operator_1),
		("r_operator_2",		r_operator_2),
		("r_operands_1",		r_operands_1),
		("r_operands_2",		r_operands_2),
		("r_operand_list_1",	r_operand_list_1),
		("r_operand_list_2",	r_operand_list_2),
		("r_operand",			r_operand),
		("r_varref",			r_varref),
		("r_decl_list_1",		r_decl_list_1),
		("r_decl_list_2",		r_decl_list_2),
		("r_decl",				r_decl),
		):
		g.Bind (n,f)

def make_grammar():
	print 'building parser...'
	g = build_grammar()
	bind_rules (g)
	print 'done.'
	return g
