def method_invocation(element): if element[0].tag == "name": name = name_to_str(element.find("name")) to_file(element) declaration_site = element.env.get_declaration_site_for_method_name( name, argument_list(element)) element.attrib["type"] = element.env.get_type_for_declaration_site( declaration_site) element.declaration = declaration_site elif element[0].tag == "primary": primary_type = element[0].attrib["type"] error_if(is_primitive(primary_type), "Cannot invoke method on primitive " + primary_type) declaration_site = element.env.get_declaration_site_for_class_name( primary_type) identifier = element.find("tok_identifier").text method_declaration = \ declaration_site.env.get_declaration_site_for_method_name( identifier, argument_list(element)) element.attrib["type"] = \ method_declaration.env.get_type_for_declaration_site( method_declaration) element.declaration = method_declaration else: assert False
def typecheck_other_conditions(tree): """Takes an abstract syntax tree which has Environments associated with it and typechecks it. Raises JoosSyntaxException if the tree does not typecheck.""" # A constructor in a class other than java.lang.Object implicitly calls the # zero-argument constructor of its superclass. Check that this # zero-argument constructor exists. # # Check that the name of a constructor is the same as the name of its # enclosing class. for ctor in tree.findall(".//constructor_declaration"): clazz = ctor.env.findclass(ctor.get("name")) superclazz = clazz.superclass error_if(not superclazz.env.find_constructor(tuple([])), "No zero-argument constructor") for lhs in tree.findall(".//assignment/left_hand_side"): if lhs.find("./name") is None: continue type_name = name_to_str(lhs.find("./name")) type_decl = lhs.env.get_declaration_site_for_variable_name(type_name, lhs.find("./name")) error_if("final" in modifiers(type_decl), "Final field on LHS") #Check that no objects of abstract classes are created. for expr in tree.findall(".//class_instance_creation_expression"): expr_type = name_to_str(expr.find("./name")) instantiated_class = tree.env.findclass(expr_type) error_if("abstract" in modifiers(instantiated_class) or instantiated_class.tag == "interface", "Cannot instantiate abstract classes.") class_name = instantiated_class.get("canonical_name") ctor_decl = expr.env.get_declaration_site_for_constructor_name( class_name, argument_list(expr)) error_if(expr.env.find_package_name() != ctor_decl.env.find_package_name() and "protected" in modifiers(ctor_decl), "Invocation of Protected Constructor.") # Check that the implicit this variable is not accessed in a static method # or in the initializer of a static field. for smethod in \ [x for x in tree.findall(".//method") if "static" in modifiers(x)]: error_if(smethod.find(".//tok_this") is not None, "Cannot acces this in static method.") for field in \ [x for x in tree.findall(".//field") if "static" in modifiers(x)]: error_if(field.find(".//tok_this") is not None, "Cannot acces this in static field.") #if_then_stmts = tree.find(".//if_then_statement/expression//assignment") #error_if(if_then_stmts is not None, #"No assignment in if_then expressions") while_stmts = tree.find(".//while_statement/expression//assignment")
def method_invocation(subtree): method = subtree.declaration subtree.slot = generate_new_stack_slot(subtree) pushes = push_arguments(subtree) if "static" not in modifiers(method): if subtree[0].tag == "name": name(subtree[0], args=argument_list(subtree)) pushes.append("push " + stack_slot_to_operand(subtree[0].slot)) return_slot = stack_slot_to_operand(subtree.slot) if "native" in modifiers(method): call = "call " + mangle_native_fn_name(subtree.declaration) argument_slot = subtree.find("./argument_list").slot operand = stack_slot_to_operand(argument_slot) pushes = ["mov eax, {slot}".format(slot=operand)] elif "static" in modifiers(method): call = "call " + mangle_fn_name(subtree.declaration) else: call = """ mov eax, {this_ptr} mov eax, [eax] add eax, {method_offset} mov eax, [eax] call eax """.format( this_ptr=stack_slot_to_operand(subtree[0].slot), method_offset=str(4 * method.mega_vtable_offset) ) subtree.assembly = """ ; method invocation {dbg} {push_arguments} {call} mov {return_slot}, eax ; end method invocation """.format( dbg=collect_debug_text(subtree), call=call, push_arguments="\n".join(pushes), return_slot=return_slot )
def resolve_constructor_name(element): return element.env.get_declaration_site_for_constructor_name( name_to_str(element.find("name")), argument_list(element))