Implement Function(...) and new Function(...)
authorLars Knoll <lars.knoll@digia.com>
Thu, 1 Nov 2012 13:49:09 +0000 (14:49 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Thu, 1 Nov 2012 14:56:54 +0000 (15:56 +0100)
Change-Id: I3ff229740820883a99dee6e32370fc528bf9169c
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
qv4codegen.cpp
qv4codegen_p.h
qv4ecmaobjects.cpp

index 976ab05..39fc3e4 100644 (file)
@@ -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);
index 1f5b87f..bd8f3f8 100644 (file)
@@ -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 };
index 3427d56..f7f8455 100644 (file)
 #include <qnumeric.h>
 #include <cassert>
 
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4ir_p.h>
+#include <qv4codegen_p.h>
+#include <qv4isel_masm_p.h>
+
 #ifndef Q_WS_WIN
 #  include <time.h>
 #  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 = &ee;
+    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<FunctionExpression *>(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)