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;
}