def build_envs(files): """Lexes/Parses/does checking for all files in files.""" global find_all_in_package_cache find_all_in_package_cache = {} trees = [ElementTree.ElementTree(file="Array.xml").getroot()] files = ["$Array.java"] + files trees[0].filename = "$Array.java" for f in files[1:]: if f in cached_trees: trees += [cached_trees[f]] else: CurrentFile.name = f tree = parse(lex(open(f).read()), f) cached_trees[f] = tree trees += [tree] name_to_class = {} for tree in trees: CurrentFile.name = tree.filename clazz = find_type_decl(tree) name = clazz.get("canonical_name") error_if(name in name_to_class, "Duplicate class defined.") if name.find(".") != -1: name_to_class[name] = clazz for x in range(0, len(trees)): CurrentFile.name = trees[x].filename if trees[x] not in cached_environments: build_environments(trees[x], trees, name_to_class) cached_environments[files[x]] = trees[x].env for tree in trees: CurrentFile.name = tree.filename clazz = find_type_decl(tree) clazz.env.add_superclass_methods() clazz.env.add_superclass_fields() check_types(tree) check_hierarchy(tree) return trees
def initialize_compilation_unit_environment(self, name_to_class, tree, trees): pkg = "" if tree.find(".//package//name"): pkg = name_to_str(tree.find(".//package//name")) self.package_name = pkg this_clazz = find_type_decl(tree) self.classes_this[this_clazz.get("name")] = this_clazz self.classes_this["this"] = this_clazz self.classes_package = find_all_in_package(pkg, trees) self.add_single_type_import_statements(pkg, this_clazz, tree, trees) imported = [] self.add_import_star_statements(imported, tree, trees) add_dict(find_all_in_package(pkg, trees), self.classes_package) add_dict(name_to_class, self.classes_fully_qualified)
def find_all_in_package(packagename, trees): """Returns all classses in packagename.""" global find_all_in_package_cache if packagename in find_all_in_package_cache: return find_all_in_package_cache[packagename] retn = {} prefix = False for tree in trees: clazz = find_type_decl(tree) if clazz is None: continue if tree.find(".//package/name") is not None: package_name = name_to_str(tree.find(".//package/name")) if package_name == packagename: retn[clazz.get("name")] = clazz elif (packagename == package_name[:len(packagename)] and package_name[len(packagename)] == "."): prefix = True elif packagename == "": retn[clazz.get("name")] = clazz error_if(not prefix and len(retn.keys()) == 0, "No class in %s" % packagename) find_all_in_package_cache[packagename] = retn return retn
def __findclass(self, fullname, trees): """Returns the 'class' object for the class. Fullname: fully qualified name of a class pkg: package to look in trees: set of ASTs to look in """ name = fullname[fullname.rfind(".") + 1:] pkg = fullname[:fullname.rfind(".")] for tree in trees: clazz = find_type_decl(tree) if clazz is None: continue if name == clazz.get("name"): package_name = "" if tree.find(".//package/name") is not None: package_name = name_to_str(tree.find(".//package/name")) if ((package_name == "" and fullname == name) or (package_name == "java.lang" and fullname == name) or pkg == package_name or fullname[:len(fullname) - len(name) - 1] == package_name): return clazz error_if(True, "No class to import / Class Not Found.")
def check_and_generate(files): init_globals() # reset global state try: out = open("output/out.s", "w") trees = typechecker.check_files(files) initializer_list = [] mega_vtable_offset = 1 type_tag = 0 string_literal_index = 0 for tree in trees: clazz = find_type_decl(tree) clazz.type_tag = type_tag method_list.class_list += [clazz] type_tag += 1 methods = ( tree.findall(".//method") + tree.findall(".//constructor_declaration") + tree.findall(".//abstract_method") ) for method in methods: method.mega_vtable_offset = mega_vtable_offset mega_vtable_offset += 1 method_list.method_list += [method] if "static" in modifiers(method): slot = -2 else: slot = -3 for param in method.findall(".//param"): param.slot = slot slot -= 1 counters.mega_vtable_members = mega_vtable_offset for string_literal in tree.findall(".//string_literal"): string_literal.index = string_literal_index string_literal_index += 1 out.write(instanceof_table(trees)) for tree in trees: CurrentFile.name = tree.filename CurrentFile.mangled_name = CurrentFile.name.replace(".", "_").replace("$", "_").replace("/", "_") CurrentFile.static_slot = 0 for this in tree.findall(".//tok_this"): this.slot = -2 generate(tree) to_file(tree, tree.filename + ".xml") out.write("section .data\n") for clazz in tree.findall(".//class"): out.write(mega_vtable_for_class(clazz)) out.write("section .text\n") initializer_name = "static_init_" + CurrentFile.mangled_name out.write( """ ; global {initializer_name} {initializer_name}: push ebp mov ebp, esp sub esp, {frame_size} """.format( initializer_name=initializer_name, frame_size=CurrentFile.static_slot * 4 ) ) initializer_list.append(initializer_name) for field in tree.findall(".//field"): if "static" in modifiers(field): mangled_name = mangle_field_name(field) out.write( """ ; initializing {mangled_name} {field_assembly} mov eax, {mangled_name} mov ebx, {assigned_value} mov DWORD [eax], ebx """.format( mangled_name=mangled_name, field_assembly=field.assembly, assigned_value=stack_slot_to_operand(field.slot), ) ) out.write( """ leave ret ; done global static initialization """ ) for constructor in tree.findall(".//constructor_declaration"): out.write(constructor.assembly + "\n") for method in tree.findall(".//method"): if method.find("block") is not None: out.write(method.assembly + "\n") out.write("\nsection .data\n") for string_literal in tree.findall(".//string_literal"): string_value = string_literal.get("value") expanded_value = expand_string_literal(string_value) out.write("\n; string literal " + string_value + "\n") out.write("__string_literal_" + str(string_literal.index) + ":\n") out.write("dd _vtable_java_lang_$Array_ ; vtable pointer\n") out.write("dd -3 ; type tag for char\n") out.write("dd " + str(len(expanded_value)) + " ; string length\n") for character in expanded_value: out.write("dd " + str(hex(ord(character))) + "\n") out.write("") out.write("\nsection .bss\n") for field in tree.findall(".//field"): if "static" in modifiers(field): mangled_name = mangle_field_name(field) out.write("""{mangled_name} resb 4""".format(mangled_name=mangled_name) + "\n") out.write("section .text\n") out.write("; prelude\n") out.write("extern __malloc\n") out.write("extern __debexit\n") out.write("extern __exception\n") out.write("extern NATIVEjava.io.OutputStream.nativeWrite\n") out.write("global _start\n") out.write("_start:\n") out.write("call install_segv_handler\n") for initializer in initializer_list: out.write("call " + initializer + "\n") class_name = mangle_class_name(find_type_decl(trees[1]).get("canonical_name")) out.write("call " + class_name + "test_\n") out.write("mov ebx, eax\n") out.write("mov eax, 1\n") out.write("int 0x80 ; invoke exit(1)\n") out.write("; end prelude\n") out.write( """ %define __NR_signal 48 %define SIGSEGV 11 global install_segv_handler install_segv_handler: mov eax, __NR_signal mov ebx, SIGSEGV mov ecx, __exception int 0x80 ret """ ) return 0 except JoosSyntaxException, e: if Testing.testing: return 42 else: out.write("\n" + e.msg + "\n") raise
def check_types(tree): """Checks for type and other errors in tree.""" toks = tree.findall(".//package//tok_identifier") name = "" for ident in range(0, len(toks)): name += toks[ident].text error_if(name in tree.env.classes_fully_qualified and name.find(".") != -1, "Package prefix conflicts with class name.") if ident < len(toks) - 1: name += "." clazz = find_type_decl(tree) if clazz is None: return for _ in all_with_modifier(clazz, "method", "abstract"): error_if("abstract" not in modifiers(clazz), "Abstract methods must be in abstract classes.") for it in clazz.findall(".//implements/name") + clazz.findall( ".//extends/name") + clazz.findall( ".//extends_interfaces/name"): name = name_to_str(it) error_if(clazz.env.findclass(name) is None, "No class %s defined." % name) for type_use in clazz.findall(".//type") + clazz.findall( ".//class_instance_creation_expression/name"): name = "" toks = type_use.findall(".//tok_identifier") for ident in range(0, len(toks)): name += toks[ident].text if ident < len(toks) - 1: error_if(tree.env.findclass(name), "Prefixes of fully qualified type resolves to type.") name += "." if type_use.find(".//name") is not None: clazz_name = name_to_str(type_use.find(".//name")) error_if(not clazz.env.findclass(clazz_name), "Type " + clazz_name + " doesn't exist.") for i_type in clazz.findall(".//implements/name"): i_name = name_to_str(i_type) error_if(clazz.env.findclass(i_name) is not None and clazz.env.findclass(i_name).tag != "interface", "Must implement an interface class.") for c_type in clazz.findall(".//extends_interfaces/name"): c_name = name_to_str(c_type) error_if(clazz.env.findclass(c_name).tag != "interface", "Must extend an interface class.") error_if(clazz == clazz.env.findclass(c_name), "Class cannot extend itself") for inf in tree.findall(".//implements/name"): name = name_to_str(inf) error_if(clazz.env.findclass(name).tag != "interface", "%s is not an interface." % name) for clz in tree.findall(".//class_type/name") + tree.findall( ".//implements/name"): name = name_to_str(clz) error_if((tree.env.findclass(name) is None) or (tree.env.findclass( name).tag == "class"), "%s is not an interface." % name)