include 'ril.lm'

namespace ruby_out
	token _IN_ /''/
	token _EX_ /''/

	lex
		token comment /
			'#' any* :> '\n'
		/

		literal `def `class `begin `end `while `if

		token id
			/[a-zA-Z_][a-zA-Z_0-9]*/

		token number /
			[0-9]+
		/

		token string /
				'"' ( [^"\\] | '\\' any ) * '"' |
				"'" ( [^'\\] | '\\' any ) * "'" |
				"/" ( [^/\\] | '\\' any ) * "/"
			/

		token symbol /
			'!' | '#' | '$' | '%' | '&' | '(' | ')' | '*' |
			'+' | ',' | '-' | '.' | '/' | ':' | ';' | '<' |
			'=' | '>' | '?' | '@' | '[' | ']' | '^' | '|' |
			'~' | '{' | '}' | '\\' /

		ignore
			/[ \t\v\r\n]+/
	end

	def item
		[comment]
	|	[id]
	|	[number]
	|	[symbol]
	|	[string]
	|	[`begin _IN_]
	|	[`class _IN_]
	|	[`while _IN_]
	|	[`if _IN_]
	|	[`def _IN_]
	|	[_EX_ `end]

	def ruby_out
		[_IN_ _EX_ item*]
end

global Parser: parser<ruby_out::ruby_out>

void tok_list( TL: host::tok* )
{
	for Tok: host::tok in repeat(TL) {
		switch Tok
		case [host::`${ StmtList: stmt* host::`}$]
		{
			send Parser
				"begin
				"[stmt_list( StmtList )]
				"end
		}
		case [host::`={ Expr: expr host::`}=]
			expr( Expr )
		case [E: escape] {
			Str: str = $E
			send Parser
				"[Str.suffix( 1 )]"
		}
		default {
			send Parser [Tok]
		}
	}
}

void embedded_host( EH: embedded_host )
{
	switch EH
	case [`host `( string `, uint `) `={ TL: host::tok* host::`}=]
	{
		send Parser
			"([tok_list( TL )])"
	}
	case [`host `( string `, uint `) `${ TL: host::tok* host::`}$]
	{
		send Parser 
			"begin
			"	[tok_list( TL )]
			"end
	}
	case [`host `( string `, uint `) `@{ TL: host::tok* host::`}@]
	{
		send Parser
			[tok_list( TL )]
	}
}

