def gen_cast_expr(info, node, method_obj): end_lbl = info.get_jump_label() output = ["; START gen_cast_expr"] output.extend(gen_expr(info, node[1], method_obj)) if primitives.is_primitive(node[1].typ): return output # check null output.append("cmp eax, 0") output.append("je %s" % end_lbl) output.append("push eax") canon = node[0].canon output.extend(util.gen_assignability_check(info, canon)) output.append("cmp eax, 0") output.append("je __exception") output.append("pop eax") output.append(end_lbl + ":") output.append("; END gen_creation_expr_array") return output
def is_array_assignable(type1, type2, c_i): if is_array_type(type1) and type2 == 'Null': return True elif is_array_type(type1) and not is_array_type(type2): return False if type1 == 'java.lang.Object' and is_array_type(type2): return True elif type1 == 'java.lang.Cloneable' and is_array_type(type2): return True elif type1 == 'java.io.Serializable' and is_array_type(type2): return True elif is_array_type(type1) and is_array_type(type2): atyp1 = get_arraytype(type1) atyp2 = get_arraytype(type2) if atyp1 == atyp2: return True # Unequal primitive types. elif primitives.is_primitive(atyp1) and primitives.is_primitive(atyp2): return False else: return is_nonstrict_subclass(atyp1, atyp2, c_i) else: return False
def typecheck_instanceof(node, c, method, t_i, c_i): expected_node = 'InstanceofExpression' if node.name != expected_node: logging.error('FATAL ERROR: expected', expected_node) sys.exit(1) lhs_type = typecheck_expr(node[0], c, method, t_i, c_i) rhs_type = node[1].canon if primitives.is_primitive(rhs_type): logging.error('Invalid Instanceof type %s' % rhs_type) sys.exit(42) if is_assignable(lhs_type, rhs_type, c_i) or \ is_assignable(rhs_type, lhs_type, c_i): node.typ = 'Boolean' return node.typ else: logging.error('Invalid %s instanceof %s' % (lhs_type, rhs_type)) sys.exit(42)
def typecheck_field_access(node, c, method, t_i, c_i): if node.name != 'FieldAccess': logging.error('FATAL ERROR: invalid node %s for field access' % node.name) sys.exit(1) receiver_type = typecheck_expr(node[1][0], c, method, t_i, c_i) field_name = node[0][0].value.value if receiver_type == None: logging.warning("FATAL: FieldAccess") return if is_array_type(receiver_type): if field_name == 'length': node.typ = 'Int' return 'Int' else: logging.error('Invalid field access on array type %s' % receiver_type) sys.exit(42) elif primitives.is_primitive(receiver_type) == True: logging.error('Invalid field access on primitive type %s' % receiver_type) else: field_decl = name_resolve.field_accessable(c_i, t_i, receiver_type, field_name, c.name, False) if field_decl is None: logging.error('Cannot access field %s of type %s from class %s' % (field_name, receiver_type, c.name)) sys.exit(42) elif 'Static' in field_decl.obj.mods: logging.error('Instance field method on non-static field') sys.exit(42) else: node.typ = field_decl[1].canon return node.typ
def typecheck_method_invocation(node, c, method, t_i, c_i): if node.name != 'MethodInvocation': logging.error('FATAL ERROR: invalid node %s for method invocation' % node.name) sys.exit(1) method_name = node[0][0].value.value # Get the type of whatever we're calling the method on. receiver_type = None is_static = False if len(node[1].children) == 0: receiver_type = c.name elif node[1][0].name == 'Name': if node[1][0].canon == None: receiver_type = typecheck_name(node[1][0]) else: receiver_type = node[1][0].canon is_static = True else: # Primary receiver_type = typecheck_expr(node[1][0], c, method, t_i, c_i) if primitives.is_primitive(receiver_type): logging.error('Cannot call method on primitive type %s' % receiver_type) sys.exit(42) if is_array_type(receiver_type): logging.error('Cannot call method on array type %s' % receiver_type) sys.exit(42) # Build types of arguments. arg_canon_types = [] for argument_expr in node[2].children: arg_canon_types.append(typecheck_expr(argument_expr, c, method, t_i, c_i)) # Call helper to find a method with the given signature (name and args). method_decl = name_resolve.method_accessable(c_i, t_i, receiver_type, method_name, arg_canon_types, c.name, not is_static) if method_decl == None: logging.error('Invalid method invocation') logging.error(" ", method_decl, receiver_type, method_name, arg_canon_types) sys.exit(42) if method_decl.name != 'MethodDeclaration': logging.error('Did not find method declaration') sys.exit(42) if 'Static' in method_decl.obj.mods and is_static == False: logging.error('Invalid static method invocation') sys.exit(42) elif 'Static' not in method_decl.obj.mods and is_static == True: logging.error('Invalid instance method invocation (of static method)') sys.exit(42) # Check for implicit This reference in static method if len(node[1].children) == 0 \ and method != None and 'Static' in method.mods \ and 'Static' not in method_decl.obj.mods: logging.error('Nonstatic access in a static method', method.name) sys.exit(42) # Link the invocation of the method with its declaration node.decl = method_decl # Get the return type of the method. node.typ = method_decl.obj.type return node.typ
def name_link_name(type_index, cu_env, pkg_name, local_vars, name_parts, disallowed_simple_names=None, check_locals=True, check_contains=True, check_type=True, check_this=True): """ name_parts is an array: e.g. ['a', 'b', 'c'] or ['this', 'c'] representing a.b.c or this.c """ global static_context_flag if len(name_parts) == 0: return None name_fields = [] if len(name_parts) > 0: name_fields = name_parts[1:] # the contain set of this class cu_canon = '%s.%s' % (pkg_name, environment.env_type_name(cu_env)) cu_contain_set = utils.class_hierarchy.contain(class_index[cu_canon]) try: field_i = cu_contain_set.index(Temp_Field(name_parts[0])) except ValueError: field_i = -1 # simple names should be enforced if they exist if disallowed_simple_names != None: if len(name_parts) == 1 and name_parts[0] in disallowed_simple_names: logging.error('Illegal forward declaration reference to %s', name_parts[0]) sys.exit(42) return None # special case for array.length if len(name_parts) == 2 \ and name_parts[0] in disallowed_simple_names \ and field_i != -1 \ and cu_contain_set[field_i].node.find_child('Type').canon.endswith('[]') \ and name_parts[1] == 'length': logging.error('Illegal forward declaration reference to %s', name_parts[0]) sys.exit(42) return None candidate = None canon_type = None is_type = False if name_parts[0] == 'this' and check_this: return name_link_name(type_index, cu_env, pkg_name, local_vars, name_fields) # is it a local variable? if name_parts[0] in local_vars and check_locals: candidate = local_vars[name_parts[0]] # is it in the contains set? elif field_i >= 0 and check_contains: candidate = cu_contain_set[field_i].node # can't be static in a static context if static_context_flag or 'static' in candidate.modifiers: logging.error('Cant reference to non-static in a static context') return None elif check_type: # we check the ambiguous name, one part at a time: for i, _ in enumerate(name_parts): type_candidate = name_parts[:i+1] canon_name = resolve_type_by_name(type_index, cu_env, pkg_name, '.'.join(type_candidate)) if canon_name: if (i+1 != len(name_parts)): canon_type = canon_name name_fields = name_parts[i+1:] is_type = True break else: # this is just a type! names can't be types return None # ACCESS CHECK FOR THE CANDIDATE! # first, we get its type if we don't already have it if candidate != None and len(name_fields) >= 1: # can we access the second part (which is a field) from here? # get canon type of candidate # candidate is a declaration astnode canon_type = candidate.find_child('Type').canon # now we check if we can access for the field's type if canon_type != None and len(name_fields) >= 1: # special case of Array if canon_type.endswith('[]'): if name_fields != ['length']: return None return primitives.array_length_node if primitives.is_primitive(canon_type): logging.error('%s is a primitive, does not have field %s' % \ (name_parts[0], name_fields)) return None fa = field_accessable(class_index, type_index, canon_type, name_fields[0], cu_canon, is_type == False) if fa != None: if is_type: if 'static' not in fa.modifiers: # uh oh, this has to be a static field! logging.error('%s is not static of type %s but is being \ accessed as one' % (fa, canon_type)) return None static_canon_type = fa.find_child('Type').canon if len(name_fields) >= 2: # i.e, MyClass.staticvar.MORESTUFF # switch context static_canon_type and work with the rest of # the name. if static_canon_type.endswith('[]'): if name_fields[1:] == ['length']: return primitives.array_length_node logging.error('Cannot access field %s of static array type %s' % (name_fields[1:], static_canon_type)) sys.exit(42) elif primitives.is_primitive(static_canon_type): logging.error('Primitives do not have fields to access!') return None #sys.exit(42) save_static_context = static_context_flag static_context_flag = False fa = name_link_name(type_index, type_index[static_canon_type], name_fields[1:], {}, # no locals check_type=False, check_this=False) static_context_flag = save_static_context return fa else: # not a type -- we can just recurse down save_static_context = static_context_flag static_context_flag = False ret = name_link_name(type_index, type_index[canon_type], canon_type.rsplit('.', 1)[0], {}, name_fields, check_type=check_type, check_this=check_this) static_context_flag = save_static_context return ret else: return None return candidate