From 88e869fe567b185e2bc7a851d78776cda3b60c03 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 1 Nov 2012 14:49:09 +0100 Subject: [PATCH] Implement Function(...) and new Function(...) Change-Id: I3ff229740820883a99dee6e32370fc528bf9169c Reviewed-by: Simon Hausmann --- qv4codegen.cpp | 27 ++++++++++++++++++++++++-- qv4codegen_p.h | 1 + qv4ecmaobjects.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 976ab05..39fc3e4 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -259,8 +259,10 @@ protected: virtual bool visit(FunctionExpression *ast) { - _env->hasNestedFunctions = true; - _env->enter(ast->name.toString()); + if (_env) { + _env->hasNestedFunctions = true; + _env->enter(ast->name.toString()); + } enterEnvironment(ast); return true; } @@ -323,6 +325,27 @@ IR::Function *Codegen::operator()(Program *node, IR::Module *module, Mode mode) return globalCode; } +IR::Function *Codegen::operator()(AST::FunctionExpression *ast, IR::Module *module) +{ + _module = module; + _env = 0; + + ScanFunctions scan(this); + scan(ast); + + IR::Function *function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0); + + foreach (IR::Function *function, _module->functions) { + linearize(function); + } + + qDeleteAll(_envMap); + _envMap.clear(); + + return function; +} + + void Codegen::enterEnvironment(Node *node) { _env = _envMap.value(node); diff --git a/qv4codegen_p.h b/qv4codegen_p.h index 1f5b87f..bd8f3f8 100644 --- a/qv4codegen_p.h +++ b/qv4codegen_p.h @@ -62,6 +62,7 @@ public: }; IR::Function *operator()(AST::Program *ast, IR::Module *module, Mode mode = GlobalCode); + IR::Function *operator()(AST::FunctionExpression *ast, IR::Module *module); protected: enum Format { ex, cx, nx }; diff --git a/qv4ecmaobjects.cpp b/qv4ecmaobjects.cpp index 3427d56..f7f8455 100644 --- a/qv4ecmaobjects.cpp +++ b/qv4ecmaobjects.cpp @@ -53,6 +53,14 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + #ifndef Q_WS_WIN # include # ifndef Q_OS_VXWORKS @@ -1726,14 +1734,58 @@ FunctionCtor::FunctionCtor(Context *scope) { } +// 15.3.2 void FunctionCtor::construct(Context *ctx) { - ctx->throwUnimplemented(QStringLiteral("Function.prototype.constructor")); + QString args; + QString body; + if (ctx->argumentCount > 0) + body = ctx->arguments[ctx->argumentCount - 1].toString(ctx)->toQString(); + + for (uint i = 0; i < ctx->argumentCount - 1; ++i) { + if (i) + args += QLatin1String(", "); + args += ctx->arguments[i].toString(ctx)->toQString(); + } + + QString function = QLatin1String("function(") + args + QLatin1String("){") + body + QLatin1String("}"); + + QQmlJS::Engine ee, *engine = ⅇ + Lexer lexer(engine); + lexer.setCode(function, 1, false); + Parser parser(engine); + + const bool parsed = parser.parseExpression(); + + if (!parsed) + // ### Syntax error + __qmljs_throw_type_error(ctx); + + using namespace AST; + FunctionExpression *fe = AST::cast(parser.rootNode()); + if (!fe) + // ### Syntax error + __qmljs_throw_type_error(ctx); + + IR::Module module; + + Codegen cg; + IR::Function *irf = cg(fe, &module); + + uchar *code = 0; + MASM::InstructionSelection isel(ctx->engine, &module, code); + isel(irf); + + ctx->thisObject = Value::fromObject(new ScriptFunction(ctx->engine->rootContext, irf)); } +// 15.3.1: This is equivalent to new Function(...) void FunctionCtor::call(Context *ctx) { - ctx->throwUnimplemented(QStringLiteral("Function")); + Value v = ctx->thisObject; + construct(ctx); + ctx->result = ctx->thisObject; + ctx->thisObject = v; } void FunctionPrototype::init(Context *ctx, const Value &ctor) -- 2.7.4