#! /usr/bin/python
#
"""LOLCODE to Python translator

A quick hack to translate LOLCODE to Python. OH NOES!
"""
__author__ = "David Basden "
__copyright__ = "GNU Public Licence v2.0"
__version__ = "0.2"

import re
import sys

class State(object):
	def __init__(self): self.level = 0
	def indent(self): return "\t"*self.level

class Keyword(object):
	format = ""
	match = None
	indent = True
	subparse = ()
	def __init__(self, match):
		self.match = match
		self.args = list( match.groups() )
	def on_match_start(self, state): pass
	def on_match_end(self, state): pass
	def on_recurse_start(self, state): pass
	def on_recurse_end(self, state): pass
	def render(self, state):
		if self.indent: out = state.indent()
		else: out = ""
		out += self.format % tuple(self.args)
		return out
	def __str__(self): return str(type(self))+str(self.args)

class Hai(Keyword):
	matchon = "HAI"
	format = "for __HAI in ('l0l',):\n"
	def on_match_end(self, state): state.level += 1
class KThxBye(Keyword):
	matchon = "KTHXBYE"
	format = "break\n"
class CanHas(Keyword):	# TODO: make this ! noop
	matchon = "CAN HAS (.+)\?"
	format = "# import %s\n"
class Visible(Keyword):
	matchon = "VISIBLE (.+)$"
	subparse = (0,)
	format = "print %s\n"
class Gimmeh(Keyword):
	matchon = "GIMMEH (.+)"
	format = "%s = raw_input()\n"
class IHasA(Keyword):
	matchon = "I HAS A (.+)"
	format = "%s = 0\n"
class ImInUrLoop(Keyword):
	matchon = "IM IN YR LOOP"
	format = "while True:\n"
	def on_match_end(self, state): state.level += 1
class ImOuttaUrLoop(Keyword):
	matchon = "IM OUTTA YR LOOP"
	format = "pass\n"
	def on_match_end(self, state): state.level -= 1
class BiggerThan(Keyword):
	matchon = """IZ (.+) BIGGER THAN (.+)\?(.+)$"""
	format = "if %s > %s:\n%s"
	subparse = (2,)
	def on_recurse_start(self, state): state.level += 1
	def on_recurse_end(self, state): state.level -= 1
class Up(Keyword):
	matchon = "UP (.+)!!(\d+)"
	format = "%s += %s\n"
class NN(Keyword):
	matchon = """^(.+?)\ N\ (.+)$"""
	subparse = (0,1)
	indent = False
	format = "%s + %s"
	
	
# This also defines precedence in descending order
keywords = (Hai,KThxBye,CanHas,Visible,Gimmeh,IHasA,ImInUrLoop,ImOuttaUrLoop,BiggerThan,Up,NN)

class LolLex(object):
	def __init__(self, keywords):
		self.keywords = keywords
		self.patternmap = [(re.compile(c.matchon,re.MULTILINE & re.DOTALL),c) for c in keywords] 
	def getkw(self,cs):
		for pattern,c in self.patternmap:
			m = pattern.match(cs.strip())
			if m != None: return c(m)
		return None
	def parse(self,cs):
		kw = self.getkw(cs)
		if kw == None: return kw
		for sp in kw.subparse:
			# Iff recursed keyword is empty, we should leave the input in place
			# because it probably contains a variable name -- Base case
			recursekw = self.parse(kw.args[sp])
			if recursekw != None: kw.args[sp]= recursekw
		return kw
class Lol2Py(object):
	def get_code_str(self, kws, s=None):
		out = ""
		if s == None: s = State()
		for kw in kws:
			if not isinstance(kw,Keyword): ## Leave non-keywords in-place
				out = out + str(kw)
				continue
			kw.on_match_start(s)
			for sp in kw.subparse: # recursive render - tres evil
				kw.on_recurse_start(s)
				token = self.get_code_str((kw.args[sp],), s=s)
				kw.args[sp] = token
				kw.on_recurse_end(s)
			out = out + kw.render(s)
			kw.on_match_end(s)
		return out

def usage():
	print >> sys.stderr, "%s < [-h|--help] | [-c|--show-code] | [-r|--run-code] > [filename]" % (sys.argv[0],)
	sys.exit()

if __name__ == "__main__":
	filename,runcode,showcode = None,False,False
	for arg in sys.argv[1:]:
		if arg == '-r' or arg == '--run': runcode = True
		elif arg == '-c' or arg == '--show-code': showcode = True
		elif filename != None or arg == '-h' or arg == '--help': usage()
		else: filename = arg
	if not (runcode or showcode): showcode = True
	if filename == None: codefile = sys.stdin
	else: codefile = open(filename,'r')

	ll = LolLex(keywords)
	kws,buf = [], ""
	while True:
		line = codefile.readline()
		if line == "": break
		buf = buf+" "+line.strip()
		kw = ll.parse(buf)
		if kw != None:
			kws.append(kw)
			buf = buf[kw.match.end()+1:]
		else:
			print "### DO NOT WANT!!! : [%s]" % (buf,)
			buf = ""
	l2p = Lol2Py()
	codez = l2p.get_code_str(kws)
	if showcode:
		if runcode: print "# Start lolpy code output"
		print codez
		if runcode: print "# End lolpy code output\n\n# RUNZ0RZ!"
	if runcode: exec codez in {}