Beispiel #1
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