public Value evaluate()

in modules/asc/src/java/macromedia/asc/semantics/FlowAnalyzer.java [3180:3462]


    public Value evaluate(Context cx, VariableBindingNode node)
    {

        boolean is_intrinsic = false;
        boolean is_const     = node.kind == CONST_TOKEN;

        Namespaces namespaces = new Namespaces();

        ObjectList<String> namespace_ids = new ObjectList<String>();

        if( node.attrs != null) // already been evaluated by VariableDefinitionNode
        {
            if( node.attrs.hasVirtual && node.attrs.hasFinal )
            {
                cx.error(node.pos(), kError_VarIsFinalAndVirtual);
            }
            if( node.attrs.hasNative )
            {
                cx.error(node.pos(), kError_NativeVars);
            }
            if( node.attrs.hasVirtual )
            {
                cx.error(node.pos(), kError_VirtualVars);
            }

            is_intrinsic = node.attrs.hasIntrinsic;
        }

        if( node.attrs == null && node.variable.type == null )
        {
            ObjectValue ns = default_namespaces.back();
            namespaces.push_back(ns);
            namespace_ids.push_back(ns.name);
            NodeFactory nf = cx.getNodeFactory();
            boolean isPublic = ns == cx.publicNamespace();
            AttributeListNode aln = nf.attributeList(nf.identifier(isPublic?PUBLIC:INTERNAL,false,node.variable.pos()),null);
            if (isPublic)
            {
                aln.hasPublic = true;
            }
            else
            {
                aln.hasInternal = true;
            }
            aln.namespaces.push_back(ns);
            if( node.variable.identifier instanceof QualifiedIdentifierNode )
            {
                ((QualifiedIdentifierNode)node.variable.identifier).qualifier = aln;
            }
            else
            {
                node.variable.identifier = nf.qualifiedIdentifier(aln, node.variable.identifier.name, node.variable.identifier.pos());
            }
            Value val = node.variable.identifier.evaluate(cx,this);
            node.ref = (val instanceof ReferenceValue) ? (ReferenceValue) val : null;
        }
        else
        {
            computeNamespaces( cx, node.attrs, namespaces, namespace_ids );
            Value val = node.variable.identifier.evaluate(cx,this);
            node.ref = (val instanceof ReferenceValue) ? (ReferenceValue) val : null;

            if (node.inPackage() == false && cx.getScopes().size() == 1 && node.attrs != null)
            {
                if( node.attrs.hasAttribute(PUBLIC) )
                    cx.error(node.attrs.pos(), kError_InvalidPublic);
            }
        }

        Value val = node.variable.identifier.evaluate(cx,this);
        node.ref = ((val instanceof ReferenceValue) ? (ReferenceValue)val : null);

        if (node.initializer != null)
        {
        	if( cx.statics.es4_nullability && cx.scope().builder instanceof InstanceBuilder )
        	{
        		// Initializers for instance variables should not have access to this.
        		cx.scope().setInitOnly(true);
            	this_contexts.push_back(init_this);
        	}
        	
            node.initializer.evaluate(cx,this);

        	if( cx.statics.es4_nullability && cx.scope().builder instanceof InstanceBuilder )
        	{
        		cx.scope().setInitOnly(false);
            	this_contexts.pop_back();
        	}
         }

        ObjectValue obj = getVariableDefinitionScope(cx);

        Builder bui = obj.builder;

        int slot_id = -1;

        if( bui instanceof InstanceBuilder && node.ref.name.equals(fun_name_stack.back()))
        {
            cx.error(node.pos(), kError_ConstructorsMustBeInstanceMethods);
        }

        Namespaces open_definition_namespaces ;
        if( node.attrs != null && node.attrs.hasUserNamespace() )
        {
            open_definition_namespaces = namespaces;
        }
        else
        {
            open_definition_namespaces = used_def_namespaces_sets.back();
        }

        if (node.variable.type != null)
        {
            rt_unresolved_sets.last().addAll(unresolved);
            unresolved.clear();

            /* We used to get node.typeref from the result of node.variable.type.eval
             * Having changed MemberExprNodes so that they return cx.object().prototype,
             * rather than node.ref, this is a workaround to setting the correct typeref: */
            val = node.variable.type.evaluate(cx,this);

            obj = getVariableDefinitionScope(cx);
            if (obj.builder instanceof ActivationBuilder)
            {
                body_unresolved_sets.last().addAll(unresolved);
            }
            else
            {
                ce_unresolved_sets.last().addAll(unresolved);
            }
            unresolved.clear();

            node.typeref = ((val instanceof ReferenceValue) ? (ReferenceValue)val : null);
            if( node.typeref != null )
            {
                node.typeref.setTypeAnnotation(true);
            }
            else
            {
                // If the type didn't resolve to a reference value then it's clearly going to be unknown
                cx.error(node.variable.type.pos(), kError_UnknownType, "");
            }
        }

        int kind = GET_TOKEN;
        Namespaces matchingNamespaces = obj.hasNames(cx,GET_TOKEN,node.ref.name,open_definition_namespaces);
        if( matchingNamespaces == null )
        {
            matchingNamespaces = obj.hasNames(cx, SET_TOKEN, node.ref.name, open_definition_namespaces);
            kind = SET_TOKEN;
        }
        if( matchingNamespaces == null )
        {
            // Allocate space for the variable and create the property
            // slots. A property is represented at compile-time as a
            // name and a pair of accessors (getter and setter).

            TypeValue type = cx.noType();
                    // ISSUE: the actual slot type is computed at constanteval time.
                    // make sure that is never too late

            if( bui.is_intrinsic || is_intrinsic )
            {
                slot_id = bui.ExplicitVar(cx,obj,node.ref.name,namespaces,type,-1);
            }
            else
            {
                int var_id;
                var_id  = bui.Variable(cx,obj);
                slot_id = bui.ExplicitVar(cx,obj,node.ref.name,namespaces,type,-1,-1,var_id);
                Slot slot = obj.getSlot(cx,slot_id);
                slot.setConst(is_const);
                slot.setTypeRef(node.typeref);

                if( (node.block != null) ||  // node.block is null for defintions at the top level of the method 
                	(node.initializer == null) )
                {
                	// Need to init the local at the beginning of the method
                	// so that the types at the backwards branch will match at 
                	// verify time.
                	slot.setNeedsInit(true);
                }
            }
        }
        else
        {
            String nsstr = "";
            for (ObjectValue ns : matchingNamespaces)
            {
                if (nsstr.length() != 0)
                    nsstr += " ";

                if (ns.name.length() == 0)
                {
                    nsstr += PUBLIC;
                }
                else
                {
                    switch( ns.getNamespaceKind() )
                    {
                        case Context.NS_PRIVATE:
                            nsstr += PRIVATE;
                            break;
                        case Context.NS_INTERNAL:
                            nsstr += INTERNAL;
                            break;
                        case Context.NS_PROTECTED:
                            nsstr += PROTECTED;
                            break;
                        default:
                            nsstr += ns.name;
                            break;
                    }
                }
            }

            int slot_index = obj.getSlotIndex(cx, kind,node.ref.name, matchingNamespaces.back());
            Slot orig = obj.getSlot(cx, slot_index);

            boolean isGlobalDefinition = bui instanceof GlobalBuilder && !node.inPackage();
            boolean isLocalDefinition  = bui instanceof ActivationBuilder;
            boolean isGlobalOrLocalDefinition = isGlobalDefinition || isLocalDefinition;

            if( isGlobalOrLocalDefinition && node.attrs == null && node.variable.type == null )
            {
                if( orig.getType().getTypeValue() == cx.typeType() || orig.isConst() )
                {
                    // attempting to declare a var with the same name as a class, don't allow that
                    cx.error(node.variable.identifier.pos(), kError_ConflictingNameInNamespace, node.ref.name, "internal");
                }
                else
                {
                    // ed.3 decl, so let it go
                    // need to modify the qualified identifers attribute list, so that the
                    // qualified identifier node that was auto generated for the init statement will refer to the correct namespace
                    NodeFactory nf = cx.getNodeFactory();
                    AttributeListNode aln = nf.attributeList(nf.identifier(matchingNamespaces.back().name,node.variable.pos()),null);
                    aln.items.clear();
                    aln.namespaces.addAll(matchingNamespaces);
                    if( node.variable.identifier instanceof QualifiedIdentifierNode )
                    {
                        ((QualifiedIdentifierNode)node.variable.identifier).qualifier = aln;
                    }
                    else
                    {
                        node.variable.identifier = nf.qualifiedIdentifier(aln, node.variable.identifier.name, node.variable.identifier.pos());
                    }
                    node.variable.identifier.ref = null; // force this to be regenerated since the namespace has probably changed
                    Value val2 = node.variable.identifier.evaluate(cx,this);
                    node.ref = (val instanceof ReferenceValue) ? (ReferenceValue) val2 : null;
                }
            }
            else
            if( orig.declaredBy != obj )
            {
                String fullname = getFullNameForInheritedSlot(cx, orig.declaredBy, node.ref.name);
                cx.error(node.variable.identifier.pos(), kError_ConflictingInheritedNameInNamespace, fullname, nsstr);
            }
            else
            {
                if( isGlobalOrLocalDefinition && !orig.isConst() && (orig.getTypeRef()==null || node.typeref==null || orig.getTypeRef().name.equals(node.typeref.name)) )
                {
                    // compatible definitions so allow
                }
                else
                {
                    cx.error(node.variable.identifier.pos(), kError_ConflictingNameInNamespace, node.ref.name, "internal");
                }
            }
            if( (node.block != null) ||  // node.block is null for defintions at the top level of the method 
                	(node.initializer == null) )
            {
            	// Need to init the local at the beginning of the method
            	// so that the types at the backwards branch will match at 
            	// verify time.
            	orig.setNeedsInit(true);
            }
            
        }

        node.debug_name = cx.debugName(region_name_stack.back(),node.ref.name,namespace_ids,VAR_TOKEN);
        return null;
    }