aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qv4codegen.cpp66
-rw-r--r--src/qml/compiler/qv4codegen_p.h3
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp7
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h4
-rw-r--r--src/qml/jit/qv4jit.cpp19
-rw-r--r--src/qml/jit/qv4jit_p.h3
-rw-r--r--src/qml/jsruntime/jsruntime.pri2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp11
-rw-r--r--src/qml/jsruntime/qv4engine_p.h8
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h2
-rw-r--r--src/qml/jsruntime/qv4function_p.h1
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp51
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h6
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp247
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h136
-rw-r--r--src/qml/jsruntime/qv4managed.cpp3
-rw-r--r--src/qml/jsruntime/qv4managed_p.h1
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp3
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp30
-rw-r--r--src/qml/parser/qqmljs.g13
20 files changed, 566 insertions, 50 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 5cfa70c03f..c5394e16c6 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2271,7 +2271,28 @@ bool Codegen::visit(FunctionDeclaration * ast)
bool Codegen::visit(YieldExpression *ast)
{
- throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Support for 'yield' unimplemented."));
+ if (ast->isYieldStar) {
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("yield* is not currently supported"));
+ return false;
+ }
+ if (inFormalParameterList) {
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("yield is not allowed inside parameter lists"));
+ return false;
+ }
+
+
+ Reference result = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
+ if (hasError)
+ return false;
+ result.loadInAccumulator();
+ Instruction::Yield yield;
+ bytecodeGenerator->addInstruction(yield);
+ Instruction::Resume resume;
+ BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume);
+ Reference acc = Reference::fromAccumulator(this);
+ emitReturn(acc);
+ jump.link();
+ _expr.setResult(acc);
return false;
}
@@ -2309,10 +2330,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
{
enterContext(ast);
- if (_context->isGenerator) {
- throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Support for generator functions unimplemented."));
- }
-
if (_context->functionIndex >= 0)
// already defined
return leaveContext();
@@ -2345,6 +2362,9 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
// reserve the js stack frame (Context & js Function & accumulator)
bytecodeGenerator->newRegisterArray(sizeof(CallData)/sizeof(Value) - 1 + _context->arguments.size());
+ bool _inFormalParameterList = false;
+ qSwap(_inFormalParameterList, inFormalParameterList);
+
int returnAddress = -1;
bool _requiresReturnValue = _context->requiresImplicitReturnValue();
qSwap(requiresReturnValue, _requiresReturnValue);
@@ -2355,6 +2375,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
RegisterScope registerScope(this);
_context->emitBlockHeader(this);
+ inFormalParameterList = true;
int argc = 0;
while (formals) {
PatternElement *e = formals->element;
@@ -2382,6 +2403,12 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
formals = formals->next;
++argc;
}
+ inFormalParameterList = false;
+
+ if (_context->isGenerator) {
+ Instruction::Yield yield;
+ bytecodeGenerator->addInstruction(yield);
+ }
beginFunctionBodyHook();
@@ -2415,6 +2442,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
qSwap(_returnAddress, returnAddress);
qSwap(requiresReturnValue, _requiresReturnValue);
+ qSwap(_inFormalParameterList, inFormalParameterList);
bytecodeGenerator = savedBytecodeGenerator;
controlFlow = savedControlFlow;
_functionContext = savedFunctionContext;
@@ -2781,6 +2809,21 @@ bool Codegen::visit(LocalForStatement *ast)
return false;
}
+void Codegen::emitReturn(const Reference &expr)
+{
+ if (controlFlow && controlFlow->returnRequiresUnwind()) {
+ if (_returnAddress >= 0)
+ (void) expr.storeOnStack(_returnAddress);
+ else
+ expr.loadInAccumulator();
+ ControlFlow::Handler h = controlFlow->getHandler(ControlFlow::Return);
+ controlFlow->jumpToHandler(h);
+ } else {
+ expr.loadInAccumulator();
+ bytecodeGenerator->addInstruction(Instruction::Ret());
+ }
+}
+
bool Codegen::visit(ReturnStatement *ast)
{
if (hasError)
@@ -2799,17 +2842,8 @@ bool Codegen::visit(ReturnStatement *ast)
expr = Reference::fromConst(this, Encode::undefined());
}
- if (controlFlow && controlFlow->returnRequiresUnwind()) {
- if (_returnAddress >= 0)
- (void) expr.storeOnStack(_returnAddress);
- else
- expr.loadInAccumulator();
- ControlFlow::Handler h = controlFlow->getHandler(ControlFlow::Return);
- controlFlow->jumpToHandler(h);
- } else {
- expr.loadInAccumulator();
- bytecodeGenerator->addInstruction(Instruction::Ret());
- }
+ emitReturn(expr);
+
return false;
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 3c64e0f00e..e14d6b16e3 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -521,6 +521,8 @@ protected:
virtual Reference fallbackNameLookup(const QString &name);
virtual void beginFunctionBodyHook() {}
+ void emitReturn(const Reference &expr);
+
// nodes
bool visit(AST::ArgumentList *ast) override;
bool visit(AST::CaseBlock *ast) override;
@@ -670,6 +672,7 @@ protected:
bool _strictMode;
bool useFastLookups = true;
bool requiresReturnValue = false;
+ bool inFormalParameterList = false;
ControlFlow *controlFlow = nullptr;
bool _fileNameIsUrl;
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index bae8d9e64e..49d8455617 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -341,6 +341,13 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << dumpRegister(base, nFormals) << "[" << index << "]";
MOTH_END_INSTR(LoadIdObject)
+ MOTH_BEGIN_INSTR(Yield)
+ MOTH_END_INSTR(Yield)
+
+ MOTH_BEGIN_INSTR(Resume)
+ d << ABSOLUTE_OFFSET();
+ MOTH_END_INSTR(Resume)
+
MOTH_BEGIN_INSTR(CallValue)
d << dumpRegister(name, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(CallValue)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 15ab1b52dd..2e3d118e52 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -91,6 +91,8 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadScopeObjectProperty(op) INSTRUCTION(op, LoadScopeObjectProperty, 3, propertyIndex, base, captureRequired)
#define INSTR_LoadContextObjectProperty(op) INSTRUCTION(op, LoadContextObjectProperty, 3, propertyIndex, base, captureRequired)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
+#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
+#define INSTR_Resume(op) INSTRUCTION(op, Resume, 1, offset)
#define INSTR_StoreProperty(op) INSTRUCTION(op, StoreProperty, 2, name, base)
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_StoreScopeObjectProperty(op) INSTRUCTION(op, StoreScopeObjectProperty, 2, base, propertyIndex)
@@ -220,6 +222,8 @@ QT_BEGIN_NAMESPACE
F(LoadScopeObjectProperty) \
F(LoadContextObjectProperty) \
F(LoadIdObject) \
+ F(Yield) \
+ F(Resume) \
F(CallValue) \
F(CallProperty) \
F(CallPropertyLookup) \
diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4jit.cpp
index 678a0c16db..87c3642479 100644
--- a/src/qml/jit/qv4jit.cpp
+++ b/src/qml/jit/qv4jit.cpp
@@ -40,6 +40,7 @@
#include "qv4jit_p.h"
#include "qv4assembler_p.h"
#include <private/qv4lookup_p.h>
+#include <private/qv4generatorobject_p.h>
#ifdef V4_ENABLE_JIT
@@ -462,6 +463,18 @@ void BaselineJIT::generate_LoadIdObject(int index, int base)
as->checkException();
}
+void BaselineJIT::generate_Yield()
+{
+ // #####
+ Q_UNREACHABLE();
+}
+
+void BaselineJIT::generate_Resume(int)
+{
+ // #####
+ Q_UNREACHABLE();
+}
+
void BaselineJIT::generate_CallValue(int name, int argc, int argv)
{
STORE_IP();
@@ -1146,6 +1159,12 @@ void BaselineJIT::collectLabelsInBytecode()
MOTH_BEGIN_INSTR(LoadIdObject)
MOTH_END_INSTR(LoadIdObject)
+ MOTH_BEGIN_INSTR(Yield)
+ MOTH_END_INSTR(Yield)
+
+ MOTH_BEGIN_INSTR(Resume)
+ MOTH_END_INSTR(Resume)
+
MOTH_BEGIN_INSTR(CallValue)
MOTH_END_INSTR(CallValue)
diff --git a/src/qml/jit/qv4jit_p.h b/src/qml/jit/qv4jit_p.h
index 150f4b6aab..bf11e69cbb 100644
--- a/src/qml/jit/qv4jit_p.h
+++ b/src/qml/jit/qv4jit_p.h
@@ -161,6 +161,9 @@ public:
void generate_LoadContextObjectProperty(int propertyIndex, int base,
int captureRequired) override;
void generate_LoadIdObject(int index, int base) override;
+ void generate_Yield() override;
+ void generate_Resume(int) override;
+
void generate_CallValue(int name, int argc, int argv) override;
void generate_CallProperty(int name, int base, int argc, int argv) override;
void generate_CallPropertyLookup(int lookupIndex, int base, int argc, int argv) override;
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index d06e505c81..96956e2613 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -21,6 +21,7 @@ SOURCES += \
$$PWD/qv4errorobject.cpp \
$$PWD/qv4function.cpp \
$$PWD/qv4functionobject.cpp \
+ $$PWD/qv4generatorobject.cpp \
$$PWD/qv4globalobject.cpp \
$$PWD/qv4iterator.cpp \
$$PWD/qv4jsonobject.cpp \
@@ -74,6 +75,7 @@ HEADERS += \
$$PWD/qv4errorobject_p.h \
$$PWD/qv4function_p.h \
$$PWD/qv4functionobject_p.h \
+ $$PWD/qv4generatorobject_p.h \
$$PWD/qv4globalobject_p.h \
$$PWD/qv4iterator_p.h \
$$PWD/qv4jsonobject_p.h \
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 1c3c3e7ff8..90c5272b7f 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -67,6 +67,7 @@
#include "qv4executableallocator_p.h"
#include "qv4iterator_p.h"
#include "qv4stringiterator_p.h"
+#include "qv4generatorobject_p.h"
#if QT_CONFIG(qml_sequence_object)
#include "qv4sequenceobject_p.h"
@@ -325,11 +326,17 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ic = ic->addMember(id_name()->identifier(), Attr_ReadOnly, &index);
Q_ASSERT(index == Heap::ScriptFunction::Index_Name);
ic = ic->changeVTable(ScriptFunction::staticVTable());
- classes[Class_ScriptFunction] = ic->addMember(id_length()->identifier(), Attr_ReadOnly, &index);
+ ic = ic->addMember(id_length()->identifier(), Attr_ReadOnly, &index);
Q_ASSERT(index == Heap::ScriptFunction::Index_Length);
+ classes[Class_ScriptFunction] = ic->d();
+ ic = ic->changeVTable(GeneratorFunction::staticVTable());
+ classes[Class_GeneratorFunction] = ic->d();
classes[Class_ObjectProto] = classes[Class_Object]->addMember(id_constructor()->identifier(), Attr_NotEnumerable, &index);
Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor);
+ jsObjects[GeneratorProto] = memoryManager->allocObject<GeneratorPrototype>(classes[Class_Object]);
+ classes[Class_GeneratorObject] = newInternalClass(QV4::GeneratorObject::staticVTable(), generatorPrototype());
+
ScopedString str(scope);
classes[Class_RegExp] = classes[Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
@@ -397,6 +404,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(global);
jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(global);
jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(global);
+ jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(global);
jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(global);
jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(global);
jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(global);
@@ -419,6 +427,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
static_cast<PropertyListPrototype *>(propertyListPrototype())->init(this);
static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
+ static_cast<GeneratorPrototype *>(generatorPrototype())->init(this, generatorFunctionCtor());
static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor());
static_cast<ErrorPrototype *>(errorPrototype())->init(this, errorCtor());
static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(this, evalErrorCtor());
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 819481ed91..64bbd1163f 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -96,6 +96,8 @@ struct Q_QML_EXPORT CppStackFrame {
const Value *originalArguments;
int originalArgumentsCount;
int instructionPointer;
+ const uchar *yield;
+ const uchar *exceptionHandler;
QString source() const;
QString function() const;
@@ -170,6 +172,7 @@ public:
BooleanProto,
DateProto,
FunctionProto,
+ GeneratorProto,
RegExpProto,
ErrorProto,
EvalErrorProto,
@@ -197,6 +200,7 @@ public:
Boolean_Ctor,
Array_Ctor,
Function_Ctor,
+ GeneratorFunction_Ctor,
Date_Ctor,
RegExp_Ctor,
Error_Ctor,
@@ -225,6 +229,7 @@ public:
FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); }
FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); }
FunctionObject *functionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Function_Ctor); }
+ FunctionObject *generatorFunctionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + GeneratorFunction_Ctor); }
FunctionObject *dateCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Date_Ctor); }
FunctionObject *regExpCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RegExp_Ctor); }
FunctionObject *errorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Error_Ctor); }
@@ -248,6 +253,7 @@ public:
Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); }
Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); }
Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); }
+ Object *generatorPrototype() const { return reinterpret_cast<Object *>(jsObjects + GeneratorProto); }
Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); }
Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); }
Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); }
@@ -539,7 +545,7 @@ public:
if (!m_canAllocateExecutableMemory)
return false;
if (f)
- return f->interpreterCallCount >= jitCallCountThreshold;
+ return !f->isGenerator() && f->interpreterCallCount >= jitCallCountThreshold;
return true;
#else
Q_UNUSED(f);
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index d1257b6248..03ff25d5b5 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -100,6 +100,8 @@ struct Q_QML_EXPORT EngineBase {
Class_Object,
Class_ArrayObject,
Class_FunctionObject,
+ Class_GeneratorFunction,
+ Class_GeneratorObject,
Class_StringObject,
Class_SymbolObject,
Class_ScriptFunction,
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index dc18245819..fa6b886b10 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -100,6 +100,7 @@ struct Q_QML_EXPORT Function {
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
inline bool isArrowFunction() const { return compiledFunction->flags & CompiledData::Function::IsArrowFunction; }
+ inline bool isGenerator() const { return compiledFunction->flags & CompiledData::Function::IsGenerator; }
QQmlSourceLocation sourceLocation() const
{
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index a684e1c5d3..6382a6e862 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -214,10 +214,8 @@ void Heap::FunctionCtor::init(QV4::ExecutionContext *scope)
}
// 15.3.2
-ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
+QQmlRefPointer<CompiledData::CompilationUnit> FunctionCtor::parse(ExecutionEngine *engine, const Value *argv, int argc, Type t)
{
- Scope scope(f->engine());
-
QString arguments;
QString body;
if (argc > 0) {
@@ -228,38 +226,51 @@ ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Val
}
body = argv[argc - 1].toQString();
}
- if (scope.engine->hasException)
- return Encode::undefined();
+ if (engine->hasException)
+ return nullptr;
- QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1Char('}');
+ QString function = (t == Type_Function ? QLatin1String("function(") : QLatin1String("function*(")) + arguments + QLatin1String("){") + body + QLatin1Char('}');
- QQmlJS::Engine ee, *engine = &ee;
- QQmlJS::Lexer lexer(engine);
+ QQmlJS::Engine ee;
+ QQmlJS::Lexer lexer(&ee);
lexer.setCode(function, 1, false);
- QQmlJS::Parser parser(engine);
+ QQmlJS::Parser parser(&ee);
const bool parsed = parser.parseExpression();
- if (!parsed)
- return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ if (!parsed) {
+ engine->throwSyntaxError(QLatin1String("Parse error"));
+ return nullptr;
+ }
QQmlJS::AST::FunctionExpression *fe = QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(parser.rootNode());
- if (!fe)
- return scope.engine->throwSyntaxError(QLatin1String("Parse error"));
+ if (!fe) {
+ engine->throwSyntaxError(QLatin1String("Parse error"));
+ return nullptr;
+ }
- Compiler::Module module(scope.engine->debugger() != nullptr);
+ Compiler::Module module(engine->debugger() != nullptr);
Compiler::JSUnitGenerator jsGenerator(&module);
- RuntimeCodegen cg(scope.engine, &jsGenerator, false);
+ RuntimeCodegen cg(engine, &jsGenerator, false);
cg.generateFromFunctionExpression(QString(), function, fe, &module);
- if (scope.hasException())
- return Encode::undefined();
+ if (engine->hasException)
+ return nullptr;
+
+ return cg.generateCompilationUnit();
+}
- QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = cg.generateCompilationUnit();
- Function *vmf = compilationUnit->linkToEngine(scope.engine);
+ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+
+ QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = parse(engine, argv, argc, Type_Function);
+ if (engine->hasException)
+ return Encode::undefined();
- ExecutionContext *global = scope.engine->rootContext();
+ Function *vmf = compilationUnit->linkToEngine(engine);
+ ExecutionContext *global = engine->rootContext();
return Encode(FunctionObject::createScriptFunction(global, vmf));
}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index c9efee1a46..e8bd574161 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -186,6 +186,12 @@ struct FunctionCtor: FunctionObject
static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+protected:
+ enum Type {
+ Type_Function,
+ Type_Generator
+ };
+ static QQmlRefPointer<CompiledData::CompilationUnit> parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function);
};
struct FunctionPrototype: FunctionObject
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
new file mode 100644
index 0000000000..4339a95f45
--- /dev/null
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qv4generatorobject_p.h>
+#include <qv4symbol_p.h>
+#include <qv4iterator_p.h>
+#include <qv4jscall_p.h>
+#include <qv4vme_moth_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(GeneratorFunctionCtor);
+DEFINE_OBJECT_VTABLE(GeneratorFunction);
+DEFINE_OBJECT_VTABLE(GeneratorObject);
+
+void Heap::GeneratorFunctionCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QStringLiteral("GeneratorFunction"));
+}
+
+ReturnedValue GeneratorFunctionCtor::callAsConstructor(const FunctionObject *f, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+
+ QQmlRefPointer<CompiledData::CompilationUnit> compilationUnit = parse(engine, argv, argc, Type_Generator);
+ if (engine->hasException)
+ return Encode::undefined();
+
+ Function *vmf = compilationUnit->linkToEngine(engine);
+ ExecutionContext *global = engine->rootContext();
+ return Encode(GeneratorFunction::create(global, vmf));
+}
+
+// 15.3.1: This is equivalent to new Function(...)
+ReturnedValue GeneratorFunctionCtor::call(const FunctionObject *f, const Value *, const Value *argv, int argc)
+{
+ return callAsConstructor(f, argv, argc);
+}
+
+Heap::FunctionObject *GeneratorFunction::create(ExecutionContext *context, Function *function)
+{
+ Scope scope(context);
+ Scoped<GeneratorFunction> g(scope, context->engine()->memoryManager->allocate<GeneratorFunction>(context, function));
+ ScopedObject proto(scope, scope.engine->newObject());
+ proto->setPrototype(scope.engine->generatorPrototype());
+ g->defineDefaultProperty(scope.engine->id_prototype(), proto, Attr_NotConfigurable|Attr_NotEnumerable);
+ g->setPrototype(ScopedObject(scope, scope.engine->generatorFunctionCtor()->get(scope.engine->id_prototype())));
+ return g->d();
+}
+
+ReturnedValue GeneratorFunction::callAsConstructor(const FunctionObject *f, const Value *, int)
+{
+ return f->engine()->throwTypeError();
+}
+
+ReturnedValue GeneratorFunction::call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ const GeneratorFunction *gf = static_cast<const GeneratorFunction *>(f);
+ Function *function = gf->function();
+ ExecutionEngine *engine = gf->engine();
+
+ // We need to set up a separate stack for the generator, as it's being re-entered
+ uint stackSize = argc; // space for the original arguments
+ int jsStackFrameSize = offsetof(CallData, args)/sizeof(Value) + function->compiledFunction->nRegisters;
+ stackSize += jsStackFrameSize;
+
+ size_t requiredMemory = sizeof(GeneratorObject::Data) - sizeof(Value) + sizeof(Value) * stackSize;
+
+ Scope scope(gf);
+ Scoped<GeneratorObject> g(scope, scope.engine->memoryManager->allocManaged<GeneratorObject>(requiredMemory, scope.engine->classes[EngineBase::Class_GeneratorObject]));
+ g->setPrototype(ScopedObject(scope, gf->get(scope.engine->id_prototype())));
+
+ Heap::GeneratorObject *gp = g->d();
+ gp->stack.size = stackSize;
+ gp->stack.alloc = stackSize;
+
+ // copy original arguments
+ memcpy(gp->stack.values, argv, argc*sizeof(Value));
+ gp->cppFrame.originalArguments = gp->stack.values;
+ gp->cppFrame.originalArgumentsCount = argc;
+
+ // setup JS stack frame
+ CallData *callData = reinterpret_cast<CallData *>(&gp->stack.values[argc]);
+ callData->function = *gf;
+ callData->context = gf->scope();
+ callData->accumulator = Encode::undefined();
+ callData->thisObject = thisObject ? *thisObject : Primitive::undefinedValue();
+ if (argc > int(function->nFormals))
+ argc = int(function->nFormals);
+ callData->setArgc(argc);
+ memcpy(callData->args, argv, argc*sizeof(Value));
+
+ gp->cppFrame.v4Function = function;
+ gp->cppFrame.instructionPointer = 0;
+ gp->cppFrame.jsFrame = callData;
+ gp->cppFrame.parent = engine->currentStackFrame;
+ engine->currentStackFrame = &gp->cppFrame;
+
+ Moth::VME::interpret(gp->cppFrame, function->codeData);
+ gp->state = GeneratorState::SuspendedStart;
+
+ engine->currentStackFrame = gp->cppFrame.parent;
+ return g->asReturnedValue();
+}
+
+
+void Heap::GeneratorPrototype::init()
+{
+ Heap::FunctionObject::init();
+}
+
+
+void GeneratorPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedValue v(scope);
+
+ ScopedObject ctorProto(scope, engine->newObject(engine->newInternalClass(Object::staticVTable(), engine->functionPrototype())));
+
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyProperty(engine->id_prototype(), ctorProto);
+
+ ctorProto->defineDefaultProperty(QStringLiteral("constructor"), (v = ctor), Attr_ReadOnly_ButConfigurable);
+ ctorProto->defineDefaultProperty(engine->symbol_toStringTag(), (v = engine->newIdentifier(QStringLiteral("GeneratorFunction"))), Attr_ReadOnly_ButConfigurable);
+ ctorProto->defineDefaultProperty(engine->id_prototype(), (v = this), Attr_ReadOnly_ButConfigurable);
+
+ defineDefaultProperty(QStringLiteral("constructor"), ctorProto, Attr_ReadOnly_ButConfigurable);
+ defineDefaultProperty(QStringLiteral("next"), method_next, 1);
+ defineDefaultProperty(QStringLiteral("return"), method_return, 1);
+ defineDefaultProperty(QStringLiteral("throw"), method_throw, 1);
+ defineDefaultProperty(engine->symbol_toStringTag(), (v = engine->newString(QStringLiteral("Generator"))), Attr_ReadOnly_ButConfigurable);
+}
+
+ReturnedValue GeneratorPrototype::method_next(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+ const GeneratorObject *g = thisObject->as<GeneratorObject>();
+ if (!g || g->d()->state == GeneratorState::Executing)
+ return engine->throwTypeError();
+ Heap::GeneratorObject *gp = g->d();
+
+ if (gp->state == GeneratorState::Completed)
+ return IteratorPrototype::createIterResultObject(engine, Primitive::undefinedValue(), true);
+
+ return g->resume(engine, argc ? argv[0] : Primitive::undefinedValue());
+}
+
+ReturnedValue GeneratorPrototype::method_return(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+ const GeneratorObject *g = thisObject->as<GeneratorObject>();
+ if (!g || g->d()->state == GeneratorState::Executing)
+ return engine->throwTypeError();
+
+ Heap::GeneratorObject *gp = g->d();
+
+ if (gp->state == GeneratorState::SuspendedStart)
+ gp->state = GeneratorState::Completed;
+
+ if (gp->state == GeneratorState::Completed)
+ return IteratorPrototype::createIterResultObject(engine, argc ? argv[0] : Primitive::undefinedValue(), true);
+
+ // the bytecode interpreter interprets an exception with empty value as
+ // a yield called with return()
+ engine->throwError(Primitive::emptyValue());
+
+ return g->resume(engine, argc ? argv[0]: Primitive::undefinedValue());
+}
+
+ReturnedValue GeneratorPrototype::method_throw(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ ExecutionEngine *engine = f->engine();
+ const GeneratorObject *g = thisObject->as<GeneratorObject>();
+ if (!g || g->d()->state == GeneratorState::Executing)
+ return engine->throwTypeError();
+
+ Heap::GeneratorObject *gp = g->d();
+
+ engine->throwError(argc ? argv[0]: Primitive::undefinedValue());
+
+ if (gp->state == GeneratorState::SuspendedStart || gp->state == GeneratorState::Completed) {
+ gp->state = GeneratorState::Completed;
+ return Encode::undefined();
+ }
+
+ return g->resume(engine, Primitive::undefinedValue());
+}
+
+ReturnedValue GeneratorObject::resume(ExecutionEngine *engine, const Value &arg) const
+{
+ Heap::GeneratorObject *gp = d();
+ gp->state = GeneratorState::Executing;
+ gp->cppFrame.parent = engine->currentStackFrame;
+ engine->currentStackFrame = &gp->cppFrame;
+
+ Q_ASSERT(gp->cppFrame.yield != nullptr);
+ const uchar *code = gp->cppFrame.yield;
+ gp->cppFrame.yield = nullptr;
+ gp->cppFrame.jsFrame->accumulator = arg;
+
+ Scope scope(engine);
+ ScopedValue result(scope, Moth::VME::interpret(gp->cppFrame, code));
+
+ engine->currentStackFrame = gp->cppFrame.parent;
+
+ bool done = (gp->cppFrame.yield == nullptr);
+ gp->state = done ? GeneratorState::Completed : GeneratorState::SuspendedYield;
+ if (engine->hasException)
+ return Encode::undefined();
+ return IteratorPrototype::createIterResultObject(engine, result, done);
+}
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
new file mode 100644
index 0000000000..62ffcbbad1
--- /dev/null
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4GENERATOROBJECT_P_H
+#define QV4GENERATOROBJECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+enum class GeneratorState {
+ Undefined,
+ SuspendedStart,
+ SuspendedYield,
+ Executing,
+ Completed
+};
+
+namespace Heap {
+
+struct GeneratorFunctionCtor : FunctionObject {
+ void init(QV4::ExecutionContext *scope);
+};
+
+struct GeneratorFunction : ScriptFunction {
+};
+
+struct GeneratorPrototype : FunctionObject {
+ void init();
+};
+
+#define GeneratorObjectMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, context) \
+ Member(class, Pointer, GeneratorFunction *, function) \
+ Member(class, NoMark, GeneratorState, state) \
+ Member(class, NoMark, CppStackFrame, cppFrame) \
+ Member(class, ValueArray, ValueArray, stack)
+
+DECLARE_HEAP_OBJECT(GeneratorObject, Object) {
+ DECLARE_MARKOBJECTS(GeneratorObject);
+};
+
+}
+
+struct GeneratorFunctionCtor : FunctionCtor
+{
+ V4_OBJECT2(GeneratorFunctionCtor, FunctionCtor)
+
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct GeneratorFunction : ScriptFunction
+{
+ V4_OBJECT2(GeneratorFunction, ScriptFunction)
+ V4_INTERNALCLASS(GeneratorFunction)
+
+ static Heap::FunctionObject *create(ExecutionContext *scope, Function *function);
+ static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc);
+ static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct GeneratorPrototype : Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_next(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_return(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_throw(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+
+struct GeneratorObject : Object {
+ V4_OBJECT2(GeneratorObject, Object)
+ Q_MANAGED_TYPE(GeneratorObject)
+ V4_INTERNALCLASS(GeneratorObject)
+ V4_PROTOTYPE(generatorPrototype)
+
+ ReturnedValue resume(ExecutionEngine *engine, const Value &arg) const;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4GENERATORFUNCTION_P_H
+
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 92c5a1a069..f96e3c87d8 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -88,6 +88,9 @@ QString Managed::className() const
case Type_FunctionObject:
s = "Function";
break;
+ case Type_GeneratorObject:
+ s = "Generator";
+ break;
case Type_BooleanObject:
s = "Boolean";
break;
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index b60602b34c..1b67aacd7b 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -185,6 +185,7 @@ public:
Type_Symbol,
Type_ArrayObject,
Type_FunctionObject,
+ Type_GeneratorObject,
Type_BooleanObject,
Type_NumberObject,
Type_StringObject,
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 135da55daf..3ddd543b40 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -62,6 +62,7 @@
#include <private/qqmljavascriptexpression_p.h>
#include "qv4qobjectwrapper_p.h"
#include "qv4symbol_p.h"
+#include "qv4generatorobject_p.h"
#include <private/qv8engine_p.h>
#endif
@@ -315,6 +316,8 @@ ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId)
QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId];
Q_ASSERT(clos);
ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context);
+ if (clos->isGenerator())
+ return GeneratorFunction::create(current, clos)->asReturnedValue();
return FunctionObject::createScriptFunction(current, clos)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 17255c7e9e..08a085c90d 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -55,6 +55,7 @@
#include <private/qv4string_p.h>
#include <private/qv4profiling_p.h>
#include <private/qv4jscall_p.h>
+#include <private/qv4generatorobject_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include <iostream>
@@ -508,6 +509,8 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
CppStackFrame frame;
frame.originalArguments = argv;
frame.originalArgumentsCount = argc;
+ frame.yield = nullptr;
+ frame.exceptionHandler = nullptr;
Function *function;
{
@@ -586,10 +589,9 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const uchar *code)
{
QV4::Function *function = frame.v4Function;
QV4::Value &accumulator = frame.jsFrame->accumulator;
- QV4::ReturnedValue acc = Encode::undefined();
+ QV4::ReturnedValue acc = accumulator.asReturnedValue();
Value *stack = reinterpret_cast<Value *>(frame.jsFrame);
ExecutionEngine *engine = function->internalClass->engine;
- const uchar *exceptionHandler = nullptr;
MOTH_JUMP_TABLE;
@@ -798,6 +800,24 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const uchar *code)
CHECK_EXCEPTION;
MOTH_END_INSTR(LoadIdObject)
+ MOTH_BEGIN_INSTR(Yield)
+ frame.yield = code;
+ return acc;
+ MOTH_END_INSTR(Yield)
+
+ MOTH_BEGIN_INSTR(Resume)
+ // check exception, in case the generator was called with throw() or return()
+ if (engine->hasException) {
+ // an empty value indicates that the generator was called with return()
+ if (engine->exceptionValue->asReturnedValue() != Primitive::emptyValue().asReturnedValue())
+ goto catchException;
+ engine->hasException = false;
+ *engine->exceptionValue = Primitive::undefinedValue();
+ } else {
+ code += offset;
+ }
+ MOTH_END_INSTR(Resume)
+
MOTH_BEGIN_INSTR(CallValue)
STORE_IP();
Value func = STACK_VALUE(name);
@@ -867,7 +887,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const uchar *code)
MOTH_END_INSTR(CallContextObjectProperty)
MOTH_BEGIN_INSTR(SetExceptionHandler)
- exceptionHandler = offset ? code + offset : nullptr;
+ frame.exceptionHandler = offset ? code + offset : nullptr;
MOTH_END_INSTR(SetExceptionHandler)
MOTH_BEGIN_INSTR(ThrowException)
@@ -1406,10 +1426,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const uchar *code)
catchException:
Q_ASSERT(engine->hasException);
- if (!exceptionHandler) {
+ if (!frame.exceptionHandler) {
acc = Encode::undefined();
return acc;
}
- code = exceptionHandler;
+ code = frame.exceptionHandler;
}
}
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 9d6f1966e4..c25f3395e2 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -3627,7 +3627,7 @@ MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN Function
} break;
./
-MethodDefinition: T_STAR PropertyName T_LPAREN StrictFormalParameters T_RPAREN GeneratorLBrace GeneratorBody GeneratorRBrace;
+MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList);
@@ -3683,10 +3683,9 @@ PropertySetParameterList: FormalParameter;
} break;
./
-GeneratorLBrace: T_LBRACE;
+GeneratorLParen: T_LPAREN;
/.
case $rule_number: {
- ++functionNestingLevel;
lexer->enterGeneratorBody();
} break;
./
@@ -3699,7 +3698,7 @@ GeneratorRBrace: T_RBRACE;
} break;
./
-GeneratorDeclaration: Function T_STAR BindingIdentifier T_LPAREN FormalParameters T_RPAREN GeneratorLBrace GeneratorBody GeneratorRBrace;
+GeneratorDeclaration: Function T_STAR BindingIdentifier GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(3), sym(5).FormalParameterList, sym(8).StatementList);
@@ -3715,7 +3714,7 @@ GeneratorDeclaration: Function T_STAR BindingIdentifier T_LPAREN FormalParameter
./
GeneratorDeclaration_Default: GeneratorDeclaration;
-GeneratorDeclaration_Default: Function T_STAR T_LPAREN FormalParameters T_RPAREN GeneratorLBrace GeneratorBody GeneratorRBrace;
+GeneratorDeclaration_Default: Function T_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(1), sym(4).FormalParameterList, sym(7).StatementList);
@@ -3730,7 +3729,7 @@ GeneratorDeclaration_Default: Function T_STAR T_LPAREN FormalParameters T_RPAREN
} break;
./
-GeneratorExpression: T_FUNCTION T_STAR BindingIdentifier T_LPAREN FormalParameters T_RPAREN GeneratorLBrace GeneratorBody GeneratorRBrace;
+GeneratorExpression: T_FUNCTION T_STAR BindingIdentifier GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(3), sym(5).FormalParameterList, sym(8).StatementList);
@@ -3746,7 +3745,7 @@ GeneratorExpression: T_FUNCTION T_STAR BindingIdentifier T_LPAREN FormalParamete
} break;
./
-GeneratorExpression: T_FUNCTION T_STAR T_LPAREN FormalParameters T_RPAREN GeneratorLBrace GeneratorBody GeneratorRBrace;
+GeneratorExpression: T_FUNCTION T_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace;
/.
case $rule_number: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(4).FormalParameterList, sym(7).StatementList);