if (first_pass)
{
return node.args.evaluate(cx,this);
}
Slot slot = null;
if( node.ref != null )
{
slot = node.ref.getSlot(cx,GET_TOKEN);
// 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 (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, SET_TOKEN);
}
//TypeValue* dt = node->ref->getType(cx); // this uses use-definition trees, rather than the slot's def. Assume slot's def for warnings
int base_index = node.ref.getScopeIndex(SET_TOKEN);
int slot_index = node.ref.getSlotIndex(SET_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 )
checkDeprecatedSlot(cx, node.expr, node.ref, slot);
// 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))
{
}
else if (slot != null && slot.getType().getTypeValue() == cx.uintType() &&
node.args != null && node.args.items.size() == 1 && node.args.items.get(0) instanceof LiteralNumberNode)
{
LiteralNumberNode ln = (LiteralNumberNode)(node.args.items.get(0));
if (ln.numericValue.doubleValue() < 0)
warning(node.getPosition(), cx.input, kWarning_NegativeUintLiteral);
}
else if ( slot == null && is_unbound_ref)
{
int pos = (node.expr != null ? node.expr.getPosition() : node.getPosition());
boolean unsupported = false;
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())
{
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 unsupportedMethodsMap 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 type : search.keySet())
{
if (type != null && type.includes(cx,searchType))
{
unsupported = true;
warning(pos, cx.input, kWarning_DepricatedPropertyError, node.ref.name,
warningConstantsMap.get(search.get(type)));
}
}
}
}
if (unsupported == false && baseType != null ) // check for unsupported event handlers (StyleSheet.onLoad = new function() ... )
{
Map<TypeValue,Integer> search = unsupportedEventsMap.get(node.ref.name);
if (search != null && ! search.isEmpty()) // it matches a former auto-registered event handler name
{
ObjectValue scope = cx.scope();
if (baseType != null) // !!@todo: check that this dynamic var wasn't seen in an addEventListener call during first_pass
{
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 unsupportedMethodsMap 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 type : search.keySet())
{