NODE_IMPLEMENTATION(DynamicPartialEvaluate::node, Pointer) { typedef FunctionSpecializer Generator; FunctionObject* f = NODE_ARG_OBJECT(1, FunctionObject); Generator::ArgumentVector args(f->function()->numArgs() + f->function()->numFreeVariables()); Generator::ArgumentMask mask(args.size()); Process* p = NODE_THREAD.process(); Context* c = p->context(); for (int i=0; i < args.size(); i++) { mask[i] = NODE_THIS.argNode(i+2)->symbol() != c->noop(); if (mask[i]) { args[i] = NODE_ANY_TYPE_ARG(i+2); } } try { Generator evaluator(f->function(), p, &NODE_THREAD); evaluator.partiallyEvaluate(args, mask); const FunctionType* rt = evaluator.result()->type(); assert(rt == NODE_THIS.argNode(0)->type()); FunctionObject* o = new FunctionObject(rt); o->setFunction(evaluator.result()); NODE_RETURN(Pointer(o)); } catch (Exception& e) { ProgramException exc(NODE_THREAD); exc.message() = e.message(); exc.message() += " during partial evaluation of "; exc.message() += f->function()->name().c_str(); throw exc; } }
NODE_IMPLEMENTATION(Curry::node, Pointer) { Process* p = NODE_THREAD.process(); Context* c = p->context(); FunctionObject* o = NODE_ARG_OBJECT(1, FunctionObject); bool d = NODE_ARG(2, bool); const Function* F = o->function(); Function::ArgumentVector args(F->numArgs() + F->numFreeVariables()); vector<bool> mask(args.size()); for (int i=0, s=args.size(); i < s; i++) { mask[i] = NODE_THIS.argNode(i+3)->symbol() != c->noop(); if (mask[i]) { args[i] = NODE_ANY_TYPE_ARG(i+3); } } NODE_RETURN(Pointer(evaluate(NODE_THREAD, o, args, mask, d))); }
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; }
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); }
NODE_IMPLEMENTATION(DynamicPartialApplication::node, Pointer) { // // Never do partial application on the result of a lambda // expression (its too difficult to archive). Instead do // partial evaluation. The good side is that there will never // be more than one level of indirection in multiple-curried // lambda expressions. the bad side is that there will be // more overhead upfront. // Process* p = NODE_THREAD.process(); Context* c = p->context(); FunctionObject* f = NODE_ARG_OBJECT(1, FunctionObject); bool apply = f->function()->isLambda(); try { if (apply) { typedef PartialApplicator Generator; Generator::ArgumentVector args(f->function()->numArgs() + f->function()->numFreeVariables()); Generator::ArgumentMask mask(args.size()); for (int i=0; i < args.size(); i++) { mask[i] = NODE_THIS.argNode(i+2)->symbol() != c->noop(); if (mask[i]) { args[i] = NODE_ANY_TYPE_ARG(i+2); } } Generator evaluator(f->function(), p, &NODE_THREAD, args, mask); const FunctionType* rt = evaluator.result()->type(); assert(rt == NODE_THIS.argNode(0)->type()); FunctionObject* o = new FunctionObject(rt); o->setDependent(f); o->setFunction(evaluator.result()); NODE_RETURN(Pointer(o)); } else { typedef FunctionSpecializer Generator; Generator::ArgumentVector args(f->function()->numArgs() + f->function()->numFreeVariables()); Generator::ArgumentMask mask(args.size()); for (int i=0; i < args.size(); i++) { mask[i] = NODE_THIS.argNode(i+2)->symbol() != c->noop(); if (mask[i]) { args[i] = NODE_ANY_TYPE_ARG(i+2); } } Generator evaluator(f->function(), p, &NODE_THREAD); evaluator.partiallyEvaluate(args, mask); const FunctionType* rt = evaluator.result()->type(); assert(rt == NODE_THIS.argNode(0)->type()); FunctionObject* o = new FunctionObject(rt); o->setFunction(evaluator.result()); NODE_RETURN(Pointer(o)); } } catch (Exception& e) { ProgramException exc(NODE_THREAD); exc.message() = e.message(); exc.message() += " during partial "; exc.message() += (apply ? "application" : "evaluation"); exc.message() += " of "; exc.message() += f->function()->name().c_str(); throw exc; } }