def tokenize(t):
	return t.split('##')
class PythonGenerator(object):
	def __init__(_):
		_.nest=0
		_.tag='py'
		_.code=[
			"import beard",
			"def template(data,value=None,output=beard.output,getvalue=beard.getvalue,compare=beard.compare):"
		]
		_.indent="    "
	def c(_,p,*args):
		_.code.append(_.indent+(p%args))
	def c0(_,p,*args):
		_.code.append(_.indent[:-4]+(p%args))
	def text(_):
		return '\n'.join(_.code)
	def getvalue(_,x):
		return 'getvalue(data,%s)'%(repr(x),)
	def icall(_,block,var):
		_.c("(%s if %s else block_%s)(data,%s,output=output,getvalue=getvalue,compare=compare)",
			_.getvalue(block),_.getvalue(block),block,_.getvalue(var) if var else 'None')
	def ielif(_,var,value):
		_.c0("elif compare(%s,%s):",repr(value),_.getvalue(var))
	def iiter(_,var,lst):
		_.c("hold%u=data.get(%s)",_.nest,repr(var));
		_.c("for var%u in %s:",_.nest,_.getvalue(lst))
		_.indent+='    '
		_.c("data[%s]=var%u",repr(var),_.nest);
		_.nest+=1
	def iblock(_,name,var):
		_.c("def block_%s(data,value,**kw):",name)
		_.indent+='    '
		if var:
			_.c("hold=data.get(%s)",repr(var))
			_.c("data[%s]=value",repr(var))
	def iif(_,var,value):
		_.c("if compare(%s,%s):",repr(value),_.getvalue(var))
		_.indent+='    '
	def iiftrue(_,var):
		_.c("if %s:",_.getvalue(var))
		_.indent+='    '
	def iiffalse(_,var):
		_.c("if not %s:",_.getvalue(var))
		_.indent+='    '
	def ielse(_):
		_.c0("else:")
	def ivar(_,var):
		_.c("output(%s)",_.getvalue(var))
	def ilit(_,text):
		_.c("output(%s)",repr(text))
	def icode(_,code):
		_.code.insert(1,code)		
	def pop(_,what):
		if what[0]=='for':
			_.nest-=1
			_.c("if hold%u is not None: data[%s]=hold%u",_.nest,repr(what[1]),_.nest)
		elif what[0]=='block':
			if what[1]:
				_.c("if hold is not None: data[%s]=hold",repr(what[1]))
		_.indent=_.indent[:-4]
class JavascriptGenerator(object):
	def __init__(_,name):
		_.tag='js'
		_.code=[
			"Beard.template[%s]=function(data,value,output,getvalue,compare) {"%(repr(name)),
			"    function _istrue(x) { if(x && x.length!=undefined) return x.length>0; return x; }"
		]
		_.indent="    "
	def c(_,p,*args):
		_.code.append(_.indent+(p%args))
	def c0(_,p,*args):
		_.code.append(_.indent[:-4]+(p%args))
	def text(_):
		return '\n'.join(_.code+['}'])
	def getvalue(_,x):
		return 'getvalue(data,%s)'%(repr(x),)
	def icall(_,block,var):
		_.c("(%s?%s:block_%s)(data,%s,output,getvalue,compare);",_.getvalue(block),_.getvalue(block),block,_.getvalue(var))
	def ielif(_,var,value):
		_.c0("} else if(compare(%s,%s)) {",repr(value),_.getvalue(var))
	def iiter(_,var,lst):
		_.c("for(var arr=%s,idx=0;idx<arr.length;idx++) {",_.getvalue(lst))
		_.indent+='    '
		_.c("var hold=data[%s]; ",repr(var))
		_.c("data[%s]=arr[idx]; ",repr(var))
	def iblock(_,name,var):
		_.c("function block_%s(data,value) {",name)
		_.indent+='    '
		_.c("var hold=data[%s];",repr(var))
		_.c("data[%s]=value;",repr(var))
	def iif(_,var,value):
		_.c("if(compare(%s,%s)) {",repr(value),_.getvalue(var))
		_.indent+='    '
	def iiftrue(_,var):
		_.c("if(_istrue(%s)) {",_.getvalue(var))
		_.indent+='    '
	def iiffalse(_,var):
		_.c("if(!_istrue(%s)) {",_.getvalue(var))
		_.indent+='    '
	def ielse(_):
		_.c0("} else {")
	def ivar(_,var):
		_.c("output(%s);",_.getvalue(var))
	def ilit(_,text):
		_.c("output(%s);",repr(text))
	def icode(_,code):
		_.code.insert(1,code)		
	def pop(_,what):
		if what[0]=='for':_.c("if(hold!=undefined) data[%s]=hold;",repr(what[1]))
		elif what[0]=='block': _.c("if(hold!=undefined) data[%s]=hold",repr(what[1]))
		_.indent=_.indent[:-4]
		_.c("}")
