}
}
else if( node.ref != null)
{
// nothing to evaluate, its an identifier
Slot slot = node.ref.getSlot(cx,GET_TOKEN); // check for base object type?
// special case for looking up a value of a class. ConstantEvaluator
// doesn't recognize direct Class references outside of the global scope, so
// it fails to set the ref's base correctly. It has to do this because when
// the function is called, its possible it will be called from a context where
// the global class definition has been superceeded by a local definition.
// This is pretty unlikely, however, and messes up the undeclared property reference
// detection. If the base of this expression (appears) to be the global definition for
// a class, temporarily reset the ref's base and use that definition.
TypeValue basetype = baseType_context.last();
if (slot == null && basetype != null && "Class".equals(basetype.name.toString()) )
{
ReferenceValue baseRef = baseRef_context.last();
if (baseRef != null)
{
ObjectValue realBase = (ObjectValue)(baseRef.getValue(cx));
ObjectValue oldBase = node.ref.getBase();
node.ref.setBase(realBase);
slot = node.ref.getSlot(cx,GET_TOKEN);
node.ref.setBase(oldBase);
}
}
// The last ditch, for handling Inteface base types. If there's a base type, see if its defined in its prototype.
// This definition is not good enough for code generation, but its good enough for a warning. Its pretty unlikely
// that the definition is superceeded at runtime.
if (slot == null && basetype != null && basetype.prototype != null && node.ref.name != null)
{
slot = getSlot(basetype.prototype, cx, node, GET_TOKEN);
}
if (slot != null )
checkDeprecatedSlot(cx, node, node.ref, slot);
TypeInfo ti = (slot != null) ? slot.getType() : null;
TypeValue type = (ti != null) ? ti.getTypeValue() : null;
result = type;
if (result == null)
{
result = cx.voidType();
}
else if (node.ref.name.compareTo("undefined")==0)
{
result = undefinedLiteral;
}
//TODO : remove this when these identifiers are declared in playerglobal.as
Boolean ignoreKeyword = hackIgnoreIdentifierMap.get(node.ref.name);
int base_index = node.ref.getScopeIndex(GET_TOKEN);
int slot_index = node.ref.getSlotIndex(GET_TOKEN);
boolean is_globalref = base_index == 0;
boolean is_dotref = base_index == -2;
boolean is_unbound_lexref = base_index == -1;
boolean is_unbound_dotref = is_dotref && slot_index < 0;
boolean is_unbound_globalref = is_globalref && slot_index < 0;
boolean is_unbound_ref = is_unbound_dotref || is_unbound_lexref || is_unbound_globalref;
if ( slot == null && (ignoreKeyword == null || !ignoreKeyword) && is_unbound_ref )
{
boolean unsupported = false;
// special case to avoid warning on access to a Class's prototype property. This
// property can't be expressed in global.as because you can't both declare a class
// and declare it to be an instance of the Class class.
if (basetype != null && "Class".equals(basetype.name.toString()) && "prototype".equals(node.ref.name))
{
return node.expr.evaluate(cx,this);
}
if (basetype == types[kDateType] || basetype == cx.regExpType() ||
(types[kErrorType] != null && types[kErrorType].includes(cx,basetype))) // these types are dynamic for backwards compatability, so ! doesn't catch this. Its unlikely anyone is adding dynamic props to them
{
warning(node.pos(), cx.input, kWarning_BadES3TypeProp, node.ref.name, basetype.name.name);
unsupported = true;
}
else
{
Map<TypeValue,Integer> search = unsupportedPropsMap.get(node.ref.name);
if (search != null && !search.isEmpty() ) // && search.second.empty() == false)
{
TypeValue searchType = baseType_context.last(); // todo: why is this more reliable than node->ref->base
// if this is an attempt to access a static member of a class, switch searchType to the class's type
// This is necessary to allow lookup in the unsupportedPropsMap table.
if (searchType != null && "Class".equals(searchType.name.toString()))
{
ReferenceValue br = baseRef_context.back();
Slot s = (br != null ? br.getSlot(cx,GET_TOKEN) : null);
// c++ variant accesses union member typValue directly, java stores value in objValue
TypeValue t = (s != null && s.getObjectValue() instanceof TypeValue) ? (TypeValue)(s.getObjectValue()) : null;
searchType = (t != null) ? t : searchType;
}
for(TypeValue matchType : search.keySet())
{