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