QQmlJS::IR::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode);
if (!f)
continue;
+
ctx->strictMode = f->isStrict;
if (debugger)
debugger->aboutToCall(0, ctx);
glo->__put__(rootContext, identifier(QStringLiteral("TypeError")), typeErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("URIError")), uRIErrorCtor);
glo->__put__(rootContext, identifier(QStringLiteral("Math")), Value::fromObject(newMathObject(rootContext)));
- glo->__put__(rootContext, identifier(QStringLiteral("undefined")), Value::undefinedValue());
- glo->__put__(rootContext, identifier(QStringLiteral("NaN")), Value::fromDouble(nan("")));
- glo->__put__(rootContext, identifier(QStringLiteral("Infinity")), Value::fromDouble(INFINITY));
+
+ PropertyDescriptor pd;
+ pd.type = PropertyDescriptor::Data;
+ pd.writable = PropertyDescriptor::Unset;
+ pd.enumberable = PropertyDescriptor::Unset;
+ pd.configurable = PropertyDescriptor::Unset;
+
+ pd.value = Value::undefinedValue();
+ glo->__defineOwnProperty__(rootContext, identifier(QStringLiteral("undefined")), &pd);
+ pd.value = Value::fromDouble(nan(""));
+ glo->__defineOwnProperty__(rootContext, identifier(QStringLiteral("NaN")), &pd);
+ pd.value = Value::fromDouble(INFINITY);
+ glo->__defineOwnProperty__(rootContext, identifier(QStringLiteral("Infinity")), &pd);
+
glo->__put__(rootContext, identifier(QStringLiteral("eval")), Value::fromObject(new EvalFunction(rootContext)));
// TODO: parseInt [15.1.2.2]
return object;
}
-Object *ExecutionEngine::newActivationObject(ExecutionContext *ctx)
+Object *ExecutionEngine::newActivationObject()
{
- return new ActivationObject(ctx);
+ return new Object();
}
Object *ExecutionEngine::newForEachIteratorObject(Object *o)
struct FunctionObject;
struct RegExpObject;
struct ErrorObject;
-struct ActivationObject;
struct ArgumentsObject;
struct ExecutionContext;
struct ExecutionEngine;
Object *newTypeErrorObject(ExecutionContext *ctx, const QString &message);
Object *newMathObject(ExecutionContext *ctx);
- Object *newActivationObject(ExecutionContext *ctx);
+ Object *newActivationObject();
Object *newForEachIteratorObject(Object *o);
};
if (__qmljs_string_equal(function->formalParameterList[i], name))
return true;
}
+ if (activation)
+ return activation->__hasProperty__(this, name);
return false;
}
-void ExecutionContext::createMutableBinding(ExecutionContext *ctx, String *name, bool deletable)
+void ExecutionContext::createMutableBinding(String *name, bool deletable)
{
if (!activation)
- activation = engine->newActivationObject(this);
+ activation = engine->newActivationObject();
- if (activation->__hasProperty__(ctx, name))
+ if (activation->__hasProperty__(this, name))
return;
PropertyDescriptor desc;
desc.value = Value::undefinedValue();
desc.configurable = deletable ? PropertyDescriptor::Set : PropertyDescriptor::Unset;
desc.writable = PropertyDescriptor::Set;
desc.enumberable = PropertyDescriptor::Set;
- activation->__defineOwnProperty__(ctx, name, &desc);
+ activation->__defineOwnProperty__(this, name, &desc);
}
-void ExecutionContext::setMutableBinding(String *name, Value value, bool strict)
+bool ExecutionContext::setMutableBinding(ExecutionContext *scope, String *name, Value value)
{
- Q_UNUSED(strict);
- assert(function);
-
- // ### throw if strict is true, and it would change an immutable binding
+ // ### throw if scope->strict is true, and it would change an immutable binding
for (unsigned int i = 0; i < variableCount(); ++i) {
if (__qmljs_string_equal(variables()[i], name)) {
locals[i] = value;
- return;
+ return true;
}
}
for (unsigned int i = 0; i < formalCount(); ++i) {
if (__qmljs_string_equal(formals()[i], name)) {
arguments[i] = value;
- return;
+ return true;
}
}
- assert(false);
+ if (activation && activation->__hasProperty__(scope, name)) {
+ activation->__put__(scope, name, value);
+ return true;
+ }
+
+ return false;
}
-Value ExecutionContext::getBindingValue(String *name, bool strict) const
+Value ExecutionContext::getBindingValue(ExecutionContext *scope, String *name, bool strict) const
{
Q_UNUSED(strict);
assert(function);
if (__qmljs_string_equal(formals()[i], name))
return arguments[i];
}
+ if (activation && activation->__hasProperty__(this, name))
+ return activation->__get__(scope, name);
assert(false);
}
-bool ExecutionContext::deleteBinding(ExecutionContext *ctx, String *name)
+bool ExecutionContext::deleteBinding(ExecutionContext *scope, String *name)
{
if (activation)
- activation->__delete__(ctx, name);
+ activation->__delete__(scope, name);
- if (ctx->strictMode)
- __qmljs_throw_type_error(ctx);
+ if (scope->strictMode)
+ __qmljs_throw_type_error(scope);
return false;
}
ctx->activation->__delete__(this, name);
}
}
- // ### throw syntax error in strict mode
+ if (strictMode)
+ throwSyntaxError(0);
return true;
}
+void ExecutionContext::setProperty(String *name, Value value)
+{
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer()) {
+ if (ctx->withObject) {
+ With *w = ctx->withObject;
+ while (w) {
+ if (w->object->__hasProperty__(ctx, name)) {
+ w->object->__put__(ctx, name, value);
+ return;
+ }
+ w = w->next;
+ }
+ }
+ if (ctx->setMutableBinding(this, name, value))
+ return;
+ }
+ if (strictMode)
+ throwReferenceError(Value::fromString(name));
+ engine->globalObject.objectValue()->__put__(this, name, value);
+}
+
+Value ExecutionContext::getProperty(String *name)
+{
+ PropertyDescriptor tmp;
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer()) {
+ if (ctx->withObject) {
+ With *w = ctx->withObject;
+ while (w) {
+ if (PropertyDescriptor *pd = w->object->__getPropertyDescriptor__(this, name, &tmp))
+ return pd->value;
+ w = w->next;
+ }
+ }
+
+ for (unsigned int i = 0; i < ctx->variableCount(); ++i)
+ if (__qmljs_string_equal(ctx->variables()[i], name))
+ return ctx->locals[i];
+ for (unsigned int i = 0; i < ctx->formalCount(); ++i)
+ if (__qmljs_string_equal(ctx->formals()[i], name))
+ return ctx->arguments[i];
+ if (ctx->activation && ctx->activation->__hasProperty__(ctx, name))
+ return ctx->activation->__get__(ctx, name);
+ if (name->isEqualTo(ctx->engine->id_arguments)) {
+ Value arguments = Value::fromObject(new ArgumentsObject(this));
+ createMutableBinding(ctx->engine->id_arguments, false);
+ setMutableBinding(this, ctx->engine->id_arguments, arguments);
+ return arguments;
+ }
+ }
+ throwReferenceError(Value::fromString(name));
+ return Value::undefinedValue();
+}
+
+
+
void ExecutionContext::inplaceBitOp(Value value, String *name, BinOp op)
{
for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer()) {
std::fill(locals, locals + function->varCount, Value::undefinedValue());
if (function->needsActivation)
- activation = engine->newActivationObject(this);
+ activation = engine->newActivationObject();
else
activation = 0;
void init(ExecutionEngine *e);
bool hasBinding(String *name) const;
- void createMutableBinding(ExecutionContext *ctx, String *name, bool deletable);
- void setMutableBinding(String *name, Value value, bool strict);
- Value getBindingValue(String *name, bool strict) const;
+ void createMutableBinding(String *name, bool deletable);
+ bool setMutableBinding(ExecutionContext *scope, String *name, Value value);
+ Value getBindingValue(ExecutionContext *scope, String *name, bool strict) const;
bool deleteBinding(ExecutionContext *ctx, String *name);
void pushWithObject(Object *with);
void throwUnimplemented(const QString &message);
PropertyDescriptor *lookupPropertyDescriptor(String *name, PropertyDescriptor *tmp);
+ void setProperty(String *name, Value value);
+ Value getProperty(String *name);
void inplaceBitOp(Value value, String *name, BinOp op);
bool deleteProperty(String *name);
}
// Section 8.12.6
-bool Object::__hasProperty__(ExecutionContext *ctx, String *name) const
+bool Object::__hasProperty__(const ExecutionContext *ctx, String *name) const
{
if (members)
return members->find(name) != 0;
__qmljs_throw_type_error(ctx);
}
- if (!ctx->activation)
- ctx->activation = new QQmlJS::VM::Object();
-
- foreach (const QString *local, globalCode->locals) {
- ctx->activation->__put__(ctx, *local, QQmlJS::VM::Value::undefinedValue());
- }
return globalCode;
}
return ctx->thisObject;
}
-PropertyDescriptor *ActivationObject::__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill)
-{
- if (context) {
- for (unsigned int i = 0; i < context->variableCount(); ++i) {
- String *var = context->variables()[i];
- if (__qmljs_string_equal(var, name)) {
- *to_fill = PropertyDescriptor::fromValue(context->locals[i]);
- to_fill->writable = PropertyDescriptor::Set;
- to_fill->enumberable = PropertyDescriptor::Set;
- return to_fill;
- }
- }
- for (unsigned int i = 0; i < context->formalCount(); ++i) {
- String *formal = context->formals()[i];
- if (__qmljs_string_equal(formal, name)) {
- *to_fill = PropertyDescriptor::fromValue(context->arguments[i]);
- to_fill->writable = PropertyDescriptor::Set;
- to_fill->enumberable = PropertyDescriptor::Set;
- return to_fill;
- }
- }
- if (name->isEqualTo(ctx->engine->id_arguments)) {
- if (arguments.isUndefined()) {
- arguments = Value::fromObject(new ArgumentsObject(ctx));
- arguments.objectValue()->prototype = ctx->engine->objectPrototype;
- }
-
- *to_fill = PropertyDescriptor::fromValue(arguments);
- to_fill->writable = PropertyDescriptor::Unset;
- to_fill->enumberable = PropertyDescriptor::Unset;
- return to_fill;
- }
- }
-
- return Object::__getPropertyDescriptor__(ctx, name, to_fill);
-}
Value ArgumentsObject::__get__(ExecutionContext *ctx, String *name)
{
struct FunctionObject;
struct RegExpObject;
struct ErrorObject;
-struct ActivationObject;
struct ArgumentsObject;
struct ExecutionContext;
struct ExecutionEngine;
virtual FunctionObject *asFunctionObject() { return 0; }
virtual RegExpObject *asRegExpObject() { return 0; }
virtual ErrorObject *asErrorObject() { return 0; }
- virtual ActivationObject *asActivationObject() { return 0; }
virtual ArgumentsObject *asArgumentsObject() { return 0; }
virtual Value __get__(ExecutionContext *ctx, String *name);
virtual PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill);
virtual void __put__(ExecutionContext *ctx, String *name, Value value);
virtual bool __canPut__(ExecutionContext *ctx, String *name);
- virtual bool __hasProperty__(ExecutionContext *ctx, String *name) const;
+ virtual bool __hasProperty__(const ExecutionContext *ctx, String *name) const;
virtual bool __delete__(ExecutionContext *ctx, String *name);
virtual bool __defineOwnProperty__(ExecutionContext *ctx, String *name, PropertyDescriptor *desc);
virtual QString className() { return QStringLiteral("URIError"); }
};
-struct ActivationObject: Object {
- ExecutionContext *context;
- Value arguments;
- ActivationObject(ExecutionContext *context)
- : context(context), arguments(Value::undefinedValue()) {}
- virtual QString className() { return QStringLiteral("Activation"); }
- virtual ActivationObject *asActivationObject() { return this; }
- virtual PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill);
-};
-
struct ArgumentsObject: Object {
ExecutionContext *context;
ArgumentsObject(ExecutionContext *context): context(context) {}
void __qmljs_set_activation_property(ExecutionContext *ctx, String *name, Value value)
{
- PropertyDescriptor tmp;
- PropertyDescriptor *prop = ctx->lookupPropertyDescriptor(name, &tmp);
- if (prop) {
- prop->value = value;
- return;
- }
- if (ctx->strictMode)
- ctx->throwReferenceError(Value::fromString(name));
- ctx->engine->globalObject.objectValue()->__put__(ctx, name, value);
+ ctx->setProperty(name, value);
}
Value __qmljs_get_property(ExecutionContext *ctx, Value object, String *name)
Value __qmljs_get_activation_property(ExecutionContext *ctx, String *name)
{
- PropertyDescriptor tmp;
- PropertyDescriptor *prop = ctx->lookupPropertyDescriptor(name, &tmp);
- if (!prop)
- ctx->throwReferenceError(Value::fromString(name));
- return prop->value;
+ return ctx->getProperty(name);
}
Value __qmljs_get_thisObject(ExecutionContext *ctx)
// TODO: remove this function. Backends should just generate a __qmljs_get_activation_property followed by a __qmljs_call_value
Value __qmljs_call_activation_property(ExecutionContext *context, String *name, Value *args, int argc)
{
- Value func = __qmljs_get_activation_property(context, name);
+ Value func = context->getProperty(name);
Object *o = func.asObject();
if (!o)
context->throwReferenceError(Value::fromString(name));
Value __qmljs_construct_activation_property(ExecutionContext *context, String *name, Value *args, int argc)
{
- PropertyDescriptor tmp;
- PropertyDescriptor *func = context->lookupPropertyDescriptor(name, &tmp);
- if (! func)
- context->throwReferenceError(Value::fromString(name));
- return __qmljs_construct_value(context, func->value, args, argc);
+ Value func = context->getProperty(name);
+ return __qmljs_construct_value(context, func, args, argc);
}
Value __qmljs_construct_value(ExecutionContext *context, Value func, Value *args, int argc)
void __qmljs_builtin_declare_var(ExecutionContext *ctx, bool deletable, String *name)
{
- ctx->createMutableBinding(ctx, name, deletable);
+ ctx->createMutableBinding(name, deletable);
}
} // extern "C"
struct RegExpObject;
struct ArrayObject;
struct ErrorObject;
-struct ActivationObject;
struct ExecutionEngine;
extern "C" {
return isObject() ? objectValue()->asErrorObject() : 0;
}
-ActivationObject *Value::asArgumentsObject() const
-{
- return isObject() ? objectValue()->asActivationObject() : 0;
-}
-
Value Value::property(ExecutionContext *ctx, String *name) const
{
return isObject() ? objectValue()->__get__(ctx, name) : undefinedValue();
struct FunctionObject;
struct RegExpObject;
struct ErrorObject;
-struct ActivationObject;
struct ArgumentsObject;
struct ExecutionContext;
struct ExecutionEngine;
RegExpObject *asRegExpObject() const;
ArrayObject *asArrayObject() const;
ErrorObject *asErrorObject() const;
- ActivationObject *asArgumentsObject() const;
Value property(ExecutionContext *ctx, String *name) const;