void ExecutionContext::createMutableBinding(String *name, bool deletable) { Scope scope(this); // find the right context to create the binding on ScopedObject activation(scope, d()->engine->globalObject); ExecutionContext *ctx = this; while (ctx) { if (ctx->d()->type >= Type_CallContext) { CallContext *c = static_cast<CallContext *>(ctx); if (!c->d()->activation) c->d()->activation = d()->engine->newObject()->getPointer(); activation = c->d()->activation; break; } ctx = ctx->d()->outer; } if (activation->hasProperty(name)) return; Property desc(Primitive::undefinedValue()); PropertyAttributes attrs(Attr_Data); attrs.setConfigurable(deletable); activation->__defineOwnProperty__(this, name, desc, attrs); }
void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine) { ExecutionContext *ctx = static_cast<ExecutionContext *>(m); if (ctx->d()->outer) ctx->d()->outer->mark(engine); // ### shouldn't need these 3 lines ctx->d()->callData->thisObject.mark(engine); for (int arg = 0; arg < ctx->d()->callData->argc; ++arg) ctx->d()->callData->args[arg].mark(engine); if (ctx->d()->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); for (unsigned local = 0, lastLocal = c->d()->function->varCount(); local < lastLocal; ++local) c->d()->locals[local].mark(engine); if (c->d()->activation) c->d()->activation->mark(engine); c->d()->function->mark(engine); } else if (ctx->d()->type == Type_WithContext) { WithContext *w = static_cast<WithContext *>(ctx); w->d()->withObject->mark(engine); } else if (ctx->d()->type == Type_CatchContext) { CatchContext *c = static_cast<CatchContext *>(ctx); c->d()->exceptionVarName->mark(engine); c->d()->exceptionValue.mark(engine); } else if (ctx->d()->type == Type_GlobalContext) { GlobalContext *g = static_cast<GlobalContext *>(ctx); g->d()->global->mark(engine); } }
/* member = string name-separator value */ bool JsonParser::parseMember(Object *o) { BEGIN << "parseMember"; Scope scope(context); QString key; if (!parseString(&key)) return false; QChar token = nextToken(); if (token != NameSeparator) { lastError = QJsonParseError::MissingNameSeparator; return false; } ScopedValue val(scope); if (!parseValue(val)) return false; ScopedString s(scope, context->d()->engine->newIdentifier(key)); uint idx = s->asArrayIndex(); if (idx < UINT_MAX) { o->putIndexed(idx, val); } else { o->insertMember(s.getPointer(), val); } END; return true; }
bool ExecutionContext::deleteProperty(String *name) { Scope scope(this); bool hasWith = false; for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) { if (ctx->d()->type == Type_WithContext) { hasWith = true; WithContext *w = static_cast<WithContext *>(ctx); if (w->d()->withObject->hasProperty(name)) return w->d()->withObject->deleteProperty(name); } else if (ctx->d()->type == Type_CatchContext) { CatchContext *c = static_cast<CatchContext *>(ctx); if (c->d()->exceptionVarName->isEqualTo(name)) return false; } else if (ctx->d()->type >= Type_CallContext) { CallContext *c = static_cast<CallContext *>(ctx); FunctionObject *f = c->d()->function; if (f->needsActivation() || hasWith) { uint index = f->function()->internalClass->find(name); if (index < UINT_MAX) // ### throw in strict mode? return false; } if (c->d()->activation && c->d()->activation->hasProperty(name)) return c->d()->activation->deleteProperty(name); } else if (ctx->d()->type == Type_GlobalContext) { GlobalContext *g = static_cast<GlobalContext *>(ctx); if (g->d()->global->hasProperty(name)) return g->d()->global->deleteProperty(name); } } if (d()->strictMode) throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString())); return true; }
void ExecutionContext::setProperty(String *name, const ValueRef value) { Scope scope(this); for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) { if (ctx->d()->type == Type_WithContext) { ScopedObject w(scope, static_cast<WithContext *>(ctx)->d()->withObject); if (w->hasProperty(name)) { w->put(name, value); return; } } else if (ctx->d()->type == Type_CatchContext && static_cast<CatchContext *>(ctx)->d()->exceptionVarName->isEqualTo(name)) { static_cast<CatchContext *>(ctx)->d()->exceptionValue = *value; return; } else { ScopedObject activation(scope, (Object *)0); if (ctx->d()->type >= Type_CallContext) { CallContext *c = static_cast<CallContext *>(ctx); if (c->d()->function->function()) { uint index = c->d()->function->function()->internalClass->find(name); if (index < UINT_MAX) { if (index < c->d()->function->formalParameterCount()) { c->d()->callData->args[c->d()->function->formalParameterCount() - index - 1] = *value; } else { index -= c->d()->function->formalParameterCount(); c->d()->locals[index] = *value; } return; } } activation = c->d()->activation; } else if (ctx->d()->type == Type_GlobalContext) { activation = static_cast<GlobalContext *>(ctx)->d()->global; } if (activation) { if (ctx->d()->type == Type_QmlContext) { activation->put(name, value); return; } else { uint member = activation->internalClass()->find(name); if (member < UINT_MAX) { activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); return; } } } } } if (d()->strictMode || name->equals(d()->engine->id_this.getPointer())) { ScopedValue n(scope, name->asReturnedValue()); throwReferenceError(n); return; } d()->engine->globalObject->put(name, value); }
/* array = begin-array [ value *( value-separator value ) ] end-array */ ReturnedValue JsonParser::parseArray() { Scope scope(context); BEGIN << "parseArray"; Scoped<ArrayObject> array(scope, context->d()->engine->newArrayObject()); if (++nestingLevel > nestingLimit) { lastError = QJsonParseError::DeepNesting; return Encode::undefined(); } if (!eatSpace()) { lastError = QJsonParseError::UnterminatedArray; return Encode::undefined(); } if (*json == EndArray) { nextToken(); } else { uint index = 0; while (1) { ScopedValue val(scope); if (!parseValue(val)) return Encode::undefined(); array->arraySet(index, val); QChar token = nextToken(); if (token == EndArray) break; else if (token != ValueSeparator) { if (!eatSpace()) lastError = QJsonParseError::UnterminatedArray; else lastError = QJsonParseError::MissingValueSeparator; return Encode::undefined(); } ++index; } } DEBUG << "size =" << array->getLength(); END; --nestingLevel; return array.asReturnedValue(); }
ReturnedValue JsonParser::parseObject() { if (++nestingLevel > nestingLimit) { lastError = QJsonParseError::DeepNesting; return Encode::undefined(); } BEGIN << "parseObject pos=" << json; Scope scope(context); ScopedObject o(scope, context->d()->engine->newObject()); QChar token = nextToken(); while (token == Quote) { if (!parseMember(o)) return Encode::undefined(); token = nextToken(); if (token != ValueSeparator) break; token = nextToken(); if (token == EndObject) { lastError = QJsonParseError::MissingObject; return Encode::undefined(); } } DEBUG << "end token=" << token; if (token != EndObject) { lastError = QJsonParseError::UnterminatedObject; return Encode::undefined(); } END; --nestingLevel; return o.asReturnedValue(); }
QString Stringify::Str(const QString &key, ValueRef v) { Scope scope(ctx); ScopedValue value(scope, *v); ScopedObject o(scope, value); if (o) { ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toJSON"))); Scoped<FunctionObject> toJSON(scope, o->get(s.getPointer())); if (!!toJSON) { ScopedCallData callData(scope, 1); callData->thisObject = value; callData->args[0] = ctx->d()->engine->newString(key); value = toJSON->call(callData); } } if (replacerFunction) { ScopedObject holder(scope, ctx->d()->engine->newObject()); holder->put(ctx, QString(), value); ScopedCallData callData(scope, 2); callData->args[0] = ctx->d()->engine->newString(key); callData->args[1] = value; callData->thisObject = holder; value = replacerFunction->call(callData); } o = value.asReturnedValue(); if (o) { if (NumberObject *n = o->asNumberObject()) value = n->value(); else if (StringObject *so = o->asStringObject()) value = so->d()->value; else if (BooleanObject *b =o->asBooleanObject()) value = b->value(); } if (value->isNull()) return QStringLiteral("null"); if (value->isBoolean()) return value->booleanValue() ? QStringLiteral("true") : QStringLiteral("false"); if (value->isString()) return quote(value->stringValue()->toQString()); if (value->isNumber()) { double d = value->toNumber(); return std::isfinite(d) ? value->toString(ctx)->toQString() : QStringLiteral("null"); } o = value.asReturnedValue(); if (o) { if (!o->asFunctionObject()) { if (o->asArrayObject()) { ScopedArrayObject a(scope, o); return JA(a); } else { return JO(o); } } } return QString(); }
bool JsonParser::parseValue(ValueRef val) { BEGIN << "parse Value" << *json; switch ((json++)->unicode()) { case 'n': if (end - json < 3) { lastError = QJsonParseError::IllegalValue; return false; } if (*json++ == 'u' && *json++ == 'l' && *json++ == 'l') { *val = Primitive::nullValue(); DEBUG << "value: null"; END; return true; } lastError = QJsonParseError::IllegalValue; return false; case 't': if (end - json < 3) { lastError = QJsonParseError::IllegalValue; return false; } if (*json++ == 'r' && *json++ == 'u' && *json++ == 'e') { *val = Primitive::fromBoolean(true); DEBUG << "value: true"; END; return true; } lastError = QJsonParseError::IllegalValue; return false; case 'f': if (end - json < 4) { lastError = QJsonParseError::IllegalValue; return false; } if (*json++ == 'a' && *json++ == 'l' && *json++ == 's' && *json++ == 'e') { *val = Primitive::fromBoolean(false); DEBUG << "value: false"; END; return true; } lastError = QJsonParseError::IllegalValue; return false; case Quote: { QString value; if (!parseString(&value)) return false; DEBUG << "value: string"; END; val = context->d()->engine->newString(value); return true; } case BeginArray: { *val = parseArray(); if (val->isUndefined()) return false; DEBUG << "value: array"; END; return true; } case BeginObject: { *val = parseObject(); if (val->isUndefined()) return false; DEBUG << "value: object"; END; return true; } case EndArray: lastError = QJsonParseError::MissingObject; return false; default: --json; if (!parseNumber(val)) return false; DEBUG << "value: number"; END; } return true; }
ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Object *&base) { Scope scope(this); ScopedValue v(scope); base = (Object *)0; name->makeIdentifier(); if (name->equals(d()->engine->id_this.getPointer())) return d()->callData->thisObject.asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) { if (ctx->d()->type == Type_WithContext) { Object *w = static_cast<WithContext *>(ctx)->d()->withObject; hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { base = w; return v.asReturnedValue(); } continue; } else if (ctx->d()->type == Type_CatchContext) { hasCatchScope = true; CatchContext *c = static_cast<CatchContext *>(ctx); if (c->d()->exceptionVarName->isEqualTo(name)) return c->d()->exceptionValue.asReturnedValue(); } else if (ctx->d()->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); FunctionObject *f = c->d()->function; if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { uint index = f->function()->internalClass->find(name); if (index < UINT_MAX) { if (index < c->d()->function->formalParameterCount()) return c->d()->callData->args[c->d()->function->formalParameterCount() - index - 1].asReturnedValue(); return c->d()->locals[index - c->d()->function->formalParameterCount()].asReturnedValue(); } } if (c->d()->activation) { bool hasProperty = false; v = c->d()->activation->get(name, &hasProperty); if (hasProperty) { if (ctx->d()->type == Type_QmlContext) base = c->d()->activation; return v.asReturnedValue(); } } if (f->function() && f->function()->isNamedExpression() && name->equals(f->function()->name())) return c->d()->function->asReturnedValue(); } else if (ctx->d()->type == Type_GlobalContext) { GlobalContext *g = static_cast<GlobalContext *>(ctx); bool hasProperty = false; v = g->d()->global->get(name, &hasProperty); if (hasProperty) return v.asReturnedValue(); } } ScopedValue n(scope, name); return throwReferenceError(n); }