def source(text,gen):
	tokens=tokenize(text)
	return generate(gen,tokens)
def generate(gen,tokens):
	stack=[]
	code=None
	pos=0
	for i in range(len(tokens)):
		token=tokens[i]
		pos+=len(token)+2
		if code is not None:
			if i%2 and token=='':
				if code: gen.icode(''.join(code))
				code=None
			else:
				if type(code)==list : code.append(token)
			continue
		if i%2:
			if token=='\\':
				gen.ilit('#')
			elif token.startswith('@'):
				gen.iiftrue(token[1:])
				stack.append(['if'])
			elif token.startswith('!'):
				gen.iiffalse(token[1:])
				stack.append(['if'])
			elif token.startswith('{'):
				code=[] if gen.tag==token[1:] else False
			elif token.endswith('?'):
				gen.ielif(stack[-1][1],token[:-1])
			elif '?' in token:
				value,var=token.split('?')
				gen.iif(var,value)
				stack.append(['if',var])
			elif token=='*':
				gen.ielse()
			elif '=' in token:
				var,name=token.split('=')
				gen.iblock(name,var)
				stack.append(['block',var])
			elif '>' in token:
				var,block=token.split('>')
				gen.icall(block,var)
			elif ':' in token:
				var,lst=token.split(':')
				gen.iiter(var,lst)
				stack.append(['for',var])
			elif token=='':
				gen.pop(stack.pop())
			else:
				gen.ivar(token)
		else:
			if token!='': gen.ilit(token)
	return gen.text()
import sys
def output(x):
	if x is not None:
		sys.stdout.write(str(x))
def getvalue(data,x):
	vs=x.split('.')
	v=data
	for y in vs:
		v=v.get(y)
		if v is None: return None
	return v
def compare(x,y):
	if repr(x)==repr(y): return True
	return False
def render(template,data):
	s=[]
	def output(x):
		if x is not None: s.append(str(x))
	template(data,output=output)
	return ''.join(s)
def compile(text):
	template=source(text,PythonGenerator())
	g={}
	l={}
	exec(template,g,l)
	compiled=l['template']
	compiled.func_globals.update(l)
	return compiled
def main(argv):
	if argv[1]=='--test': return test()
	text=open(argv[1]).read()
	tokens=tokenize(text)
	name=argv[1][:-6] if argv[1].endswith('.beard') else argv[1]
	f=open(name+'.py','w')
	template=generate(PythonGenerator(),tokens)
	f.write(template)
	f.close()
	f=open(name+'.js','w')
	template=generate(JavascriptGenerator(name),tokens)
	f.write(template)
	f.close()
def test():
	from sys import argv
	from importlib import import_module
	m=import_module(argv[2])
	
	m.template({
		'simple_var': 'Simple Variable',
		'simple_cond_var': True,
		'list_var': ['left','center','right','unknown'],
		'ext_block': lambda data,x,output,**kw: output("External block received '%s' value"%(x,)),
		'nestlist_var': [{'cond':'left'},{'cond':'center'},{'cond':'right'},{'cond':'unknown'}],
	})
if __name__=='__main__':
	from sys import argv
	main(argv)