void expr_factor( ExprFactor: expr_factor )
{
	switch  ExprFactor
	case [EH: embedded_host]
	{
		send Parser
			[embedded_host( EH )]
	}
	case [O:`( TL: expr C: `)]
	{
		send Parser
			[O expr(TL) C]
	}
	case [ident O: `[ TL: expr C: `]]
	{
		send Parser
			[ExprFactor.ident O expr( TL ) C]
	}
	case ['offset' '(' ident ',' expr ')']
	{
		send Parser
			[expr( ExprFactor.expr )]
	}
	case ['deref' '(' ident ',' expr ')']
	{
		send Parser
			[ ExprFactor.ident '[' expr( ExprFactor.expr ) ']']
		if $ExprFactor.ident == 'data'
			send Parser '.ord'
	}
	case [T: `TRUE]
	{
		T.data = 'true'
		send Parser [T]
	}
	case [F: `FALSE]
	{
		F.data = 'false'
		send Parser [F]
	}
	case [N: `nil]
	{
		N.data = '0'
		send Parser [N]
	}
	case [Number: number]
	{
		ruby_number( Number )
	}
	case [E1: embedded_host `-> E2: expr_factor]
	{
		embedded_host( E1 )
		expr_factor( E2 )
	}
	case [`cast Open: `( Type: type Close: `) expr_factor]
	{
		#send Parser [Open]
		#type( Type )
		#send Parser [Close]
		expr_factor( ExprFactor._expr_factor )
	}
	case [I: ident `[ E: expr `] `. F: ident] {
		send Parser
			[^I '_' ^F '[' E ']']
	}
	default {
		# Catches cases not specified
		send Parser [ExprFactor]
	}
}

void lvalue( ExprFactor: lvalue )
{
	switch ExprFactor
	case [EH: embedded_host]
	{
		send Parser
			[embedded_host( EH )]
	}
	case [ident O: `[ TL: expr C: `]]
	{
		send Parser
			[ExprFactor.ident O expr( TL ) C]
	}
	case [E1: embedded_host `-> E2: lvalue]
	{
		embedded_host( E1 )
		lvalue( E2 )
	}
	case [I: ident `[ E: expr `] `. F: ident] {
		send Parser
			[^I '_' ^F '[' E ']']
	}
	default {
		# Catches cases not specified
		send Parser [ExprFactor]
	}
}

void expr_factor_op( ExprFactorOp: expr_factor_op )
{
	switch ExprFactorOp
	case [B: `! expr_factor_op]
	{
		send Parser [B]
		expr_factor_op( ExprFactorOp._expr_factor_op )
	}
	case [T: `~ expr_factor_op]
	{
		send Parser [T]
		expr_factor_op( ExprFactorOp._expr_factor_op )
	}
	case [expr_factor]
	{
		expr_factor( ExprFactorOp.expr_factor )
	}
}

void expr_bitwise( ExprBitwise: expr_bitwise )
{
	switch ExprBitwise
	case [expr_bitwise A: `& expr_factor_op]
	{
		expr_bitwise( ExprBitwise._expr_bitwise )
		send Parser [A]
		expr_factor_op( ExprBitwise.expr_factor_op )
	}
	case [expr_factor_op]
	{
		expr_factor_op( ExprBitwise.expr_factor_op )
	}
}

void expr_mult( ExprMult: expr_mult )
{
	switch ExprMult
	case [expr_mult T: `* expr_bitwise]
	{
		expr_mult( ExprMult._expr_mult )
		send Parser [T]
		expr_bitwise( ExprMult.expr_bitwise )
	}
	case [expr_bitwise]
	{
		expr_bitwise( ExprMult.expr_bitwise )
	}
}

void expr_add( ExprAdd: expr_add )
{
	switch ExprAdd
	case [expr_add Op: add_op expr_mult]
	{
		expr_add( ExprAdd._expr_add )
		send Parser [Op]
		expr_mult( ExprAdd.expr_mult )
	}
	case [expr_mult]
	{
		expr_mult( ExprAdd.expr_mult )
	}
}

void expr_shift( ExprShift: expr_shift )
{
	switch ExprShift
	case [expr_shift Op: shift_op expr_add]
	{
		expr_shift( ExprShift._expr_shift )
		send Parser [Op]
		expr_add( ExprShift.expr_add )
	}
	case [expr_add]
	{
		expr_add( ExprShift.expr_add )
	}
}

void expr_test( ExprTest: expr_test )
{
	switch ExprTest
	case [expr_test Op: test_op expr_shift]
	{
		expr_test( ExprTest._expr_test )
		send Parser [Op]
		expr_shift( ExprTest.expr_shift )
	}
	case [expr_shift]
	{
		expr_shift( ExprTest.expr_shift )
	}
}

void expr( Expr: expr )
{
	expr_test( Expr.expr_test )
}

void type( Type: type )
{
	switch Type
	case "s8"
		send Parser ['byte ']
	case "s16"
		send Parser ['short ']
	case "s32"
		send Parser ['int ']
	case "s64"
		send Parser ['long ']
	case "s128"
		send Parser ['long long ']
	case "uint"
		send Parser ['int ']
	default
		send Parser [Type]
}

void ruby_number( Number: number )
{
	switch Number
	case [`u `( uint `) ]
		send Parser "[Number.uint]"
	default
		send Parser [Number]
}

void ruby_num_list( NumList: num_list )
{
	for Number: number in NumList
		send Parser "[ruby_number( Number )], "
}

void stmt( Stmt: stmt )
{
	switch Stmt
	case [EH: embedded_host]
	{
		send Parser
			[embedded_host( EH )]
	}
	case [A: static_array] {
		send Parser
			"class << self
			"	attr_accessor :[ A.ident ] 
			"	private :[ A.ident ], :[ A.ident ]=
			"end
			"self.[ A.ident ] = \[
			"	[ruby_num_list( A.num_list )]
			"\]
			"
	}
	case [V: static_value] {
		send Parser
			"class << self
			"	attr_accessor :[ V.ident ]
			"end
			"self.[ V.ident ] = [ V.number ];
			"
	}
	case [
			'if' O: `( IfExpr: expr C: `) IfStmt: stmt
			ElseIfClauseList: else_if_clause* ElseClauseOpt: else_clause?
	] {
		send Parser
			"if ( [expr(IfExpr)] )
			"	[stmt(IfStmt)]

		for ElseIfClause: else_if_clause in repeat( ElseIfClauseList ) {
			match ElseIfClause
				['else if (' ElseIfExpr: expr ')' ElseIfStmt: stmt]

			send Parser
				"elsif ( [expr(ElseIfExpr)] )
				"	[stmt(ElseIfStmt)]
		}

		if ( match ElseClauseOpt ['else' ElseStmt: stmt] ) {
			send Parser
				"else
				"	[stmt(ElseStmt)]
		}
		send Parser
			"end
	}
	case ['while' '(' WhileExpr: expr ')' WhileStmt: stmt] {
		send Parser
			"while ( [expr(WhileExpr)] )
			"	[stmt(WhileStmt)]
			"end
	}
	case ['switch' '(' SwitchExpr: expr ')' '{' StmtList: stmt* '}'] {
		send Parser
			"case  [expr(SwitchExpr)] 
			"when -2 then
			"begin
			"	[stmt_list(StmtList)]
			"end
			"end
	}
	case [ExprExpr: expr Semi: `;] {
		send Parser
			[expr(ExprExpr) Semi]
	}
	case [L: `{ TL: stmt* R: `}] {
		send Parser
			"begin
			"[stmt_list(TL)]
			"end
	}
	# [declaration]
	case [
		TypeList: opt_const Type: type
		Ident: ident OptInit: opt_init Semi: `;
	]
	{
		send Parser
			[Ident]

		if match OptInit [E: `= expr] {
			send Parser
				[E expr(OptInit.expr)]
		}
		else {
			send Parser
				"= 0
		}

		send Parser
			[Semi]
	}
	case [Export: export_stmt]
	{
		send Parser
			"class << self
			"	attr_accessor :[ Export.ident ]
			"end
			"self.[ Export.ident ] = [ ruby_number(Export.number) ];
			"
	}
	case ['fallthrough' ';']
	{
		# Nothing needed here.
	}
	case [Index: index_stmt]
	{
		send Parser
			"[Index.ident]"

		if match Index.opt_init [E: `= expr] {
			send Parser
				[E expr(Index.opt_init.expr)]
		}
		else {
			send Parser
				"= 0
		}

		send Parser ";
	}
	case [case_block]
	{
		send Parser
			"end
			"when [expr( Stmt.case_block.expr )] then
			"begin
			"[stmt_list( Stmt.case_block._repeat_stmt )]
	}
	case [default_block]
	{
		send Parser
			"end
			"else
			"begin
			"[stmt_list( Stmt.default_block._repeat_stmt )]
	}
	case [goto_label] {}
	case [goto_stmt] {}
	case [AS: assign_stmt]
	{
		send Parser
			"[lvalue(AS.LValue) AS.assign_op expr(AS.expr)];
	}
	case [continue_stmt]
	{
		send Parser
			"next;
	}
	default {
		# catches unspecified cases
		send Parser [Stmt]
	}
}

void stmt_list( StmtList: stmt* )
{
	for Stmt: stmt in repeat( StmtList )
		stmt( Stmt )
}

void ruby_trans( Output: stream, Start: start )
{
	Parser = new parser<ruby_out::ruby_out>()

	if ( Start.opt_bom.bom )
		send Output [Start.opt_bom.bom]

	stmt_list( Start._repeat_stmt )

	RO: ruby_out::ruby_out = Parser->finish()

	if RO {
		send Output
			[RO]
	}
	else {
		send stderr
			"failed to parse output: [Parser->error]
	}
}

void trans( Output: stream, Start: start )
{
	ruby_trans( Output, Start )
}

include 'rlhc-main.lm'
