#!/usr/bin/env python from types import StringType # Licensed under Apache as I have borrowed some code from # PyJs which is under Apache 2.0 License. # # Copyright Ganhawk, James Tauber # This file contains some code from pyjs by James Tauber and contributors # pyjs is part of pyjamas (http://pyjs.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # import compiler from compiler import ast import os import copy import cStringIO import sys import re class TranslationError(Exception): def __init__(self, message, node): self.message = "line %s:\n%s\n%s" % (node.lineno, message, node) def __str__(self): return self.message class Translator: def __init__(self, mod, output): self.output = output self.funcVars = [] self.indent = "" self.globalVars = [] for child in mod.node: if isinstance(child, ast.Global): self._global(child) for child in mod.node: if isinstance(child, ast.Function): self._function(child, False) self.funcVars = [] print >>self.output,self.indent, "task main()" print >>self.output,self.indent, "{" self.inindent() for child in mod.node: if isinstance(child, ast.Function): continue elif isinstance(child, ast.Discard): self._discard(child) elif isinstance(child, ast.Assign): self._assign(child) else: self._stmt(child) self.deindent() print >>self.output,self.indent, "}" def inindent(self): self.indent += " " def deindent(self): self.indent = self.indent[:-3] def _varargs_handler(self, node, varargname, argNames): print >>self.output,self.indent,self.indent, "int ", varargname, '[] = {}; ' def _function(self, node, local=False): functionName = node.name argNames = list(node.argnames) normalArgNames = list(argNames) if node.varargs: varargname = normalArgNames.pop() declaredArgNames = list(normalArgNames) self.funcVars = [] function_args = "(" for argNam in declaredArgNames: type = "int " if argNam.find("long") > -1: type = "long " function_args += type+argNam+"," function_args = function_args.rstrip(',') + ")" print >>self.output,self.indent, "sub %s%s {" % (functionName, function_args) if node.varargs: self._varargs_handler(node, varargname, declaredArgNames) self.inindent() for child in node.code: self._stmt(child) self.deindent() print >>self.output,self.indent, "}" print >>self.output,self.indent, "\n" def _return(self, node): expr = self.expr(node.value) if expr != "null": print >>self.output,self.indent, "return " + expr + ";" else: print >>self.output,self.indent, "return;" def _break(self, node): print >>self.output,self.indent, "break;" def _continue(self, node): print >>self.output,self.indent, "continue;" def _callfunc(self, v): if isinstance(v.node, ast.Name): callName = v.node.name callArgs = [] elif isinstance(v.node, ast.Getattr): attrName = v.node.attrname if isinstance(v.node.expr, ast.Name): callName = self._name(v.node.expr) callArgs = [] elif isinstance(v.node.expr, ast.Getattr): callName = self._getattr(v.node.expr) callArgs = [] elif isinstance(v.node.expr, ast.CallFunc): callName = self._callfunc(v.node.expr) + "." + v.node.attrname callArgs = [] elif isinstance(v.node.expr, ast.Subscript): callName = self._subscript(v.node.expr) + "." + v.node.attrname callArgs = [] elif isinstance(v.node.expr, ast.Const): callName = self.expr(v.node.expr) + "." + v.node.attrname callArgs = [] else: raise TranslationError("unsupported type (in _callfunc)", v.node.expr) else: # pass through call callName = v.node.name kwargs = [] for ch4 in v.args: if isinstance(ch4, ast.Keyword): kwarg = ch4.name + ":" + self.expr(ch4.expr) kwargs.append(kwarg) else: arg = self.expr(ch4) callArgs.append(arg) if kwargs: try: call_this, methodName = callName.rsplit(".", 1) except ValueError: raise TranslationError("unsupported type (in _callfunc)", v.node.expr) else: return callName + "(" + ", ".join(callArgs) + ")" def _print(self, node): callArgs = [] for ch4 in node.nodes: arg = self.expr(ch4) callArgs.append(arg) print >>self.output,self.indent, "printf(", ', '.join(callArgs), ");" def _discard(self, node): if isinstance(node.expr, ast.CallFunc): expr = self._callfunc(node.expr) print >>self.output,self.indent, expr + ";" elif isinstance(node.expr, ast.Const): if node.expr.value is not None: # Empty statements generate ignore None print >>self.output,self.indent, self._const(node.expr) else: raise TranslationError("unsupported type (in _discard)", node.expr) def _stmt(self, node): if isinstance(node, ast.Return): self._return(node) elif isinstance(node, ast.Break): self._break(node) elif isinstance(node, ast.Continue): self._continue(node) elif isinstance(node, ast.Assign): self._assign(node) elif isinstance(node, ast.AugAssign): self._augassign(node) elif isinstance(node, ast.Discard): self._discard(node) elif isinstance(node, ast.If): self._if(node) elif isinstance(node, ast.For): self._for(node) elif isinstance(node, ast.While): self._while(node) elif isinstance(node, ast.Subscript): self._subscript_stmt(node) elif isinstance(node, ast.Global): self._global(node) elif isinstance(node, ast.Pass): pass elif isinstance(node, ast.Function): self._function(node, True) elif isinstance(node, ast.Printnl): self._print(node) elif isinstance(node, ast.Print): self._print(node) else: raise TranslationError("unsupported type (in _stmt)", node) def _augassign(self, node): v = node.node if isinstance(v, ast.Getattr): lhs = self._getattr(v) else: lhs = self._name(node.node) op = node.op rhs = self.expr(node.expr) print >>self.output,self.indent, lhs + " " + op + " " + rhs + ";" def _assign(self, node): if len(node.nodes) != 1: tempvar = '__temp'+str(node.lineno) tnode = ast.Assign([ast.AssName(tempvar, "OP_ASSIGN", node.lineno)], node.expr, node.lineno) self._assign(tnode) for v in node.nodes: tnode2 = ast.Assign([v], ast.Name(tempvar, node.lineno), node.lineno) self._assign(tnode2) return v = node.nodes[0] if isinstance(v, ast.AssAttr): attrName = v.attrname if isinstance(v.expr, ast.Name): obj = v.expr.name lhs = " " + self._name(v.expr) + "." + attrName elif isinstance(v.expr, ast.Getattr): lhs = " " + self._getattr(v) elif isinstance(v.expr, ast.Subscript): lhs = " " + self._subscript(v.expr) + "." + attrName else: raise TranslationError("unsupported type (in _assign)", v.expr) if v.flags == "OP_ASSIGN": op = "=" else: raise TranslationError("unsupported flag (in _assign)", v) elif isinstance(v, ast.AssName): type = "int " declaration = 0 if v.name.find("long") > -1: type = "long " if v.name in self.funcVars or v.name in self.globalVars: lhs = v.name else: self.funcVars.append(v.name) lhs = type + v.name declaration = 1 if v.flags == "OP_ASSIGN": op = "=" else: raise TranslationError("unsupported flag (in _assign)", v) elif isinstance(v, ast.Subscript): if v.flags == "OP_ASSIGN": obj = self.expr(v.expr) if len(v.subs) != 1: raise TranslationError("must have one sub (in _assign)", v) idx = self.expr(v.subs[0]) value = self.expr(node.expr) print >>self.output,self.indent, obj + "[" + idx + "] = " + value + ";" return else: raise TranslationError("unsupported flag (in _assign)", v) else: raise TranslationError("unsupported type (in _assign)", v) rhs = self.expr(node.expr) if rhs.find('{') != -1 and rhs.find('}') != -1: if not declaration: raise TranslationError("Reinitialization of array not supported (in _assign)", v) arrlen = len(rhs.split(",")) print >>self.output,self.indent, lhs + "["+str(arrlen)+"] " + op + " " + rhs+";" else: print >>self.output,self.indent, lhs + " " + op + " " + rhs +";" def _if(self, node): for i in range(len(node.tests)): test, consequence = node.tests[i] if i == 0: keyword = "if" else: keyword = "else if" self._if_test(keyword, test, consequence) if node.else_: keyword = "else" test = None consequence = node.else_ self._if_test(keyword, test, consequence) def _if_test(self, keyword, test, consequence): if test: expr = self.expr(test) print >>self.output,self.indent, keyword + " (" + expr + ") {" else: print >>self.output,self.indent, keyword + " {" self.inindent() if isinstance(consequence, ast.Stmt): for child in consequence.nodes: self._stmt(child) else: raise TranslationError("unsupported type (in _if_test)", consequence) self.deindent() print >>self.output,self.indent, "}" def _compare(self, node): lhs = self.expr(node.expr) if len(node.ops) != 1: raise TranslationError("only one ops supported (in _compare)", node) op = node.ops[0][0] rhs_node = node.ops[0][1] rhs = self.expr(rhs_node) if op == "is": op = "==" return "(" + lhs + " " + op + " " + rhs + ")" def _not(self, node): expr = self.expr(node.expr) return "!(" + expr + ")" def _or(self, node): expr = " || ".join([self.expr(child) for child in node.nodes]) return expr def _and(self, node): expr = " && ".join([self.expr(child) for child in node.nodes]) return expr def _for(self, node): assignName = "" assname = "" assign_tuple = "" if isinstance(node.assign, ast.AssName): assignName = node.assign.name if node.assign.flags == "OP_ASSIGN": op = "=" else: raise TranslationError("Not implemented yet", node.assign) if isinstance(node.list, ast.CallFunc): expr = self._callfunc(node.list) if expr.find("range")>-1: descStr = "(\d+),(\D+)(\d+)" descRe = re.compile(descStr) m = descRe.search(expr) if m: sval = m.group(1) dval = m.group(3) print >>self.output,self.indent, "for (%s=%s; %s < %s; %s++) {"%(assignName, sval, assignName, dval, assignName) elif isinstance(node.list, ast.Name): expr = self._name(node.list) assignName1 = assignName + "_t" dval = "ArrayLen(%s)"%(expr) print >>self.output,self.indent, "for (%s=0; %s < %s; %s++) {"%(assignName1, assignName1, dval, assignName1) print >>self.output,self.indent, " int %s = %s[%s];"%(assignName, expr, assignName1) #elif isinstance(node.list, ast.Getattr): # list_expr = self._getattr(node.list) else: raise TranslationError("unsupported type (in _for)", node.list) self.inindent() for node in node.body.nodes: self._stmt(node) self.deindent() print >>self.output,self.indent, "}" def _while(self, node): test = self.expr(node.test) print >>self.output,self.indent, "while (" + test + ") {" self.inindent() if isinstance(node.body, ast.Stmt): for child in node.body.nodes: self._stmt(child) else: raise TranslationError("unsupported type (in _while)", node.body) self.deindent() print >>self.output,self.indent, "}" def _const(self, node): if isinstance(node.value, int): return str(node.value) elif isinstance(node.value, float): return str(node.value) elif isinstance(node.value, str): return "'" + node.value.encode('string_escape') + "'" elif node.value is None: return "null" else: raise TranslationError("unsupported type (in _const)", node) def _unarysub(self, node): return "-" + self.expr(node.expr) def _add(self, node): return self.expr(node.left) + " + " + self.expr(node.right) def _sub(self, node): return self.expr(node.left) + " - " + self.expr(node.right) def _div(self, node): return self.expr(node.left) + " / " + self.expr(node.right) def _mul(self, node): return self.expr(node.left) + " * " + self.expr(node.right) def _mod(self, node): return self.expr(node.left) + " % " + self.expr(node.right) def _invert(self, node): return "~" + self.expr(node.expr) def _bitand(self, node): return " & ".join([self.expr(child) for child in node.nodes]) def _bitor(self, node): return " | ".join([self.expr(child) for child in node.nodes]) def _subscript(self, node): if node.flags == "OP_APPLY": if len(node.subs) == 1: return self.expr(node.expr) + ".__getitem__(" + self.expr(node.subs[0]) + ")" else: raise TranslationError("must have one sub (in _subscript)", node) else: raise TranslationError("unsupported flag (in _subscript)", node) def _list(self, node): return "{" + ", ".join([self.expr(x) for x in node.nodes]) + "};" def _global(self, node): for name in node.names: if name in self.globalVars: continue else: self.globalVars.append(name) type = "int " if name.find("long") > -1: type = "long " print >>self.output,self.indent, type," ",name,";" def _name(self, v, return_none_for_module=False): if v.name == "True": return "true" elif v.name == "False": return "false" elif v.name == "None": return "null" else: return v.name def expr(self, node): if isinstance(node, ast.Const): return self._const(node) elif isinstance(node, ast.Mul): return " ( " + self._mul(node) + " ) " elif isinstance(node, ast.Add): return " ( " + self._add(node) + " ) " elif isinstance(node, ast.Sub): return " ( " + self._sub(node) + " ) " elif isinstance(node, ast.Div): return " ( " + self._div(node) + " ) " elif isinstance(node, ast.Mod): return self._mod(node) elif isinstance(node, ast.UnarySub): return self._unarysub(node) elif isinstance(node, ast.Not): return self._not(node) elif isinstance(node, ast.Or): return self._or(node) elif isinstance(node, ast.And): return self._and(node) elif isinstance(node, ast.Invert): return self._invert(node) elif isinstance(node, ast.Bitand): return self._bitand(node) elif isinstance(node, ast.Bitor): return self._bitor(node) elif isinstance(node, ast.Compare): return self._compare(node) elif isinstance(node, ast.CallFunc): return self._callfunc(node) elif isinstance(node, ast.Name): return self._name(node) elif isinstance(node, ast.Subscript): return self._subscript(node) elif isinstance(node, ast.Getattr): return self._getattr(node) elif isinstance(node, ast.List): return self._list(node) elif isinstance(node, ast.Dict): return self._dict(node) elif isinstance(node, ast.Tuple): return self._tuple(node) elif isinstance(node, ast.Slice): return self._slice(node) else: raise TranslationError("unsupported type (in expr)", node) def translate(fileName): output = cStringIO.StringIO() mod = compiler.parseFile(fileName) t = Translator(mod, output) return output.getvalue() if __name__ == "__main__": print translate(sys.argv[1])