예제 #1
0
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
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
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
예제 #6
0
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