From 1a550e4a496775f709752f3315728de48709b896 Mon Sep 17 00:00:00 2001 From: SWG Master Date: Sun, 2 Aug 2015 11:38:07 -0500 Subject: [PATCH] add missing files --- .gitignore | 3 - utils/mocha/.gitignore | 10 + utils/mocha/README.md | 49 + utils/mocha/build_java.sh | 18 + utils/mocha/build_java_single.sh | 9 + utils/mocha/mocha/__init__.py | 76 ++ utils/mocha/mocha/crc.py | 56 + utils/mocha/mocha/generator.py | 1038 +++++++++++++++++ utils/mocha/mocha/model.py | 493 ++++++++ utils/mocha/mocha/parser.py | 1336 ++++++++++++++++++++++ utils/mocha/mocha/visit.py | 50 + utils/mocha/parse_expr.py | 14 + utils/mocha/parse_file.py | 14 + utils/mocha/parse_stmt.py | 14 + utils/mocha/prepare_all_scripts.sh | 29 + utils/mocha/script_prep | 31 + utils/mocha/script_prep2.py | 60 + utils/mocha/test/comments.script | 12 + utils/mocha/test/empty.script | 0 utils/mocha/test/for.script | 8 + utils/mocha/test/function.script | 4 + utils/mocha/test/if_else.script | 29 + utils/mocha/test/includes.script | 22 + utils/mocha/test/simple_statement.script | 8 + utils/mocha/test/switch.script | 13 + utils/mocha/test/while.script | 9 + utils/mocha/test_all_scripts.sh | 15 + utils/mocha/test_script.py | 13 + utils/mocha/tokenizer.py | 14 + 29 files changed, 3444 insertions(+), 3 deletions(-) create mode 100644 utils/mocha/.gitignore create mode 100644 utils/mocha/README.md create mode 100755 utils/mocha/build_java.sh create mode 100755 utils/mocha/build_java_single.sh create mode 100644 utils/mocha/mocha/__init__.py create mode 100644 utils/mocha/mocha/crc.py create mode 100644 utils/mocha/mocha/generator.py create mode 100644 utils/mocha/mocha/model.py create mode 100644 utils/mocha/mocha/parser.py create mode 100644 utils/mocha/mocha/visit.py create mode 100755 utils/mocha/parse_expr.py create mode 100755 utils/mocha/parse_file.py create mode 100755 utils/mocha/parse_stmt.py create mode 100755 utils/mocha/prepare_all_scripts.sh create mode 100755 utils/mocha/script_prep create mode 100755 utils/mocha/script_prep2.py create mode 100644 utils/mocha/test/comments.script create mode 100644 utils/mocha/test/empty.script create mode 100644 utils/mocha/test/for.script create mode 100644 utils/mocha/test/function.script create mode 100644 utils/mocha/test/if_else.script create mode 100644 utils/mocha/test/includes.script create mode 100644 utils/mocha/test/simple_statement.script create mode 100644 utils/mocha/test/switch.script create mode 100644 utils/mocha/test/while.script create mode 100755 utils/mocha/test_all_scripts.sh create mode 100755 utils/mocha/test_script.py create mode 100755 utils/mocha/tokenizer.py diff --git a/.gitignore b/.gitignore index 7198f1def..c3893a59b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,12 +6,9 @@ config .setup *.log default-configs -utils/mocha -mocha build*/ data exe -utils/mocha lextab.py yacctab.py ibm*/ diff --git a/utils/mocha/.gitignore b/utils/mocha/.gitignore new file mode 100644 index 000000000..3abf1c7cc --- /dev/null +++ b/utils/mocha/.gitignore @@ -0,0 +1,10 @@ +lextab.py +yacctab.py +parser.out +*.pyc +script +*.txt +*.log +*.java + +scratch.script diff --git a/utils/mocha/README.md b/utils/mocha/README.md new file mode 100644 index 000000000..e57d4e0d6 --- /dev/null +++ b/utils/mocha/README.md @@ -0,0 +1,49 @@ +# mocha - A .script to .java translator + +This utility uses the [PLY (Python Lex-Yacc)](http://www.dabeaz.com/ply/) library to generate .java files from .script file inputs. To install this library on debian based systems run the following command: + + sudo apt-get install python-ply + +# parse_expr.py - Parse debugging utility/example + +This tool will parse any expression given to it and print out a string representation of the AST. + + ./parse_expr.py 'a + ++(++1 * 2++)' + +# script_prep.py - Primary code generation tool + +This translator will accept .script or .scriptlib filenames via the -i flag and generate the .java file via stdout. + + ./script_prep.py -i ./filename.script + ./script_prep.py -i ./library.scriptlib + +Alternatively an -o flag can be given to specify a custom output target. + + ./script_prep.py -i ./src/file.script -o ./built/file.java + + +# Design Goals + +In addition to serving as an important tool for the SWGNext's scripting system, this script serves as a learning tool for the author in language parsing. With that in mind a few notes about the overall design and intent will be kept here for reference. + + +The first phase of translation is turning the .script or .scriptlib file into a series of "tokens" using the ScriptLexer class. Consider the following simple bit of code: + + int a = 5; + +The output from the script lexer would be a list of 8 tokens: + + INT, 'int' + WS, ' ' + ID, 'a' + WS, ' ' + EQ, '=' + WS, ' ' + NUM, '5' + SEMI, ';' + +This stream of tokens is then fed into the ScriptParser class which builds a tree of logical constructs held in a ScriptAST. + +@TODO: More information here about how ScriptParser generates an AST and what an AST is in laymens terms. + +Finally, the generated AST is passed to the JavaGenerator class which turns it into .java code that can then be either dumped to stdout or a specied file target. diff --git a/utils/mocha/build_java.sh b/utils/mocha/build_java.sh new file mode 100755 index 000000000..a7180fe38 --- /dev/null +++ b/utils/mocha/build_java.sh @@ -0,0 +1,18 @@ +#/bin/bash + +destination="tmp2" +sourcepath="tmp" + +mkdir -p $destination/script + +for filename in $(find $sourcepath -name '*.java'); do + ok=1 + + javac -classpath "$destination" -d "$destination" -sourcepath "$sourcepath" -g -deprecation "$filename" || ok=0 + + if [ $ok -eq 1 ]; then + echo -n . + else + echo "$filename" + fi +done diff --git a/utils/mocha/build_java_single.sh b/utils/mocha/build_java_single.sh new file mode 100755 index 000000000..4c2d235af --- /dev/null +++ b/utils/mocha/build_java_single.sh @@ -0,0 +1,9 @@ +#/bin/bash + +destination="tmp2" +sourcepath="tmp" + +mkdir -p $destination/script + +javac -classpath "$destination" -d "$destination" -sourcepath "$sourcepath" -g -deprecation "$1" + diff --git a/utils/mocha/mocha/__init__.py b/utils/mocha/mocha/__init__.py new file mode 100644 index 000000000..249c63da8 --- /dev/null +++ b/utils/mocha/mocha/__init__.py @@ -0,0 +1,76 @@ + +import getopt, sys, string + +def parse_input(args): + """Returns a the input and output filenames based on sys.argv input.""" + ifilename = '' + ofilename = '' + + try: + opts, args = getopt.getopt(args, "hi:o:", ["ifile=", "ofile="]) + except getopt.GetoptError: + print_help() + sys.exit(2) + + for opt, arg in opts: + if opt == "-h": + print_help() + sys.exit() + elif opt in ("-i", "--ifile"): + ifilename = arg + elif opt in ("-o", "--ofile"): + ofilename = arg + + if ifilename == "": + print_help() + sys.exit(2) + + return (ifilename, ofilename) + +def print_help(): + print "script_prep.py -i [-o ]" + +def write_output(ofilename, output): + with open(ofilename, "w") as java_file: + java_file.write(output) + +def build_package_name(filename): + filename = filename.replace(".scriptlib", "") + filename = filename.replace(".script", "") + + pos = filename.find("script/") + if pos >= 0: + filename = filename[pos:] + elif filename[0] == "/": + filename = filename[1:] + elif filename[0] == ".": + filename = filename[2:] + + pos = filename.rfind("/") + filename = filename[:pos] + + filename = filename.replace("/", ".") + + return filename + +def build_class_name(filename): + filename = filename.replace(".scriptlib", "") + filename = filename.replace(".script", "") + pos = filename.rfind("/") + filename = filename[pos+1:] + return filename + +def get_script_base(filename): + pos = filename.find("script/") + + if pos > 0: + return filename[:pos] + if pos == 0: + return "." + + return "" + + + +def is_library(filename): + return filename.find(".scriptlib") > 0 diff --git a/utils/mocha/mocha/crc.py b/utils/mocha/mocha/crc.py new file mode 100644 index 000000000..c86251adb --- /dev/null +++ b/utils/mocha/mocha/crc.py @@ -0,0 +1,56 @@ + +import ctypes, sys + +crctable = [ + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, + 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, + 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, + 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, + 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, + 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, + 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, + 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, + 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, + 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, + 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, + 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, + 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, + 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, + 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, + 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, + 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, + 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, + 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, + 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, + 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, + 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, + 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, + 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, + 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, + 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, + 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, + 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, + 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, + 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, + 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 +] + +def calculate(string): + if string == "": + return 0 + allf = 0xFFFFFFFF + crc_init = 0xFFFFFFFF + crc = crc_init + + for c in string: + crc = crctable[((crc >> 24) ^ ord(c)) & 255] ^ (crc << 8) & allf + + return ctypes.c_long(crc ^ crc_init).value + +if __name__ == "__main__": + if len(sys.argv) == 1: + print('''usage: mocha/crc.py ... + Example: mocha/crc.py "hello" ''') + sys.exit(1) + print calculate(sys.argv[1]) diff --git a/utils/mocha/mocha/generator.py b/utils/mocha/mocha/generator.py new file mode 100644 index 000000000..cdcd67b9c --- /dev/null +++ b/utils/mocha/mocha/generator.py @@ -0,0 +1,1038 @@ + +import sys + +from .model import * + +import crc +import visit as v + + +class ScopeStack(object): + def __init__(self): + self._stack = [{"functions": dict(), "variables": dict()}] + self._last_function = dict() + + def push_scope(self): + self._stack.append({"functions": dict(), "variables": dict()}) + + def pop_scope(self): + assert len(self._stack) >= 1 + self._stack.pop() + + def depth(self): + return len(self._stack) - 1 + + def add_function(self, name, return_type, resizeable=False): + self._stack[-1]["functions"][name] = {"return_type": return_type, "resizeable": resizeable} + + def add_variable(self, name, _type, resizeable=False): + self._stack[-1]["variables"][name] = {"type": _type, "resizeable": resizeable} + + def get_function_data(self, func_name): + for s in reversed(self._stack): + if func_name in s["functions"].keys(): + return s["functions"][func_name] + + return None + + def get_enclosing_function(self): + return self._last_function + + def get_variable_data(self, var_name): + for s in reversed(self._stack): + if var_name in s["variables"].keys(): + return s["variables"][var_name] + + return None + + +class JavaClassGenerator(object): + def __init__(self): + self._scope_stack = ScopeStack() + + def generate(self, package_name, class_name, ast, functions): + if type(ast) is not CompilationUnit: + return "" + + self._scope_stack._stack[-1]["functions"] = functions + self.package_name = package_name + self.class_name = class_name + + if class_name == "base_script": + self.inherits = "script.base_class" + else: + self.inherits = "script.base_script" + + self.indention = 4 + + self._add_global_scope_functions(ast) + + s = ast.accept(self) + + self._scope_stack.pop_scope() + + s += self._generate_class_footer() + + return s + + @v.on('model') + def visit(self, model): + return "%s" % model + + @v.when(Additive) + def visit(self, model): + return "%s %s %s" % (self.visit(model.lhs), model.operator, self.visit(model.rhs)) + + @v.when(ArrayAccess) + def visit(self, model): + varname = self.visit(model.target) + vspec = self._scope_stack.get_variable_data(varname) + + if vspec is not None and vspec["resizeable"]: + _type = self.visit(vspec["type"].name) + + if _type == "int": + return "((Integer)%s.get(%s)).intValue()" % (varname, self.visit(model.index)) + elif _type == "float": + return "((Float)%s.get(%s)).floatValue()" % (varname, self.visit(model.index)) + elif _type == "boolean": + return "((Boolean)%s.get(%s)).booleanValue()" % (varname, self.visit(model.index)) + else: + return "((%s)%s.get(%s))" % (_type, varname, self.visit(model.index)) + else: + return "%s[%s]" % (self.visit(model.target), self.visit(model.index)) + + @v.when(ArrayCreation) + def visit(self, model): + if type(model.type) is str: + s = "new %s" % model.type + else: + s = "new %s" % self.visit(model.type.name) + + for d in model.dimensions: + if d is None: + s += "[]" + else: + s += "[%s]" % self.visit(d) + + if model.initializer is not None: + s += "%s" % self.visit(model.initializer) + + return s + + @v.when(ArrayInitializer) + def visit(self, model): + s = "\n" + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + for i, e in enumerate(model.elements): + s += self._indent() + self.visit(e) + + if i + 1 < len(model.elements): + s += "," + + s += "\n" + + self._scope_stack.pop_scope() + + s += self._indent() + "}" + + return "%s" % s + + @v.when(Assignment) + def visit(self, model): + s = "" + + if type(model.lhs) is Name and type(model.rhs) is Name: + if self._is_resizeable(model.rhs.value) and not self._is_resizeable(model.lhs.value): + to_spec = self._scope_stack.get_variable_data(model.lhs.value) + to_type = self.visit(to_spec["type"].name) + + s = "if (%s != null)\n" % model.rhs.value + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s = new %s[%s.size()];\n" % (model.lhs.value, to_type, model.rhs.value) + + if to_type == "int": + s += self._indent() + "for (int _i = 0; _i < %s.size(); ++_i)\n" % model.rhs.value + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s[_i] = ((Integer)%s.get(_i)).intValue();\n" % (model.lhs.value, model.rhs.value) + + self._scope_stack.pop_scope() + + s += self._indent() + "}\n" + + else: + s += self._indent() + "%s.toArray(%s);\n" % (model.rhs.value, model.lhs.value) + + self._scope_stack.pop_scope() + + s += "\n" + s += self._indent() + "}" + + if self._is_resizeable(model.lhs.value) and not self._is_resizeable(model.rhs.value): + s = "%s = new Vector(Arrays.asList(%s))" % (model.lhs.value, model.rhs.value) + + if type(model.lhs) is ArrayAccess and self._is_resizeable(self.visit(model.lhs.target)): + #print "%s" % model.lhs.target + to_spec = self._scope_stack.get_variable_data(self.visit(model.lhs.target)) + to_type = self.visit(to_spec["type"].name) + + if to_type == "int": + s = "%s.set(%s, new Integer(%s))" % (self.visit(model.lhs.target), self.visit(model.lhs.index), self.visit(model.rhs)) + elif to_type == "float": + s = "%s.set(%s, new Float(%s))" % (self.visit(model.lhs.target), self.visit(model.lhs.index), self.visit(model.rhs)) + else: + s = "%s.set(%s, %s)" % (self.visit(model.lhs.target), self.visit(model.lhs.index), self.visit(model.rhs)) + + if s == "": + s = "%s %s %s" % (self.visit(model.lhs), model.operator, self.visit(model.rhs)) + + return s + + @v.when(BinaryExpression) + def visit(self, model): + return "%s %s %s" % (self.visit(model.lhs), model.operator, self.visit(model.rhs)) + + @v.when(Block) + def visit(self, model): + s = "\n" + + if model.wrap: + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + for stmt in model.statements: + s += "%s" % self.visit(stmt) + + if model.wrap: + self._scope_stack.pop_scope() + + s += self._indent() + "}" + + return s + + @v.when(BlockStatement) + def visit(self, model): + return self._indent() + "%s\n" % self.visit(model.statement) + + @v.when(Break) + def visit(self, model): + return "break;" + + @v.when(Cast) + def visit(self, model): + if "resizeable" in model.modifiers: + return "(Vector)%s" % self.visit(model.expression) + else: + return "(%s)%s" % (self.visit(model.target), self.visit(model.expression)) + + @v.when(Catch) + def visit(self, model): + s = "\n%scatch(" % self._indent() + + for m in model.modifiers: + s += self._build_modifier(m) + + s += "%s " % self.visit(model.type) + + s += model.variable.name + + s += ")" + s += "%s" % self.visit(model.block) + + return s + + @v.when(CompilationUnit) + def visit(self, model): + s = "package %s;\n\n" % self.package_name + s += "import script.*;\n" + s += "import script.base_class.*;\n" + s += "import script.combat_engine.*;\n" + s += "import java.util.Arrays;\n" + s += "import java.util.Hashtable;\n" + s += "import java.util.Vector;\n" + s += "import script.base_script;\n\n" + + self.include_count = len(model.includes) + + if model.inherits is not None: + self.inherits = "script." + model.inherits.name.value + + if self.include_count is 0: + s += self._generate_class_header() + + for include in model.includes: + s += self.visit(include) + + for statement in model.statements: + s += self.visit(statement) + + return s + + @v.when(Conditional) + def visit(self, model): + return "%s ? %s : %s" % (self.visit(model.predicate), self.visit(model.if_true), self.visit(model.if_false)) + + @v.when(Continue) + def visit(self, model): + return "continue;" + + @v.when(CrcString) + def visit(self, model): + return "(%s)" % crc.calculate(model.string.lower().replace('"', '')) + + @v.when(DoWhile) + def visit(self, model): + s = "do" + + s += self.visit(model.body) + s += " while (%s);" % self.visit(model.predicate) + + return s + + @v.when(Empty) + def visit(self, model): + return "" + + @v.when(Equality) + def visit(self, model): + s = "" + if type(model.lhs) is Name: + vspec = self._scope_stack.get_variable_data(model.lhs.value) + if vspec is not None: + _type = self.visit(vspec["type"].name) + rhs = self.visit(model.rhs) + + if (_type == "String" or _type == "dictionary" or _type == "string_id" or _type == "location") and rhs != "null": + s = "" + if model.operator == "!=": + s += "!" + + s += "%s.equals(%s)" % (self.visit(model.lhs), self.visit(model.rhs)) + + if type(model.lhs) is ArrayAccess: + vspec = self._scope_stack.get_variable_data(self.visit(model.lhs.target)) + if vspec is not None: + _type = self.visit(vspec["type"].name) + rhs = self.visit(model.rhs) + + if (_type == "String" or _type == "dictionary" or _type == "string_id" or _type == "location") and rhs != "null": + s = "" + if model.operator == "!=": + s += "!" + + s += "%s.equals(%s)" % (self.visit(model.lhs), self.visit(model.rhs)) + + + if s == "": + s = "%s %s %s" % (self.visit(model.lhs), model.operator, self.visit(model.rhs)) + + return s + + @v.when(FieldAccess) + def visit(self, model): + return "%s.%s" % (self.visit(model.target), model.name) + + @v.when(For) + def visit(self, model): + init = "" + predicate = "" + update = "" + + if model.init is not None: + if type(model.init) is list: + for i, _init in enumerate(model.init): + init += "%s" % self.visit(_init) + + if i + 1 < len(model.init): + init += ", " + else: + init = "%s" % self.visit(model.init) + if model.predicate is not None: + predicate = "%s" % self.visit(model.predicate) + if model.update is not None: + for i, u in enumerate(model.update): + update += "%s" % self.visit(u) + + if i + 1 < len(model.update): + update += ", " + + s = "for (%s; %s; %s)" % (init, predicate, update) + + if type(model.body) is Block: + s += self.visit(model.body) + else: + s += "\n" + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s" % self.visit(model.body) + + self._scope_stack.pop_scope() + + s += "\n" + s += self._indent() + "}" + + return s + + @v.when(FormalParameter) + def visit(self, model): + s = "" + + for m in model.modifiers: + s += self._build_modifier(m) + + if "resizeable" in model.modifiers: + s += "Vector " + else: + s += "%s " % self.visit(model.type) + + s += model.variable.name + s += self._build_dimensions(model.variable.dimensions) + return s + + @v.when(FunctionDeclaration) + def visit(self, model): + return_type = self.visit(model.return_type) + if return_type == "commandHandler": + model = self._build_commandHandler_declaration(model) + elif return_type == "messageHandler": + model = self._build_messageHandler_declaration(model) + elif return_type == "trigger": + model = self._build_trigger_declaration(model) + + return self._build_function_declaration(model) + + + @v.when(IfThenElse) + def visit(self, model): + s = "if (%s)" % self.visit(model.predicate) + + if model.if_true is not None: + s += "%s" % self.visit(model.if_true) + + if model.if_false is not None: + s += "\n" + s += self._indent() + "else " + if type(model.if_false) is not IfThenElse and type(model.if_false) is not Block: + s += "\n" + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s" % self.visit(model.if_false) + + self._scope_stack.pop_scope() + + s += "\n" + s += self._indent() + "}" + + else: + s += "%s" % self.visit(model.if_false) + + return s + + @v.when(IncludeDeclaration) + def visit(self, model): + on_demand = ".*" if model.on_demand else "" + + if model.name.value[:4] == "java": + s = "import %s%s;\n" % (model.name.value, on_demand) + else: + s = "import script.%s%s;\n" % (model.name.value, on_demand) + + self.include_count -= 1 + + if self.include_count is 0: + s += "\n" + s += self._generate_class_header() + + return s + + @v.when(InstanceCreation) + def visit(self, model): + s = "new %s(" % self.visit(model.type) + + for i, a in enumerate(model.arguments): + s += "%s" % self.visit(a) + + if i + 1 < len(model.arguments): + s += ", " + + s += ")" + + return s + + @v.when(InstanceOf) + def visit(self, model): + _type = self.visit(model.rhs) + if _type == "int": + return "%s instanceof Integer" % self.visit(model.lhs) + elif _type == "float": + return "%s instanceof Float" % self.visit(model.lhs) + else: + return "%s instanceof %s" % (self.visit(model.lhs), _type) + + @v.when(Literal) + def visit(self, model): + return model.literal + + @v.when(MethodInvocation) + def visit(self, model): + if model.target is not None: + if type(model.target) is not Name and type(model.target) is not ArrayAccess and type(model.target) is not str: + s = "(%s).%s" % (self.visit(model.target), model.name) + else: + s = "%s.%s" % (self.visit(model.target), model.name) + else: + s = model.name + + s += "(" + + for i, a in enumerate(model.arguments): + s += "%s" % self.visit(a) + + if i + 1 < len(model.arguments): + s += ", " + + s += ")" + + return s + + @v.when(Name) + def visit(self, model): + if model.value == "string": + model.value = "String" + + if "." in model.value: + tmp = model.value.split(".") + + if self._is_resizeable(tmp[0]) and tmp[1] == "length": + return "%s.size()" % tmp[0] + + return model.value + + @v.when(Precidence) + def visit(self, model): + return "(%s)" % self.visit(model.expression) + + @v.when(Return) + def visit(self, model): + s = "" + if model.result is not None: + enclosing_func = self._scope_stack.get_enclosing_function() + + if type(model.result) is Name and self._is_resizeable(model.result.value) and not enclosing_func["resizeable"] and not self.visit(enclosing_func["return_type"].name) == "Vector": + varname = model.result.value + s = self._build_resizeable_conversion_to_type("_%s" % varname, self.visit(enclosing_func["return_type"].name), varname) + s += "\n" + s += self._indent() + "return _%s;" % varname + else: + s = "return %s;" % self.visit(model.result) + else: + s += "return;" + + return s + + @v.when(StatementExpression) + def visit(self, model): + s = "%s" % self.visit(model.expression) + if not ";\n" in s: + s += ";" + + return s + + @v.when(Switch) + def visit(self, model): + s = "switch (%s)\n" % self.visit(model.expression) + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + for c in model.switch_cases: + s += "%s" % self.visit(c) + + self._scope_stack.pop_scope() + + s += self._indent() + "}" + return s + + @v.when(SwitchCase) + def visit(self, model): + s = "" + + for c in model.cases: + if c == "default": + s += self._indent() + "default:\n" + else: + s += self._indent() + "case %s:\n" % self.visit(c) + + for stmt in model.body: + s += "%s" % self.visit(stmt) + + return s + + @v.when(Throw) + def visit(self, model): + return "throw %s;" % self.visit(model.expression) + + @v.when(Try) + def visit(self, model): + s = "try" + + s += "%s" % self.visit(model.block) + + for c in model.catches: + s += "%s" % self.visit(c) + + return s + + @v.when(Type) + def visit(self, model): + s = "" + + if type(model.name) is str: + s += "%s" % model.name + else: + name = self.visit(model.name) + + if name == "unknown": + name = "Object" + + s += "%s" % name + + s += "%s" % self._build_dimensions(model.dimensions) + + return s + + @v.when(Unary) + def visit(self, model): + if model.sign == "x++": + return "%s%s" % (self.visit(model.expression), "++") + elif model.sign == "x--": + return "%s%s" % (self.visit(model.expression), "--") + elif model.sign == "++x": + return "%s%s" % ("++", self.visit(model.expression)) + elif model.sign == "--x": + return "%s%s" % ("--", self.visit(model.expression)) + else: + #return "%s" % model.sign + return "%s%s" % (model.sign, self.visit(model.expression)) + + @v.when(VariableDeclarator) + def visit(self, model): + variable = model.variable.name + dimensions = self._build_dimensions(model.variable.dimensions) + initializer = "" + if model.initializer is not None: + initializer = " = %s" % self.visit(model.initializer) + + return "%s%s%s" % (variable, dimensions, initializer) + + @v.when(VariableDeclaration) + def visit(self, model): + if "resizeable" in model.modifiers or (len(model.variable_declarators) == 1 and type(model.variable_declarators[0].initializer) is Name and self._is_resizeable(model.variable_declarators[0].initializer.value)): + return self._visit_resizeable_declaration(model) + + s = "" + + if self._scope_stack.depth() == 1: + s += "public static " + + + for m in model.modifiers: + s += self._build_modifier(m) + + s += "%s " % self.visit(model.type) + + for i, d in enumerate(model.variable_declarators): + self._scope_stack.add_variable(d.variable.name, model.type, True if "resizeable" in model.modifiers else False) + + s += self.visit(d) + + if i + 1 < len(model.variable_declarators): + s += ", " + + return "%s" % s + + @v.when(VariableDeclarationStatement) + def visit(self, model): + s = "%s" % self.visit(model.statement) + if not ";\n" in s: + s += ";" + + return s + + @v.when(While) + def visit(self, model): + s = "while (%s)" % self.visit(model.predicate) + + if model.body is not None: + s += self.visit(model.body) + else: + s += ";" + + return s + + def _build_dimensions(self, count): + dimensions = "" + while count > 0: + dimensions += "[]" + count -= 1 + return dimensions + + def _build_modifier(self, modifier): + if modifier == "const": + modifier = "final" + + if modifier == "resizeable": + return "" + + return "%s " % modifier + + def _build_commandHandler_declaration(self, model): + model.return_type = Type(name=Name(value='int'), enclosed_in=None, dimensions=0) + + prepend = [ + FormalParameter(variable=Variable(name='self', dimensions=0), type=Type(name=Name(value='obj_id'), enclosed_in=None, dimensions=0), modifiers=[]), + FormalParameter(variable=Variable(name='target', dimensions=0), type=Type(name=Name(value='obj_id'), enclosed_in=None, dimensions=0), modifiers=[]), + FormalParameter(variable=Variable(name='params', dimensions=0), type=Type(name=Name(value='string'), enclosed_in=None, dimensions=0), modifiers=[]), + FormalParameter(variable=Variable(name='defaultTime', dimensions=0), type=Type(name=Name(value='float'), enclosed_in=None, dimensions=0), modifiers=[]) + ] + + model.parameters = prepend + model.parameters + + return model + + def _build_messageHandler_declaration(self, model): + model.return_type = Type(name=Name(value='int'), enclosed_in=None, dimensions=0) + + prepend = [ + FormalParameter(variable=Variable(name='self', dimensions=0), type=Type(name=Name(value='obj_id'), enclosed_in=None, dimensions=0), modifiers=[]), + FormalParameter(variable=Variable(name='params', dimensions=0), type=Type(name=Name(value='dictionary'), enclosed_in=None, dimensions=0), modifiers=[]) + ] + + model.parameters = prepend + model.parameters + + return model + + def _build_trigger_declaration(self, model): + model.return_type = Type(name=Name(value='int'), enclosed_in=None, dimensions=0) + + prepend = [ + FormalParameter(variable=Variable(name='self', dimensions=0), type=Type(name=Name(value='obj_id'), enclosed_in=None, dimensions=0), modifiers=[]) + ] + + model.parameters = prepend + model.parameters + + return model + + def _build_function_pre_declaration(self): + return self._indent() + "public " + + def _build_function_declaration(self, model): + self._scope_stack._last_function["name"] = model.name + self._scope_stack._last_function["return_type"] = model.return_type + self._scope_stack._last_function["resizeable"] = True if "resizeable" in model.modifiers else False + + s = self._build_function_pre_declaration() + + if "resizeable" in model.modifiers: + s += "Vector %s(" % model.name + else: + for m in model.modifiers: + s += self._build_modifier(m) + + s += "%s %s(" % (self.visit(model.return_type), model.name) + + append_stack = dict() + + for i, p in enumerate(model.parameters): + append_stack[p.variable.name] = { + "type": p.type, + "resizeable": True if "resizeable" in p.modifiers else False + } + + s += "%s" % self.visit(p) + + if i + 1 < len(model.parameters): + s += ", " + + s += ") throws InterruptedException\n" + + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + self._scope_stack._stack[-1]["variables"].update(append_stack) + + + for stmt in model.body: + s += "%s" % self.visit(stmt) + + self._scope_stack.pop_scope() + + s += self._indent() + "}\n" + + return s + + def _generate_class_header(self): + s = self._indent() + "public class %s extends %s\n" % (self.class_name, self.inherits) + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "public %s()\n" % self.class_name + s += self._indent() + "{\n" + s += self._indent() + "}\n" + + return s + + def _generate_class_footer(self): + s = "}\n" + + return s + + def _indent(self): + return " " * (self.indention * self._scope_stack.depth()) + + def _add_global_scope_functions(self, ast): + for stmt in ast.statements: + if type(stmt) is FunctionDeclaration: + self._scope_stack.add_function(stmt.name, stmt.return_type, True if "resizeable" in stmt.modifiers else False) + + + ### Resizeable handling ### + + def _visit_resizeable_declaration(self, model): + self._scope_stack.add_variable(model.variable_declarators[0].variable.name, model.type, True if "resizeable" in model.modifiers else False) + + if len(model.variable_declarators) > 1: + raise Exception("Too many declarators in resizeable declaration") + + decl = model.variable_declarators[0] + + if type(decl.initializer) is Name and self._is_resizeable(decl.initializer.value) and not self._is_resizeable(decl.variable.name): + #vdata = self._scope_stack.get_variable_data(decl.variable.name) + #return "%s t %s" % (decl.variable.name, vdata["type"]) + return self._build_resizeable_conversion_to_type(decl.variable.name, self.visit(model.type.name), decl.initializer.value) + + if type(model.variable_declarators[0].initializer) is ArrayCreation: + return self._handle_resizeable_ArrayCreation(model) + if type(model.variable_declarators[0].initializer) is Cast: + return self._handle_resizeable_Cast(model) + if type(model.variable_declarators[0].initializer) is Conditional: + return self._handle_resizeable_Conditional(model) + if type(model.variable_declarators[0].initializer) is InstanceCreation: + return self._handle_resizeable_InstanceCreation(model) + if type(model.variable_declarators[0].initializer) is Literal: + return self._handle_resizeable_Literal(model) + if type(model.variable_declarators[0].initializer) is MethodInvocation: + return self._handle_resizeable_MethodInvocation(model) + if type(model.variable_declarators[0].initializer) is Name: + return self._handle_resizeable_Name(model) + if model.variable_declarators[0].initializer is None: + return self._handle_resizeable_Init(model) + return "%s" % model + + def _handle_resizeable_ArrayCreation(self, model): + name = model.variable_declarators[0].variable.name + length = self.visit(model.variable_declarators[0].initializer.dimensions[0]) + + if length is None: + length = 0 + + s = "Vector %s = new Vector();\n" % name + s += self._indent() + "%s.setSize(%s);" % (name, length) + + return s + + def _handle_resizeable_Cast(self, model): + name = model.variable_declarators[0].variable.name + cast = model.variable_declarators[0].initializer + + if self._is_resizeable(name): + if "resizeable" in cast.modifiers: + return "Vector %s = new Vector(Arrays.asList((%s)%s))" % (name, self.visit(cast.target), self.visit(cast.expression)) + else: + return "Vector %s = %s" % (name, self.visit(cast)) + + return "%s" % model + + def _handle_resizeable_Conditional(self, model): + name = model.variable_declarators[0].variable.name + return "Vector %s = %s" % (name, self.visit(model.variable_declarators[0].initializer)) + + def _handle_resizeable_InstanceCreation(self, model): + name = model.variable_declarators[0].variable.name + _type = model.variable_declarators[0].initializer.type.name.value + + if _type == "Vector": + return "Vector %s = new Vector()" % name + else: + return "%s" % model + + def _handle_resizeable_Literal(self, model): + name = model.variable_declarators[0].variable.name + literal = model.variable_declarators[0].initializer.literal + + if literal == "null": + return "Vector %s = null" % name + else: + return "%s" % model + + def _handle_resizeable_MethodInvocation(self, model): + name = model.variable_declarators[0].variable.name + method_invocation = model.variable_declarators[0].initializer + + s = "" + + fspec = self._scope_stack.get_function_data(method_invocation.name) + + if fspec is None: + s += "Vector %s = %s" % (name, self.visit(method_invocation)) + else: + if fspec["resizeable"] is True or (type(fspec["return_type"]) is Type and fspec["return_type"].name.value == "Vector"): + s += "Vector %s = %s" % (name, self.visit(method_invocation)) + else: + s += "%s" % model + + return s + + def _handle_resizeable_Name(self, model): + name = model.variable_declarators[0].variable.name + varname = model.variable_declarators[0].initializer.value + + vspec = self._scope_stack.get_variable_data(varname) + + if vspec["resizeable"] is True or vspec["type"].name.value == "Vector": + s = "Vector %s = %s" % (name, varname) + else: + to_type = self.visit(vspec["type"].name) + + if to_type == "int": + s = "Vector %s = new Vector();\n" % (name) + s += self._indent() + "if (%s != null)\n" % (name) + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s.setSize(%s.length);\n" % (name, varname) + s += self._indent() + "for (int _i = 0; _i < %s.length; ++_i)\n" % (varname) + + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s.set(_i, new Integer(%s[_i]));\n" % (name, varname) + + self._scope_stack.pop_scope() + + s += self._indent() + "}\n" + + self._scope_stack.pop_scope() + + s += self._indent() + "}" + + elif to_type == "float": + s = "Vector %s = new Vector();\n" % (name) + s += self._indent() + "if (%s != null)\n" % (name) + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s.setSize(%s.length);\n" % (name, varname) + s += self._indent() + "for (int _i = 0; _i < %s.length; ++_i)\n" % (varname) + + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s.set(_i, new Float(%s[_i]));\n" % (name, varname) + + self._scope_stack.pop_scope() + + s += self._indent() + "}\n" + + self._scope_stack.pop_scope() + + s += self._indent() + "}" + + else: + s = "Vector %s = new Vector(Arrays.asList(%s))" % (name, varname) + + return s + + def _handle_resizeable_Init(self, model): + name = model.variable_declarators[0].variable.name + return "Vector %s" % name + + def _build_resizeable_conversion_to_type(self, to_name, to_type, from_name): + s = "%s[] %s = new %s[0];\n" % (to_type, to_name, to_type) + s += self._indent() + "if (%s != null)\n" % from_name + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s = new %s[%s.size()];\n" % (to_name, to_type, from_name) + + if to_type == "int": + s += self._indent() + "for (int _i = 0; _i < %s.size(); ++_i)\n" % from_name + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s[_i] = ((Integer)%s.get(_i)).intValue();\n" % (to_name, from_name) + + self._scope_stack.pop_scope() + + s += self._indent() + "}\n" + elif to_type == "float": + s += self._indent() + "for (int _i = 0; _i < %s.size(); ++_i)\n" % from_name + s += self._indent() + "{\n" + + self._scope_stack.push_scope() + + s += self._indent() + "%s[_i] = ((Float)%s.get(_i)).floatValue();\n" % (to_name, from_name) + + self._scope_stack.pop_scope() + + s += self._indent() + "}\n" + else: + s += self._indent() + "%s.toArray(%s);\n" % (from_name, to_name) + + self._scope_stack.pop_scope() + + s += self._indent() + "}" + + return s + + def _is_resizeable(self, name): + data = self._scope_stack.get_variable_data(name) + + if data is not None: + return True if data["resizeable"] is True or data["type"].name.value == "Vector" else False + else: + return False + + def _is_resizeable_function(self, name): + data = self._scope_stack.get_function_data(name) + + if data is not None: + return True if data["resizeable"] is True or data["return_type"].name.value == "Vector" else False + else: + return False + +class JavaStaticClassGenerator(JavaClassGenerator): + def _build_function_pre_declaration(self): + return self._indent() + "public static " + diff --git a/utils/mocha/mocha/model.py b/utils/mocha/mocha/model.py new file mode 100644 index 000000000..e2efcc5fa --- /dev/null +++ b/utils/mocha/mocha/model.py @@ -0,0 +1,493 @@ + +class SourceElement(object): + + def __init__(self): + super(SourceElement, self).__init__() + self._fields = [] + + def __repr__(self): + equals = ("{0}={1!r}".format(k, getattr(self, k)) + for k in self._fields) + args = ", ".join(equals) + return "{0}({1})".format(self.__class__.__name__, args) + + def __eq__(self, other): + try: + return self.__dict__ == other.__dict__ + except AttributeError: + return False + + def __ne__(self, other): + return not self == other + + def accept(self, visitor): + s = visitor.visit(self) + return s + + +class ArrayAccess(SourceElement): + def __init__(self, index, target): + super(ArrayAccess, self).__init__() + self._fields = ['index', 'target'] + self.index = index + self.target = target + + +class ArrayInitializer(SourceElement): + + def __init__(self, elements=None): + super(ArrayInitializer, self).__init__() + self._fields = ['elements'] + if elements is None: + elements = [] + self.elements = elements + + +class Catch(SourceElement): + + def __init__(self, variable, modifiers=None, _type=None, block=None): + super(Catch, self).__init__() + self._fields = ['variable', 'modifiers', 'type', 'block'] + if modifiers is None: + modifiers = [] + self.variable = variable + self.modifiers = modifiers + self.type = _type + self.block = block + + +class CompilationUnit(SourceElement): + + def __init__(self, includes=None, inherits=None, statements=None): + super(CompilationUnit, self).__init__() + self._fields = ['includes', 'statements'] + if includes is None: + includes = [] + if statements is None: + statements = [] + self.includes = includes + self.inherits = inherits + self.statements = statements + + +class CrcString(SourceElement): + + def __init__(self, string): + super(CrcString, self).__init__() + self._fields = ['string'] + self.string = string + + +class Expression(SourceElement): + + def __init__(self): + super(Expression, self).__init__() + self._fields = [] + + +class FieldDeclaration(SourceElement): + + def __init__(self, type, variable_declarators, modifiers=None): + super(FieldDeclaration, self).__init__() + self._fields = ['type', 'variable_declarators', 'modifiers'] + if modifiers is None: + modifiers = [] + self.type = type + self.variable_declarators = variable_declarators + self.modifiers = modifiers + + +class FormalParameter(SourceElement): + + def __init__(self, variable, type, modifiers=None): + super(FormalParameter, self).__init__() + self._fields = ['variable', 'type', 'modifiers'] + if modifiers is None: + modifiers = [] + self.variable = variable + self.type = type + self.modifiers = modifiers + + +class FunctionDeclaration(SourceElement): + + def __init__(self, name, modifiers=None, parameters=None, return_type='void', body=None): + super(FunctionDeclaration, self).__init__() + self._fields = ['name', 'modifiers', 'parameters', 'return_type', 'body'] + if modifiers is None: + modifiers = [] + if parameters is None: + parameters = [] + self.name = name + self.modifiers = modifiers + self.parameters = parameters + self.return_type = return_type + self.body = body + + +class IncludeDeclaration(SourceElement): + + def __init__(self, name, on_demand=False): + super(IncludeDeclaration, self).__init__() + self._fields = ['name', 'on_demand'] + self.name = name + self.on_demand = on_demand + + +class InheritsDeclaration(SourceElement): + + def __init__(self, name): + super(InheritsDeclaration, self).__init__() + self._fields = ['name'] + self.name = name + + +class Literal(SourceElement): + + def __init__(self, literal): + super(Literal, self).__init__() + self._fields = ['literal'] + self.literal = literal + + +class Name(SourceElement): + + def __init__(self, value): + super(Name, self).__init__() + self._fields = ['value'] + self.value = value + + def append_name(self, name): + try: + self.value = self.value + '.' + name.value + except: + self.value = self.value + '.' + name + + +class Precidence(SourceElement): + + def __init__(self, expression): + super(Precidence, self).__init__() + self._field = ['expression'] + self.expression = expression + + +class Statement(SourceElement): + pass + + +class SwitchCase(SourceElement): + + def __init__(self, cases, body=None): + super(SwitchCase, self).__init__() + self._fields = ['cases', 'body'] + if body is None: + body = [] + self.cases = cases + self.body = body + + +class Type(SourceElement): + + def __init__(self, name, enclosed_in=None, dimensions=0): + super(Type, self).__init__() + self._fields = ['name', 'enclosed_in', 'dimensions'] + + self.name = name + self.enclosed_in = enclosed_in + self.dimensions = dimensions + + +class Variable(SourceElement): + + def __init__(self, name, dimensions=0): + super(Variable, self).__init__() + self._fields = ['name', 'dimensions'] + self.name = name + self.dimensions = dimensions + + +class VariableDeclarator(SourceElement): + + def __init__(self, variable, initializer=None): + super(VariableDeclarator, self).__init__() + self._fields = ['variable', 'initializer'] + self.variable = variable + self.initializer = initializer + + +class VariableDeclaration(Statement, FieldDeclaration): + pass + + +class ArrayCreation(Expression): + + def __init__(self, type, dimensions=None, initializer=None): + super(ArrayCreation, self).__init__() + self._fields = ['type', 'dimensions', 'initializer'] + if dimensions is None: + dimensions = [] + self.type = type + self.dimensions = dimensions + self.initializer = initializer + + +class BinaryExpression(Expression): + + def __init__(self, operator, lhs, rhs): + super(BinaryExpression, self).__init__() + self._fields = ['operator', 'lhs', 'rhs'] + self.operator = operator + self.lhs = lhs + self.rhs = rhs + + +class Cast(Expression): + + def __init__(self, target, expression, modifiers=None): + super(Cast, self).__init__() + self._fields = ['target', 'expression', 'modifiers'] + if modifiers is None: + modifiers = [] + self.target = target + self.expression = expression + self.modifiers = modifiers + + +class Conditional(Expression): + + def __init__(self, predicate, if_true, if_false): + super(self.__class__, self).__init__() + self._fields = ['predicate', 'if_true', 'if_false'] + self.predicate = predicate + self.if_true = if_true + self.if_false = if_false + + +class FieldAccess(Expression): + + def __init__(self, name, target): + super(FieldAccess, self).__init__() + self._fields = ['name', 'target'] + self.name = name + self.target = target + + +class InstanceCreation(Expression): + + def __init__(self, type, arguments=None): + super(InstanceCreation, self).__init__() + self._fields = ['type', 'arguments'] + if arguments is None: + arguments = [] + self.type = type + self.arguments = arguments + + +class MethodInvocation(Expression): + + def __init__(self, name, arguments=None, target=None): + super(MethodInvocation, self).__init__() + self._fields = ['name', 'arguments', 'target'] + if arguments is None: + arguments = [] + self.name = name + self.arguments = arguments + self.target = target + + +class Unary(Expression): + + def __init__(self, sign, expression): + super(Unary, self).__init__() + self._fields = ['sign', 'expression'] + self.sign = sign + self.expression = expression + + +class Assignment(BinaryExpression): + pass + + +class ConditionalOr(BinaryExpression): + pass + + +class ConditionalAnd(BinaryExpression): + pass + + +class Or(BinaryExpression): + pass + + +class Xor(BinaryExpression): + pass + + +class And(BinaryExpression): + pass + + +class Equality(BinaryExpression): + pass + + +class InstanceOf(BinaryExpression): + pass + + +class Relational(BinaryExpression): + pass + + +class Shift(BinaryExpression): + pass + + +class Additive(BinaryExpression): + pass + + +class Multiplicative(BinaryExpression): + pass + + +class Block(Statement): + + def __init__(self, statements=None, wrap=True): + super(Block, self).__init__() + self._fields = ['statements', 'wrap'] + if statements is None: + statements = [] + self.statements = statements + self.wrap = wrap + + def __iter__(self): + for s in self.statements: + yield s + + +class BlockStatement(Statement): + + def __init__(self, statement): + super(BlockStatement, self).__init__() + self._fields = ['statement'] + self.statement = statement + + +class Break(Statement): + + def __init__(self, label=None): + super(Break, self).__init__() + self._fields = ['label'] + self.label = label + + +class Continue(Statement): + + def __init__(self, label=None): + super(Continue, self).__init__() + self._fields = ['label'] + self.label = label + + +class DoWhile(Statement): + + def __init__(self, predicate, body=None): + super(DoWhile, self).__init__() + self._fields = ['predicate', 'body'] + self.predicate = predicate + self.body = body + + +class Empty(Statement): + pass + + +class For(Statement): + + def __init__(self, init, predicate, update, body): + super(For, self).__init__() + self._fields = ['init', 'predicate', 'update', 'body'] + self.init = init + self.predicate = predicate + self.update = update + self.body = body + + +class IfThenElse(Statement): + + def __init__(self, predicate, if_true=None, if_false=None): + super(IfThenElse, self).__init__() + self._fields = ['predicate', 'if_true', 'if_false'] + self.predicate = predicate + + if if_true is not None and type(if_true) is not Block: + if_true = Block([BlockStatement(if_true)]) + + self.if_true = if_true + self.if_false = if_false + + +class Return(Statement): + + def __init__(self, result=None): + super(Return, self).__init__() + self._fields = ['result'] + self.result = result + + +class StatementExpression(Statement): + + def __init__(self, expression): + super(StatementExpression, self).__init__() + self._fields = ['expression'] + self.expression = expression + + +class Switch(Statement): + + def __init__(self, expression, switch_cases): + super(Switch, self).__init__() + self._fields = ['expression', 'switch_cases'] + self.expression = expression + self.switch_cases = switch_cases + + +class Throw(Statement): + + def __init__(self, expression): + super(Throw, self).__init__() + self._fields = ['expression'] + self.expression = expression + + +class Try(Statement): + + def __init__(self, block, catches=None, _finally=None): + super(Try, self).__init__() + self._fields = ['block', 'catches', '_finally'] + if catches is None: + catches = [] + self.block = block + self.catches = catches + self._finally = _finally + + +class VariableDeclarationStatement(Statement): + + def __init__(self, statement): + super(VariableDeclarationStatement, self).__init__() + self._fields = ['statement'] + self.statement = statement + + +class While(Statement): + + def __init__(self, predicate, body=None): + super(While, self).__init__() + self._fields = ['predicate', 'body'] + self.predicate = predicate + self.body = body + diff --git a/utils/mocha/mocha/parser.py b/utils/mocha/mocha/parser.py new file mode 100644 index 000000000..e9f8fdf0a --- /dev/null +++ b/utils/mocha/mocha/parser.py @@ -0,0 +1,1336 @@ +#!/usr/bin/env python + +import ply.lex as lex +import ply.yacc as yacc + +from .model import * + + +class Coord(object): + """ Coordinates of a syntatic element: + - Filename + - Line number + - (optional) column number + """ + def __init__(self, file, line, column=None): + self.file = file + self.line = line + self.column = column + + def __str__(self): + str = "%s:%s" % (self.file, self.line) + if self.column: str += ":%s" % self.column + return str + + +class ParseError(Exception): pass + + +class BaseParser(object): + + def _coord(self, lineno, column=None): + return Coord( + file=self.lexer.filename, + line=lineno, + column=column) + + def _parse_error(self, msg, coord): + raise ParseError("%s: %s" % (coord, msg)) + + +class MochaLexer(object): + + def __init__(self, error_func=None): + self.error_func = error_func + self.filename = '' + + def build(self, **kwargs): + self.lexer = lex.lex(object=self, **kwargs) + + def reset_lineno(self): + """ Resets the internal line number counter of the lexer. + """ + self.lexer.lineno = 1 + + def input(self, text): + self.lexer.input(text) + + def token(self): + self.last_token = self.lexer.token() + return self.last_token + + def find_tok_column(self, token): + """ Find the column of the token in its line. + """ + last_cr = self.lexer.lexdata.rfind('\n', 0, token.lexpos) + return token.lexpos - last_cr + + def _error(self, msg, token): + location = self._make_tok_location(token) + self.error_func(msg, location[0], location[1]) + self.lexer.skip(1) + + def _make_tok_location(self, token): + return (token.lineno, self.find_tok_column(token)) + + keywords = ('boolean', 'void', 'byte', 'short', 'int', 'long', 'char', + 'float', 'double', 'new', 'include', 'const', 'true', 'false', + 'null', 'if', 'else', 'while', 'for', 'do', 'break', 'continue', + 'return', 'switch', 'case', 'default', 'resizeable', 'inherits', + 'instanceof', 'throw', 'try', 'catch', 'finally', 'define', + 'ifdef', 'endif') + + tokens = [ + 'NAME', + + 'INT_CONST', + 'INT_CONST_HEX', + 'FLOAT_CONST', + 'CHAR_LITERAL', + 'STRING_LITERAL', + + # Operators (+,-,*,/,%,|,&,~,^,<<,>>, ||, &&, !, <, <=, >, >=, ==, !=) + 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD', + 'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT', + 'LOR', 'LAND', 'LNOT', + 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE', + + # Assignment (=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=) + 'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL', 'PLUSEQUAL', 'MINUSEQUAL', + 'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL', 'OREQUAL', + + # Ternary operator (?) + 'TERNARY', + + # Hash symbol + 'HASH', + + # Increment/decrement (++,--) + 'PLUSPLUS', 'MINUSMINUS', + + # Delimeters ( ) [ ] { } , . ; : + 'LPAREN', 'RPAREN', + 'LBRACKET', 'RBRACKET', + 'LBRACE', 'RBRACE', + 'COMMA', 'PERIOD', 'SEMI', 'COLON', + + ] + [ k.upper() for k in keywords ] + + hex_prefix = '0[xX]' + hex_digits = '[0-9a-fA-F]+' + + integer_suffix_opt = r'(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?' + + # literals + t_INT_CONST = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?' + t_INT_CONST_HEX = hex_prefix + hex_digits + integer_suffix_opt + t_FLOAT_CONST = r'([0-9]+[.]?[fF]|[0-9]*(\.[0-9]+))([fF])?' + t_CHAR_LITERAL = r'\'([^\\\n]|(\\.))*?\'' + t_STRING_LITERAL = r'\"(\\.|[^"])*\"' + + # Comment (C++-Style) + def t_CPPCOMMENT(self, t): + r'//.*\n?' + t.lexer.lineno += 1 + pass + + # Comment (C-Style) + def t_COMMENT(self, t): + r'/\*(.|\n)*?\*/' + t.lexer.lineno += t.value.count('\n') + pass + + # Operators + t_PLUS = r'\+' + t_MINUS = r'-' + t_TIMES = r'\*' + t_DIVIDE = r'/' + t_MOD = r'%' + t_OR = r'\|' + t_AND = r'&' + t_NOT = r'~' + t_XOR = r'\^' + t_LSHIFT = r'<<' + t_RSHIFT = r'>>' + t_LOR = r'\|\|' + t_LAND = r'&&' + t_LNOT = r'!' + t_LT = r'<' + t_GT = r'>' + t_LE = r'<=' + t_GE = r'>=' + t_EQ = r'==' + t_NE = r'!=' + + # Assignment operators + t_EQUALS = r'=' + t_TIMESEQUAL = r'\*=' + t_DIVEQUAL = r'/=' + t_MODEQUAL = r'%=' + t_PLUSEQUAL = r'\+=' + t_MINUSEQUAL = r'-=' + t_LSHIFTEQUAL = r'<<=' + t_RSHIFTEQUAL = r'>>=' + t_ANDEQUAL = r'&=' + t_OREQUAL = r'\|=' + t_XOREQUAL = r'^=' + + # Increment/decrement + t_PLUSPLUS = r'\+\+' + t_MINUSMINUS = r'--' + + # ? + t_TERNARY = r'\?' + + # # + t_HASH = r'\#' + + # Delimeters + t_LPAREN = r'\(' + t_RPAREN = r'\)' + t_LBRACKET = r'\[' + t_RBRACKET = r'\]' + t_LBRACE = r'\{' + t_RBRACE = r'\}' + t_COMMA = r',' + t_PERIOD = r'\.' + t_SEMI = r';' + t_COLON = r':' + + t_ignore = ' \t\f' + + def t_NAME(self, t): + '[A-Za-z_$][A-Za-z0-9_$]*' + if t.value in MochaLexer.keywords: + t.type = t.value.upper() + return t + + def t_newline(self, t): + r'\n+' + t.lexer.lineno += len(t.value) + + def t_newline2(self, t): + r'(\r\n)+' + t.lexer.lineno += len(t.value) / 2 + + def t_error(self, t): + msg = 'Illegal character %s' % repr(t.value[0]) + self._error(msg, t) + + +class ClassParser(BaseParser): + + def p_argument_list_opt_1(self, p): + ''' argument_list_opt : argument_list ''' + p[0] = p[1] + + def p_argument_list_opt_2(self, p): + ''' argument_list_opt : empty ''' + p[0] = [] + + def p_argument_list(self, p): + ''' argument_list : expression + | argument_list COMMA expression + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[3]] + + +class ExpressionParser(BaseParser): + + def p_expression(self, p): + ''' expression : assignment_expression ''' + p[0] = p[1] + + def p_expression_not_name(self, p): + ''' expression_not_name : assignment_expression_not_name ''' + p[0] = p[1] + + def p_assignment_expression(self, p): + ''' assignment_expression : assignment + | conditional_expression + ''' + p[0] = p[1] + + def p_assignment_expression_not_name(self, p): + ''' assignment_expression_not_name : assignment + | conditional_expression_not_name + ''' + p[0] = p[1] + + def p_assignment(self, p): + ''' assignment : postfix_expression assignment_operator assignment_expression ''' + p[0] = Assignment(p[2], p[1], p[3]) + + def p_assignment_operator(self, p): + ''' assignment_operator : EQUALS + | XOREQUAL + | TIMESEQUAL + | DIVEQUAL + | MODEQUAL + | PLUSEQUAL + | MINUSEQUAL + | LSHIFTEQUAL + | RSHIFTEQUAL + | ANDEQUAL + | OREQUAL + ''' + p[0] = p[1] + + def p_conditional_expression(self, p): + ''' conditional_expression : conditional_or_expression + | conditional_or_expression TERNARY expression COLON conditional_expression + ''' + if len(p) == 2: + p[0] = p[1] + else: + p[0] = Conditional(p[1], p[3], p[5]) + + def p_conditional_expression_not_name(self, p): + ''' conditional_expression_not_name : conditional_or_expression_not_name + | conditional_or_expression_not_name TERNARY expression COLON conditional_expression + | name TERNARY expression COLON conditional_expression + ''' + if len(p) == 2: + p[0] = p[1] + else: + p[0] = Conditional(p[1], p[3], p[5]) + + def binop(self, p, ctor): + if len(p) == 2: + p[0] = p[1] + else: + p[0] = ctor(p[2], p[1], p[3]) + + def p_conditional_or_expression(self, p): + ''' conditional_or_expression : conditional_and_expression + | conditional_or_expression LOR conditional_and_expression + ''' + self.binop(p, ConditionalOr) + + def p_conditional_or_expression_not_name(self, p): + ''' conditional_or_expression_not_name : conditional_and_expression_not_name + | conditional_or_expression_not_name LOR conditional_and_expression + | name LOR conditional_and_expression + ''' + self.binop(p, ConditionalOr) + + def p_conditional_and_expression(self, p): + ''' conditional_and_expression : inclusive_or_expression + | conditional_and_expression LAND inclusive_or_expression + ''' + self.binop(p, ConditionalAnd) + + def p_conditional_and_expression_not_name(self, p): + ''' conditional_and_expression_not_name : inclusive_or_expression_not_name + | conditional_and_expression_not_name LAND inclusive_or_expression + | name LAND inclusive_or_expression''' + self.binop(p, ConditionalAnd) + + def p_inclusive_or_expression(self, p): + '''inclusive_or_expression : exclusive_or_expression + | inclusive_or_expression OR exclusive_or_expression''' + self.binop(p, Or) + + def p_inclusive_or_expression_not_name(self, p): + '''inclusive_or_expression_not_name : exclusive_or_expression_not_name + | inclusive_or_expression_not_name OR exclusive_or_expression + | name OR exclusive_or_expression''' + self.binop(p, Or) + + def p_exclusive_or_expression(self, p): + '''exclusive_or_expression : and_expression + | exclusive_or_expression XOR and_expression''' + self.binop(p, Xor) + + def p_exclusive_or_expression_not_name(self, p): + '''exclusive_or_expression_not_name : and_expression_not_name + | exclusive_or_expression_not_name XOR and_expression + | name XOR and_expression''' + self.binop(p, Xor) + + def p_and_expression(self, p): + '''and_expression : equality_expression + | and_expression AND equality_expression''' + self.binop(p, And) + + def p_and_expression_not_name(self, p): + '''and_expression_not_name : equality_expression_not_name + | and_expression_not_name AND equality_expression + | name AND equality_expression''' + self.binop(p, And) + + def p_equality_expression(self, p): + '''equality_expression : instanceof_expression + | equality_expression EQ instanceof_expression + | equality_expression NE instanceof_expression''' + self.binop(p, Equality) + + def p_equality_expression_not_name(self, p): + '''equality_expression_not_name : instanceof_expression_not_name + | equality_expression_not_name EQ instanceof_expression + | name EQ instanceof_expression + | equality_expression_not_name NE instanceof_expression + | name NE instanceof_expression''' + self.binop(p, Equality) + + def p_instanceof_expression(self, p): + '''instanceof_expression : relational_expression + | instanceof_expression INSTANCEOF type''' + self.binop(p, InstanceOf) + + def p_instanceof_expression_not_name(self, p): + '''instanceof_expression_not_name : relational_expression_not_name + | name INSTANCEOF reference_type + | instanceof_expression_not_name INSTANCEOF type''' + self.binop(p, InstanceOf) + + def p_relational_expression(self, p): + '''relational_expression : shift_expression + | relational_expression GT shift_expression + | relational_expression LT shift_expression + | relational_expression GE shift_expression + | relational_expression LE shift_expression''' + self.binop(p, Relational) + + def p_relational_expression_not_name(self, p): + '''relational_expression_not_name : shift_expression_not_name + | shift_expression_not_name LT shift_expression + | name LT shift_expression + | shift_expression_not_name GT shift_expression + | name GT shift_expression + | shift_expression_not_name GE shift_expression + | name GE shift_expression + | shift_expression_not_name LE shift_expression + | name LE shift_expression''' + self.binop(p, Relational) + + def p_shift_expression(self, p): + '''shift_expression : additive_expression + | shift_expression LSHIFT additive_expression + | shift_expression RSHIFT additive_expression''' + self.binop(p, Shift) + + def p_shift_expression_not_name(self, p): + '''shift_expression_not_name : additive_expression_not_name + | shift_expression_not_name LSHIFT additive_expression + | name LSHIFT additive_expression + | shift_expression_not_name RSHIFT additive_expression + | name RSHIFT additive_expression''' + self.binop(p, Shift) + + def p_additive_expression(self, p): + '''additive_expression : multiplicative_expression + | additive_expression PLUS multiplicative_expression + | additive_expression MINUS multiplicative_expression''' + self.binop(p, Additive) + + def p_additive_expression_not_name(self, p): + '''additive_expression_not_name : multiplicative_expression_not_name + | additive_expression_not_name PLUS multiplicative_expression + | name PLUS multiplicative_expression + | additive_expression_not_name MINUS multiplicative_expression + | name MINUS multiplicative_expression''' + self.binop(p, Additive) + + def p_multiplicative_expression(self, p): + '''multiplicative_expression : unary_expression + | multiplicative_expression TIMES unary_expression + | multiplicative_expression DIVIDE unary_expression + | multiplicative_expression MOD unary_expression''' + self.binop(p, Multiplicative) + + def p_multiplicative_expression_not_name(self, p): + '''multiplicative_expression_not_name : unary_expression_not_name + | multiplicative_expression_not_name TIMES unary_expression + | name TIMES unary_expression + | multiplicative_expression_not_name DIVIDE unary_expression + | name DIVIDE unary_expression + | multiplicative_expression_not_name MOD unary_expression + | name MOD unary_expression''' + self.binop(p, Multiplicative) + + def p_unary_expression(self, p): + '''unary_expression : pre_increment_expression + | pre_decrement_expression + | PLUS unary_expression + | MINUS unary_expression + | unary_expression_not_plus_minus''' + if len(p) == 2: + p[0] = p[1] + else: + p[0] = Unary(p[1], p[2]) + + def p_unary_expression_not_name(self, p): + '''unary_expression_not_name : pre_increment_expression + | pre_decrement_expression + | PLUS unary_expression + | MINUS unary_expression + | unary_expression_not_plus_minus_not_name''' + if len(p) == 2: + p[0] = p[1] + else: + p[0] = Unary(p[1], p[2]) + + def p_pre_increment_expression(self, p): + ''' pre_increment_expression : PLUSPLUS unary_expression''' + p[0] = Unary('++x', p[2]) + + def p_pre_decrement_expression(self, p): + ''' pre_decrement_expression : MINUSMINUS unary_expression''' + p[0] = Unary('--x', p[2]) + + def p_unary_expression_not_plus_minus(self, p): + '''unary_expression_not_plus_minus : postfix_expression + | NOT unary_expression + | LNOT expression + | cast_expression''' + if len(p) == 2: + p[0] = p[1] + else: + p[0] = Unary(p[1], p[2]) + + def p_unary_expression_not_plus_minus_not_name(self, p): + '''unary_expression_not_plus_minus_not_name : postfix_expression_not_name + | NOT unary_expression + | LNOT expression + | cast_expression''' + if len(p) == 2: + p[0] = p[1] + else: + p[0] = Unary(p[1], p[2]) + + def p_postfix_expression(self, p): + ''' postfix_expression : primary_expression + | name + | post_increment_expression + | post_decrement_expression + ''' + p[0] = p[1] + + def p_postfix_expression_not_name(self, p): + '''postfix_expression_not_name : primary_expression + | post_increment_expression + | post_decrement_expression''' + p[0] = p[1] + + def p_post_increment_expression(self, p): + ''' post_increment_expression : postfix_expression PLUSPLUS ''' + p[0] = Unary('x++', p[1]) + + def p_post_decrement_expression(self, p): + ''' post_decrement_expression : postfix_expression MINUSMINUS ''' + p[0] = Unary('x--', p[1]) + + def p_primary_expression(self, p): + ''' primary_expression : primary_expression_no_new_array + | array_creation_with_array_initializer + | array_creation_without_array_initializer + ''' + p[0] = p[1] + + def p_primary_expression_no_new_array_1(self, p): + ''' primary_expression_no_new_array : literal + | class_instance_creation_expression + | field_access + | method_invocation + | array_access + | crc_string + ''' + p[0] = p[1] + + def p_primary_expression_no_new_array_2(self, p): + ''' primary_expression_no_new_array : LPAREN name RPAREN + | LPAREN expression_not_name RPAREN + ''' + p[0] = Precidence(p[2]) + + def p_dimensions_opt_1(self, p): + ''' dimensions_opt : dimensions ''' + p[0] = p[1] + + def p_dimensions_opt_2(self, p): + ''' dimensions_opt : empty ''' + p[0] = 0 + + def p_dimensions(self, p): + ''' dimensions : dimension + | dimensions dimension + ''' + if len(p) == 2: + p[0] = 1 + else: + p[0] = 1 + p[1] + + def p_dimension(self, p): + ''' dimension : LBRACKET RBRACKET ''' + pass + + def p_cast_expression_1(self, p): + ''' cast_expression : LPAREN primitive_type dimensions_opt RPAREN unary_expression ''' + p[0] = Cast(Type(p[2], dimensions=p[3]), p[5]) + + def p_cast_expression_2(self, p): + ''' cast_expression : LPAREN modifiers primitive_type dimensions_opt RPAREN unary_expression ''' + p[0] = Cast(Type(p[3], dimensions=p[4]), p[6], p[2]) + + def p_cast_expression_3(self, p): + ''' cast_expression : LPAREN name RPAREN unary_expression_not_plus_minus ''' + p[0] = Cast(Type(p[2]), p[4]) + + def p_cast_expression_4(self, p): + ''' cast_expression : LPAREN modifiers name RPAREN unary_expression_not_plus_minus ''' + p[0] = Cast(Type(p[3]), p[5], p[2]) + + def p_cast_expression_5(self, p): + ''' cast_expression : LPAREN name dimensions RPAREN unary_expression_not_plus_minus ''' + p[0] = Cast(Type(p[2], dimensions=p[3]), p[5]) + + def p_cast_expression_6(self, p): + ''' cast_expression : LPAREN modifiers name dimensions RPAREN unary_expression_not_plus_minus ''' + p[0] = Cast(Type(p[3], dimensions=p[4]), p[6], p[2]) + + +class FunctionParser(BaseParser): + + def p_formal_parameter_list_opt_1(self, p): + ''' formal_parameter_list_opt : formal_parameter_list ''' + p[0] = p[1] + + def p_formal_parameter_list_opt_2(self, p): + ''' formal_parameter_list_opt : formal_parameter_list COMMA ''' + p[0] = p[1] + + def p_formal_parameter_list_opt_3(self, p): + ''' formal_parameter_list_opt : empty ''' + p[0] = [] + + def p_formal_parameter_list(self, p): + ''' formal_parameter_list : formal_parameter + | formal_parameter_list COMMA formal_parameter + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[3]] + + def p_formal_parameter(self, p): + ''' formal_parameter : modifiers_opt type variable_declarator_id ''' + p[0] = FormalParameter(p[3], p[2], modifiers=p[1]) + + def p_function_body(self, p): + ''' function_body : LBRACE block_statements_opt RBRACE ''' + p[0] = p[2] + + def p_function_declaration(self, p): + ''' function_declaration : function_header function_body ''' + p[0] = FunctionDeclaration( + p[1]['name'], + modifiers=p[1]['modifiers'], + parameters=p[1]['parameters'], + return_type=p[1]['type'], + body=p[2]) + + def p_function_header(self, p): + ''' function_header : function_header_name formal_parameter_list_opt RPAREN ''' + p[1]['parameters'] = p[2] + p[0] = p[1] + + def p_function_header_name_1(self, p): + ''' function_header_name : type NAME LPAREN ''' + p[0] = {'modifiers': [], 'type': p[1], 'name': p[2] } + + def p_function_header_name_2(self, p): + ''' function_header_name : modifiers type NAME LPAREN ''' + p[0] = {'modifiers': p[1], 'type': p[2], 'name': p[3] } + + +class LiteralParser(BaseParser): + + def p_literal(self, p): + ''' literal : INT_CONST + | INT_CONST_HEX + | FLOAT_CONST + | CHAR_LITERAL + | STRING_LITERAL + | TRUE + | FALSE + | NULL + ''' + p[0] = Literal(p[1]) + + def p_crc_string_literal(self, p): + ''' crc_string : HASH HASH STRING_LITERAL ''' + p[0] = CrcString(p[3]) + + +class NameParser(BaseParser): + + def p_name(self, p): + ''' name : simple_name + | qualified_name + ''' + p[0] = p[1] + + def p_simple_name(self, p): + ''' simple_name : NAME ''' + p[0] = Name(p[1]) + + def p_qualified_name(self, p): + ''' qualified_name : name PERIOD simple_name ''' + p[1].append_name(p[3]) + p[0] = p[1] + + +class StatementParser(BaseParser): + + def p_block(self, p): + ''' block : LBRACE block_statements_opt RBRACE ''' + p[0] = Block(p[2]) + + def p_block_statements_opt_1(self, p): + ''' block_statements_opt : block_statements ''' + p[0] = p[1] + + def p_block_statements_opt_2(self, p): + ''' block_statements_opt : empty ''' + p[0] = [] + + def p_block_statements(self, p): + ''' block_statements : block_statement + | block_statements block_statement + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + def p_block_statement_1(self, p): + ''' block_statement : statement + | pp_define + | pp_ifdef + ''' + p[0] = BlockStatement(p[1]) + + def p_block_statement_2(self, p): + ''' block_statement : function_declaration ''' + p[0] = p[1] + + def p_pp_define(self, p): + ''' pp_define : HASH DEFINE NAME INT_CONST ''' + self.defines[p[3]] = p[4] + p[0] = Empty() + + def p_pp_ifdef_1(self, p): + ''' pp_ifdef : HASH IFDEF NAME block_statements HASH ENDIF ''' + if self.defines.get(p[3], False): + p[0] = Block(p[4], False) + else: + p[0] = Empty() + + def p_local_variable_declaration_statement(self, p): + ''' local_variable_declaration_statement : local_variable_declaration SEMI ''' + p[0] = VariableDeclarationStatement(p[1]) + + def p_local_variable_declaration_1(self, p): + ''' local_variable_declaration : type variable_declarators ''' + p[0] = VariableDeclaration(p[1], p[2]) + + def p_local_variable_declaration_2(self, p): + ''' local_variable_declaration : modifiers type variable_declarators ''' + p[0] = VariableDeclaration(p[2], p[3], modifiers=p[1]) + + def p_variable_declarators(self, p): + '''variable_declarators : variable_declarator + | variable_declarators COMMA variable_declarator''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[3]] + + def p_variable_declarator(self, p): + ''' variable_declarator : variable_declarator_id + | variable_declarator_id EQUALS variable_initializer + ''' + if len(p) == 2: + p[0] = VariableDeclarator(p[1]) + else: + p[0] = VariableDeclarator(p[1], initializer=p[3]) + + def p_variable_declarator_id(self, p): + ''' variable_declarator_id : NAME dimensions_opt ''' + p[0] = Variable(p[1], dimensions=p[2]) + + def p_variable_initializer(self, p): + ''' variable_initializer : expression + | array_initializer + ''' + p[0] = p[1] + + def p_statement(self, p): + ''' statement : local_variable_declaration_statement + | statement_without_trailing_substatement + | if_then_statement + | if_then_else_statement + | while_statement + | for_statement + ''' + p[0] = p[1] + + def p_statement_without_trailing_substatement(self, p): + ''' statement_without_trailing_substatement : block + | expression_statement + | empty_statement + | switch_statement + | do_statement + | break_statement + | continue_statement + | return_statement + | throw_statement + | try_statement + ''' + p[0] = p[1] + + def p_expression_statement(self, p): + ''' expression_statement : statement_expression SEMI + ''' + p[0] = StatementExpression(p[1]) + + def p_statement_expression(self, p): + ''' statement_expression : assignment + | pre_increment_expression + | pre_decrement_expression + | post_increment_expression + | post_decrement_expression + | method_invocation + | class_instance_creation_expression + ''' + p[0] = p[1] + + def p_comma_opt(self, p): + ''' comma_opt : COMMA + | empty + ''' + pass + + def p_array_initializer_1(self, p): + ''' array_initializer : LBRACE comma_opt RBRACE ''' + p[0] = ArrayInitializer() + + def p_array_initializer_2(self, p): + ''' array_initializer : LBRACE variable_initializers RBRACE + | LBRACE variable_initializers COMMA RBRACE + ''' + p[0] = ArrayInitializer(p[2]) + + def p_variable_initializers(self, p): + ''' variable_initializers : variable_initializer + | variable_initializers COMMA variable_initializer + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[3]] + + def p_method_invocation_1(self, p): + ''' method_invocation : NAME LPAREN argument_list_opt RPAREN ''' + p[0] = MethodInvocation(p[1], arguments=p[3]) + + def p_method_invocation_2(self, p): + ''' method_invocation : name PERIOD NAME LPAREN argument_list_opt RPAREN + | primary_expression PERIOD NAME LPAREN argument_list_opt RPAREN + ''' + p[0] = MethodInvocation(p[3], target=p[1], arguments=p[5]) + + def p_if_then_statement(self, p): + ''' if_then_statement : IF LPAREN expression RPAREN statement %prec then''' + p[0] = IfThenElse(p[3], p[5]) + + def p_if_then_else_statement_1(self, p): + ''' if_then_else_statement : IF LPAREN expression RPAREN statement ELSE statement ''' + p[0] = IfThenElse(p[3], p[5], p[7]) + + def p_while_statement_1(self, p): + ''' while_statement : WHILE LPAREN expression RPAREN statement ''' + p[0] = While(p[3], p[5]) + + def p_while_statement_2(self, p): + ''' while_statement : WHILE LPAREN expression RPAREN SEMI ''' + p[0] = While(p[3]) + + def p_for_statement(self, p): + ''' for_statement : FOR LPAREN for_init_opt SEMI expression_opt SEMI for_update_opt RPAREN statement ''' + p[0] = For(p[3], p[5], p[7], p[9]) + + def p_for_init_opt(self, p): + ''' for_init_opt : for_init + | empty + ''' + p[0] = p[1] + + def p_for_init(self, p): + ''' for_init : statement_expression_list + | local_variable_declaration + ''' + p[0] = p[1] + + def p_statement_expression_list(self, p): + ''' statement_expression_list : statement_expression + | statement_expression_list COMMA statement_expression + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[3]] + + def p_expression_opt(self, p): + ''' expression_opt : expression + | empty + ''' + p[0] = p[1] + + def p_for_update_opt(self, p): + ''' for_update_opt : for_update + | empty + ''' + p[0] = p[1] + + def p_for_update(self, p): + ''' for_update : statement_expression_list ''' + p[0] = p[1] + + def p_empty_statement(self, p): + '''empty_statement : SEMI ''' + p[0] = Empty() + + def p_switch_statement(self, p): + ''' switch_statement : SWITCH LPAREN expression RPAREN switch_block ''' + p[0] = Switch(p[3], p[5]) + + def p_switch_block_1(self, p): + ''' switch_block : LBRACE RBRACE ''' + p[0] = [] + + def p_switch_block_2(self, p): + ''' switch_block : LBRACE switch_block_statements RBRACE ''' + p[0] = p[2] + + def p_switch_block_3(self, p): + ''' switch_block : LBRACE switch_labels RBRACE ''' + p[0] = [SwitchCase(p[2])] + + def p_switch_block_4(self, p): + ''' switch_block : LBRACE switch_block_statements switch_labels RBRACE ''' + p[0] = p[2] + [SwitchCase(p[3])] + + def p_switch_block_statements(self, p): + ''' switch_block_statements : switch_block_statement + | switch_block_statements switch_block_statement + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + def p_switch_block_statement(self, p): + ''' switch_block_statement : switch_labels block_statements ''' + p[0] = SwitchCase(p[1], body=p[2]) + + def p_switch_labels(self, p): + ''' switch_labels : switch_label + | switch_labels switch_label + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + def p_switch_label(self, p): + ''' switch_label : CASE constant_expression COLON + | DEFAULT COLON + ''' + if len(p) == 3: + p[0] = 'default' + else: + p[0] = p[2] + + def p_constant_expression(self, p): + ''' constant_expression : expression ''' + p[0] = p[1] + + def p_do_statement(self, p): + ''' do_statement : DO statement WHILE LPAREN expression RPAREN SEMI ''' + p[0] = DoWhile(p[5], body=p[2]) + + def p_break_statement(self, p): + ''' break_statement : BREAK SEMI + | BREAK NAME SEMI + ''' + if len(p) == 3: + p[0] = Break() + else: + p[0] = Break(p[2]) + + def p_continue_statement(self, p): + ''' continue_statement : CONTINUE SEMI + | CONTINUE NAME SEMI + ''' + if len(p) == 3: + p[0] = Continue() + else: + p[0] = Continue(p[2]) + + def p_return_statement(self, p): + ''' return_statement : RETURN expression_opt SEMI ''' + p[0] = Return(p[2]) + + def p_throw_statement(self, p): + ''' throw_statement : THROW expression SEMI ''' + p[0] = Throw(p[2]) + + def p_try_statement(self, p): + ''' try_statement : TRY try_block catches + | TRY try_block catches_opt finally + ''' + if len(p) == 4: + p[0] = Try(p[2], catches=p[3]) + else: + p[0] = Try(p[2], catches=p[3], _finally=p[4]) + + def p_try_block(self, p): + ''' try_block : block ''' + p[0] = p[1] + + def p_catches(self, p): + ''' catches : catch_clause + | catches catch_clause + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + def p_catches_opt_1(self, p): + ''' catches_opt : catches ''' + p[0] = p[1] + + def p_catches_opt_2(self, p): + ''' catches_opt : empty ''' + p[0] = [] + + def p_catch_clause(self, p): + ''' catch_clause : CATCH LPAREN catch_formal_parameter RPAREN block ''' + p[0] = Catch(p[3]['variable'], _type=p[3]['type'], modifiers=p[3]['modifiers'], block=p[5]) + + def p_catch_formal_parameter(self, p): + ''' catch_formal_parameter : modifiers_opt type variable_declarator_id ''' + p[0] = {'modifiers': p[1], 'type': p[2], 'variable': p[3]} + + def p_finally(self, p): + ''' finally : FINALLY block ''' + p[0] = p[2] + + def p_class_instance_creation_expression_1(self, p): + ''' class_instance_creation_expression : NEW class_type LPAREN argument_list_opt RPAREN ''' + p[0] = InstanceCreation(p[2], p[4]) + + def p_field_access(self, p): + ''' field_access : primary_expression PERIOD NAME ''' + p[0] = FieldAccess(p[3], p[1]) + + def p_array_access(self, p): + ''' array_access : name LBRACKET expression RBRACKET + | primary_expression_no_new_array LBRACKET expression RBRACKET + | array_creation_with_array_initializer LBRACKET expression RBRACKET + ''' + p[0] = ArrayAccess(p[3], p[1]) + + def p_array_creation_with_array_initializer_1(self, p): + ''' array_creation_with_array_initializer : NEW primitive_type dim_with_or_without_exprs array_initializer ''' + p[0] = ArrayCreation(Type(p[2]), dimensions=p[3], initializer=p[4]) + + def p_array_creation_with_array_initializer_2(self, p): + ''' array_creation_with_array_initializer : NEW class_type dim_with_or_without_exprs array_initializer ''' + p[0] = ArrayCreation(p[2], dimensions=p[3], initializer=p[4]) + + def p_dim_with_or_without_exprs(self, p): + '''dim_with_or_without_exprs : dim_with_or_without_expr + | dim_with_or_without_exprs dim_with_or_without_expr''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + def p_dim_with_or_without_expr(self, p): + '''dim_with_or_without_expr : LBRACKET expression RBRACKET + | LBRACKET RBRACKET + ''' + if len(p) == 3: + p[0] = None + else: + p[0] = p[2] + + def p_array_creation_without_array_initializer_1(self, p): + ''' array_creation_without_array_initializer : NEW primitive_type dim_with_or_without_exprs ''' + p[0] = ArrayCreation(Type(p[2]), dimensions=p[3]) + + def p_array_creation_without_array_initializer_2(self, p): + ''' array_creation_without_array_initializer : NEW class_type dim_with_or_without_exprs ''' + p[0] = ArrayCreation(p[2], dimensions=p[3]) + +class TypeParser(BaseParser): + + def p_modifiers_opt_1(self, p): + ''' modifiers_opt : modifiers ''' + p[0] = p[1] + + def p_modifiers_opt_2(self, p): + ''' modifiers_opt : empty ''' + p[0] = [] + + def p_modifiers(self, p): + ''' modifiers : modifier + | modifiers modifier + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + def p_modifier(self, p): + ''' modifier : CONST + | RESIZEABLE + ''' + p[0] = p[1] + + def p_type_1(self, p): + ''' type : reference_type ''' + p[0] = p[1] + + def p_type_2(self, p): + ''' type : primitive_type ''' + p[0] = Type(p[1]) + + def p_primitive_type(self, p): + ''' primitive_type : BOOLEAN + | VOID + | BYTE + | SHORT + | INT + | LONG + | CHAR + | FLOAT + | DOUBLE + ''' + p[0] = Name(p[1]) + + def p_reference_type(self, p): + ''' reference_type : class_type + | array_type + ''' + p[0] = p[1] + + def p_class_type(self, p): + ''' class_type : name ''' + p[0] = Type(p[1]) + + def p_array_type(self, p): + ''' array_type : primitive_type dimensions + | name dimensions + ''' + p[0] = Type(p[1], dimensions=p[2]) + + +class CompilationParser(BaseParser): + + def p_pp_ifdef_compilation_unit_2(self, p): + ''' pp_ifdef_compilation_unit : HASH IFDEF NAME include_declarations block_statements HASH ENDIF ''' + if self.defines.get(p[3], False): + p[0] = CompilationUnit(includes=p[4], statements=p[5]) + + def p_compilation_unit_0(self, p): + ''' compilation_unit : pp_ifdef_compilation_unit ''' + p[0] = p[1] + + def p_compilation_unit_1(self, p): + ''' compilation_unit : include_declarations ''' + p[0] = CompilationUnit(includes=p[1]) + + def p_compilation_unit_2(self, p): + ''' compilation_unit : inherits_declaration ''' + p[0] = CompilationUnit(inherits=p[1]) + + def p_compilation_unit_3(self, p): + ''' compilation_unit : block_statements ''' + p[0] = CompilationUnit(statements=p[1]) + + def p_compilation_unit_4(self, p): + ''' compilation_unit : include_declarations inherits_declaration ''' + p[0] = CompilationUnit(includes=p[1], inherits=p[2]) + + def p_compilation_unit_5(self, p): + ''' compilation_unit : include_declarations block_statements ''' + p[0] = CompilationUnit(includes=p[1], statements=p[2]) + + def p_compilation_unit_6(self, p): + ''' compilation_unit : inherits_declaration block_statements ''' + p[0] = CompilationUnit(inherits=p[1], statements=p[2]) + + def p_compilation_unit_7(self, p): + ''' compilation_unit : include_declarations inherits_declaration block_statements ''' + p[0] = CompilationUnit(includes=p[1], inherits=p[2], statements=p[3]) + + def p_compilation_unit_8(self, p): + ''' compilation_unit : inherits_declaration include_declarations block_statements ''' + p[0] = CompilationUnit(inherits=p[1], includes=p[2], statements=p[3]) + + def p_compilation_unit_9(self, p): + ''' compilation_unit : empty ''' + p[0] = CompilationUnit() + + def p_inherits_declaration(self, p): + ''' inherits_declaration : INHERITS name semi_opt ''' + p[0] = InheritsDeclaration(p[2]) + + def p_include_declarations(self, p): + ''' include_declarations : include_declaration + | include_declarations include_declaration + ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = p[1] + [p[2]] + + def p_include_declaration(self, p): + ''' include_declaration : single_type_include_declaration + | type_include_on_demand_declaration + ''' + p[0] = p[1] + + def p_single_type_include_declaration(self, p): + ''' single_type_include_declaration : INCLUDE name semi_opt ''' + p[0] = IncludeDeclaration(p[2]) + + def p_type_include_on_demand_declaration(self, p): + ''' type_include_on_demand_declaration : INCLUDE name PERIOD TIMES semi_opt ''' + p[0] = IncludeDeclaration(p[2], on_demand=True) + + def p_semi_opt(self, p): + ''' semi_opt : SEMI + | empty + ''' + p[0] = p[1] + + +class MochaParser(ClassParser, CompilationParser, ExpressionParser, FunctionParser, LiteralParser, NameParser, StatementParser, TypeParser): + + tokens = MochaLexer.tokens + + precedence = ( + ('nonassoc', 'then'), + ('nonassoc', 'ELSE'), + ('left', 'LOR'), + ('left', 'LAND'), + ('left', 'OR'), + ('left', 'XOR'), + ('left', 'AND'), + ('left', 'EQ', 'NE'), + ('left', 'GT', 'GE', 'LT', 'LE'), + ('left', 'RSHIFT', 'LSHIFT'), + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE', 'MOD') + ) + + def __init__(self, + optimize_lex=True, + lextab='mocha.lextab', + optimize_yacc=True, + yacctab='mocha.yacctab', + debug=False): + super(MochaParser, self).__init__() + self.lexer = MochaLexer(self._lex_error_func) + self.lexer.build(optimize=optimize_lex, lextab=lextab, debug=debug) + self.parser = yacc.yacc(module=self, + start='root', + debug=debug, + optimize=optimize_yacc, + tabmodule=yacctab) + self.defines = { "DEBUG": True } + + def _lex_error_func(self, msg, line, column): + self._parse_error(msg, self._coord(line, column)) + + def tokenize_string(self, code): + self.lexer.input(code) + for token in self.lexer: + print(token) + + def tokenize_file(self, _file): + if type(_file) == str: + _file = file(_file) + content = '' + for line in _file: + content += line + return self.tokenize_string(content) + + def parse_expression(self, code, debug=0, lineno=1): + return self.parse_string(code, debug, lineno, prefix='--') + + def parse_statement(self, code, debug=0, lineno=1): + return self.parse_string(code, debug, lineno, prefix='* ') + + def parse_string(self, code, debug=0, lineno=1, prefix='++'): + self.lexer.lineno = lineno + return self.parser.parse(prefix + code, lexer=self.lexer, debug=debug) + + def parse_file(self, _file, debug=0): + if type(_file) == str: + _file = file(_file) + content = '' + for line in _file: + content += line + self.lexer.filename = _file.name + + res = () + + try: + res = self.parse_string(content, debug=debug) + except ParseError, e: + if debug: + raise + else: + print e + + return res + + def p_root_compilation_unit(self, p): + ''' root : PLUSPLUS compilation_unit ''' + p[0] = p[2] + + def p_root_expression(self, p): + """ root : MINUSMINUS expression + """ + p[0] = p[2] + + def p_root_statement(self, p): + """ root : TIMES block_statement + """ + p[0] = p[2] + + def p_empty(self, p): + ''' empty : ''' + + def p_error(self, p): + # If error recovery is added here in the future, make sure + # _get_yacc_lookahead_token still works! + # + if p: + self._parse_error( + 'before: %s' % p.value, + self._coord(lineno=p.lineno, + column=self.lexer.find_tok_column(p))) + else: + self._parse_error('At end of input', '') + diff --git a/utils/mocha/mocha/visit.py b/utils/mocha/mocha/visit.py new file mode 100644 index 000000000..aa72468c2 --- /dev/null +++ b/utils/mocha/mocha/visit.py @@ -0,0 +1,50 @@ +# visit.py + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + dispatcher = frame.f_locals[fn.func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = inspect.getargspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ # BUG FIX: use __class__ here + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.iterkeys() + for k in ks: + if issub(typ, k): + return t[k](*args, **kw) + + def add_target(self, typ, target): + self.targets[typ] = target diff --git a/utils/mocha/parse_expr.py b/utils/mocha/parse_expr.py new file mode 100755 index 000000000..c1bc29c63 --- /dev/null +++ b/utils/mocha/parse_expr.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import sys + +if len(sys.argv) == 1: + print('''usage: parse_expr.py ... + Example: parse_expr.py '1+2' '3' 'j = (int) i + 3' ''') + sys.exit(1) + +from mocha.parser import MochaParser + +parser = MochaParser() +for expr in sys.argv[1:]: + print(parser.parse_expression(expr)) diff --git a/utils/mocha/parse_file.py b/utils/mocha/parse_file.py new file mode 100755 index 000000000..7915c6095 --- /dev/null +++ b/utils/mocha/parse_file.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import sys + +if len(sys.argv) == 1: + print('''usage: parse_file.py ... + Example: parse_file.py path/to/file.script ''') + sys.exit(1) + +from mocha.parser import MochaParser + +parser = MochaParser() +for _file in sys.argv[1:]: + print(parser.parse_file(_file)) diff --git a/utils/mocha/parse_stmt.py b/utils/mocha/parse_stmt.py new file mode 100755 index 000000000..a948fdb00 --- /dev/null +++ b/utils/mocha/parse_stmt.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import sys + +if len(sys.argv) == 1: + print('''usage: parse_stmt.py ... + Example: parse_expr.py 'int a = 5;' ''') + sys.exit(1) + +from mocha.parser import MochaParser + +parser = MochaParser() +for stmt in sys.argv[1:]: + print(parser.parse_statement(stmt)) diff --git a/utils/mocha/prepare_all_scripts.sh b/utils/mocha/prepare_all_scripts.sh new file mode 100755 index 000000000..3be308236 --- /dev/null +++ b/utils/mocha/prepare_all_scripts.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +DIR="$( dirname "${BASH_SOURCE[0]}" )" +spinstr='|/-\' +i=0 +filenames=$(find $1 -type f \( -name '*.script' -o -name '*.scriptlib' \) -not -path "*/.deps/*") +current=0 +total=$(ls ${filenames[@]} | wc -l) +for filename in $filenames; do + OFILENAME=${filename//.scriptlib/.java} + OFILENAME=${OFILENAME//.script/.java} + + ok=1 + + if [[ -e $OFILENAME && $filename -nt $OFILENAME ]] || [ ! -e $OFILENAME ]; then + ${DIR}/script_prep2.py -i $filename -o $OFILENAME || ok=0 + + if [ ! $ok -eq 1 ]; then + printf "$filename $OFILENAME\n\n" + fi + fi + + current=$((current+1)) + i=$(( (i+1) %4 )) + perc=$(bc -l <<< "scale=0; $current*100/$total") + printf "\rConverting .scripts [${spinstr:$i:1}] $perc%%" +done + +echo "" diff --git a/utils/mocha/script_prep b/utils/mocha/script_prep new file mode 100755 index 000000000..66a31ee87 --- /dev/null +++ b/utils/mocha/script_prep @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +import sys +import mocha + +from mocha.parser import MochaParser +from mocha.generator import JavaClassGenerator + + +def main(): + sys.setrecursionlimit(5000) + + ifilename, ofilename = mocha.parse_input(sys.argv[1:]) + + package_name = mocha.build_package_name(ifilename) + class_name = mocha.build_class_name(package_name) + + parser = MochaParser() + generator = JavaClassGenerator() + + ast = parser.parse_file(ifilename) + + if ofilename is "": + print generator.generate(package_name, class_name, ast) + else: + with open(ofilename, "w") as java_file: + java_file.write(generator.generate(package_name, class_name, ast)) + +if __name__ == "__main__": + main() + diff --git a/utils/mocha/script_prep2.py b/utils/mocha/script_prep2.py new file mode 100755 index 000000000..b69ccb865 --- /dev/null +++ b/utils/mocha/script_prep2.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +import codecs +import os +import sys +import mocha + +from mocha.parser import MochaParser +from mocha.generator import JavaClassGenerator, JavaStaticClassGenerator +from mocha.model import FunctionDeclaration + +def main(): + sys.setrecursionlimit(5000) + + ifilename, ofilename = mocha.parse_input(sys.argv[1:]) + + ibase = mocha.get_script_base(ifilename) + package_name = mocha.build_package_name(ifilename) + class_name = mocha.build_class_name(ifilename) + + parser = MochaParser() + + if ifilename[-9:] == "scriptlib": + generator = JavaStaticClassGenerator() + else: + generator = JavaClassGenerator() + + ast = parser.parse_file(ifilename) + + functions = dict() + + #for inc in ast.includes: + # name = inc.name.value + # if len(name) >= 6 and name[:5] == "java.": + # continue + + # fname = "%s/script/%s.scriptlib" % (ibase, name.replace(".", "/")) + + # if not os.path.isfile(fname): + # continue + + # alias = name.split(".")[-1] + # dast = parser.parse_file(fname) + + # for stmt in dast.statements: + # if type(stmt) is FunctionDeclaration: + # func_name = "%s.%s" % (alias, stmt.name) + # functions[func_name] = {"return_type": stmt.return_type, "resizeable": True if "resizeable" in stmt.modifiers else False} + + if ofilename is "": + print generator.generate(package_name, class_name, ast, functions) + else: + with open(ofilename, "w") as java_file: + java_file.write(generator.generate(package_name, class_name, ast, functions)) + #with codecs.open(ofilename, "w", "utf-8") as java_file: + # java_file.write(generator.generate(package_name, class_name, ast, functions).decode("utf8")) + +if __name__ == "__main__": + main() + diff --git a/utils/mocha/test/comments.script b/utils/mocha/test/comments.script new file mode 100644 index 000000000..70234cc64 --- /dev/null +++ b/utils/mocha/test/comments.script @@ -0,0 +1,12 @@ + +// A line comment on its own line + +int a = 5; // A line comment after a statement + +int a = // A line comment in the middle of a multiline statement + 5; + +/* A + block comment + here + */ diff --git a/utils/mocha/test/empty.script b/utils/mocha/test/empty.script new file mode 100644 index 000000000..e69de29bb diff --git a/utils/mocha/test/for.script b/utils/mocha/test/for.script new file mode 100644 index 000000000..ac9e9ee23 --- /dev/null +++ b/utils/mocha/test/for.script @@ -0,0 +1,8 @@ + +for (int i = 0; i < 42; ++i) + test(); + +for (int i = 0; i < 42; ++i) +{ + test(); +} diff --git a/utils/mocha/test/function.script b/utils/mocha/test/function.script new file mode 100644 index 000000000..1530d70e0 --- /dev/null +++ b/utils/mocha/test/function.script @@ -0,0 +1,4 @@ +boolean addLoot( obj_id target ) +{ + return hasLoot; +} diff --git a/utils/mocha/test/if_else.script b/utils/mocha/test/if_else.script new file mode 100644 index 000000000..5b62135a4 --- /dev/null +++ b/utils/mocha/test/if_else.script @@ -0,0 +1,29 @@ + +if (t) + test(); + +if (t) { + test(); +} + +if (t) { + test(); +} +else + test2(); + + +if (t) { + test(); +} else { + test2(); +} + + +if (t) { + test(); +} else if (p) { + test2(); +} else { + ++i; +} diff --git a/utils/mocha/test/includes.script b/utils/mocha/test/includes.script new file mode 100644 index 000000000..e1ca2d664 --- /dev/null +++ b/utils/mocha/test/includes.script @@ -0,0 +1,22 @@ + +include library.ai_lib; +include library.buff; +include library.corpse; +include library.consumable; +include library.craftinglib; +include library.factions; +include library.healing; +include library.hue; +include library.money; +include library.pet_lib; +include library.resource; +include library.slots; +include library.static_item; +include library.storyteller; +include library.trace; +include library.utils; +include library.weapons; +include java.util.Arrays; +include java.util.Enumeration; +include java.util.Vector; +include java.util.*; diff --git a/utils/mocha/test/simple_statement.script b/utils/mocha/test/simple_statement.script new file mode 100644 index 000000000..143afbe5a --- /dev/null +++ b/utils/mocha/test/simple_statement.script @@ -0,0 +1,8 @@ + +int a = 5; + +a = 4; + +++a; + +; diff --git a/utils/mocha/test/switch.script b/utils/mocha/test/switch.script new file mode 100644 index 000000000..5395a842c --- /dev/null +++ b/utils/mocha/test/switch.script @@ -0,0 +1,13 @@ +switch(getContainerType(self)) +{ + case 0: + detachScript(self, "item.container.base.base_container"); + break; + case 1: + utils.requestContainerOpen(player, self); + break; + + default: + break; + +} diff --git a/utils/mocha/test/while.script b/utils/mocha/test/while.script new file mode 100644 index 000000000..53daa2c2f --- /dev/null +++ b/utils/mocha/test/while.script @@ -0,0 +1,9 @@ + +while(true) +{ + test(); +} + +do { + test(); +} while(true); diff --git a/utils/mocha/test_all_scripts.sh b/utils/mocha/test_all_scripts.sh new file mode 100755 index 000000000..187df5887 --- /dev/null +++ b/utils/mocha/test_all_scripts.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +for filename in $(find /home/apathy/projects/swgnge/dsrc/sku.0/sys.server/compiled/game/script -type f \( -name '*.script' -o -name '*.scriptlib' \) -not -path "*/.deps/*"); do + OUTPUT=$(./test_script.py $filename) + if [[ ! -z "$OUTPUT" ]]; then + echo " + +$OUTPUT + " >&2 + else + echo -n . + fi +done + +echo "Finished" diff --git a/utils/mocha/test_script.py b/utils/mocha/test_script.py new file mode 100755 index 000000000..16c134f06 --- /dev/null +++ b/utils/mocha/test_script.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +import sys + +if len(sys.argv) == 1: + print('''usage: test_script.py ... + Example: test_script.py '/path/to/file.script' ''') + sys.exit(1) + +from mocha.parser import MochaParser + +parser = MochaParser() +parser.parse_file(sys.argv[1]) diff --git a/utils/mocha/tokenizer.py b/utils/mocha/tokenizer.py new file mode 100755 index 000000000..01ed3f24b --- /dev/null +++ b/utils/mocha/tokenizer.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import sys + +if len(sys.argv) == 1: + print('''usage: tokenizer.py ... + Example: tokenizer.py '/path/to/file.script' ''') + sys.exit(1) + +from mocha.parser import MochaParser + +parser = MochaParser() +for filename in sys.argv[1:]: + print(parser.tokenize_file(filename))