def iteratively_name_link_nodes(type_index, cu_env, pkg_name, local_vars, name_nodes, disallowed_simple_names): for i in range(len(name_nodes)): name_slice_nodes = name_nodes[:i+1] name_slice = [n.value.value for n in name_slice_nodes] resolved_node_slice = name_link_name(type_index, cu_env, pkg_name, local_vars, name_slice, disallowed_simple_names) if resolved_node_slice != None: name_slice_nodes[-1].decl = resolved_node_slice else: canon_type = resolve_type_by_name(type_index, cu_env, pkg_name, '.'.join(name_slice)) if canon_type != None: name_slice_nodes[-1].canon = canon_type
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
def find_and_resolve_names(type_index, cu_env, pkg_name, stmt, local_vars, disallowed_simple_names=None): for node in find_nodes(stmt, [Node('Name'), Node('MethodInvocation'), Node('FieldAccess'), Node('ArrayAccess'), Node('Assignment')]): if node == Node('MethodInvocation'): # node.children = ['MethodName', 'MethodReceiver', 'Arguments'] # resolve the receiver as much as possible meth_recv = node[1] if len(meth_recv.children) > 0: if meth_recv[0] == Node('Name'): meth_recv_name = '.'.join(meth_recv.leaf_values()) name_node = meth_recv[0] resolved_node = name_link_name(type_index, cu_env, pkg_name, local_vars, meth_recv_name.split('.'), disallowed_simple_names) canon_type = resolve_type_by_name(type_index, cu_env, pkg_name, meth_recv_name) # it could an ambig name if resolved_node != None: name_node.decl = resolved_node name_node.typ = resolved_node.find_child('Type').canon name_node.canon = node.typ # it could be a static type elif canon_type != None: name_node.canon = canon_type else: logging.error('method receiver %s could not be resolved!' % (meth_recv_name)) sys.exit(42) # iteratively resolve the method receiver's identifier -- # used during codegen iteratively_name_link_nodes(type_index, cu_env, pkg_name, local_vars, meth_recv.leafs(), disallowed_simple_names) else: # resolve some more! find_and_resolve_names(type_index, cu_env, pkg_name, meth_recv, local_vars, disallowed_simple_names) # if it has arguments, name resolve those if len(node.children) == 3: find_and_resolve_names(type_index, cu_env, pkg_name, node[2], local_vars, disallowed_simple_names) continue elif node == Node('ArrayAccess'): # node.children = ['ArrayReceiver', 'Primary'] find_and_resolve_names(type_index, cu_env, pkg_name, node[0], local_vars, {}) find_and_resolve_names(type_index, cu_env, pkg_name, node[1], local_vars, disallowed_simple_names) continue elif node == Node('FieldAccess'): # this? # node.children = ['FieldName', 'FieldReceiver'] if node[1][0] == Node('This'): name = ['this'] + node[0].leaf_values() name_nodes = [node[1][0]] + node[0].leafs() else: find_and_resolve_names(type_index, cu_env, pkg_name, node[1], local_vars, disallowed_simple_names) continue elif node == Node('Assignment'): find_and_resolve_names(type_index, cu_env, pkg_name, ASTNode(children=[node[0]]), local_vars) find_and_resolve_names(type_index, cu_env, pkg_name, ASTNode(children=[node[1]]), local_vars, disallowed_simple_names) continue elif node == Node('Name'): name = node.leaf_values() name_nodes = node.leafs() resolved_node = name_link_name(type_index, cu_env, pkg_name, local_vars, name, disallowed_simple_names) if resolved_node == None: logging.error('Could not resolve name %s in %s.%s with %s' % (name, pkg_name, cu_env['ClassDeclaration'], local_vars)) sys.exit(42) # now lets label each part of this ambiguous name iteratively_name_link_nodes(type_index, cu_env, pkg_name, local_vars, name_nodes, disallowed_simple_names) node.decl = resolved_node node.typ = resolved_node.find_child('Type').canon