aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-03-21 12:25:51 +0100
committerLars Knoll <lars.knoll@qt.io>2018-04-27 08:11:00 +0000
commitc3ad706c6ff19a132bf78501430c850040e967fc (patch)
tree9d16716001c3cd25bf6c778fe9b5f4dc117c17c4 /src/qml/compiler
parent0de2ac924a3dbbd59b9e726f470113e4c87b0ae7 (diff)
Added support for generator functions and yield expressions to the AST
Some smaller changes to the codegen are included as well to ensure that we catch all uses of generators and properly throw an unimplemented error on them for now. Change-Id: Ib915a0e862e128644ff00dfe989507783c912c66 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/compiler')
-rw-r--r--src/qml/compiler/qv4codegen.cpp10
-rw-r--r--src/qml/compiler/qv4codegen_p.h1
-rw-r--r--src/qml/compiler/qv4compileddata_p.h1
-rw-r--r--src/qml/compiler/qv4compiler.cpp2
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h1
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp22
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h2
7 files changed, 31 insertions, 8 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 0033383189..d72162eeb1 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2260,6 +2260,12 @@ bool Codegen::visit(FunctionDeclaration * ast)
return false;
}
+bool Codegen::visit(YieldExpression *ast)
+{
+ throwSyntaxError(ast->firstSourceLocation(), QLatin1String("Support for 'yield' unimplemented."));
+ return false;
+}
+
static bool endsWithReturn(Node *node)
{
if (!node)
@@ -2288,6 +2294,10 @@ 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();
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 6de6affdcc..140f804d4a 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -588,6 +588,7 @@ protected:
bool visit(AST::UnaryPlusExpression *ast) override;
bool visit(AST::VoidExpression *ast) override;
bool visit(AST::FunctionDeclaration *ast) override;
+ bool visit(AST::YieldExpression *ast) override;
// statements
bool visit(AST::Block *ast) override;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 48bef10c6d..8f49fbd728 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -211,6 +211,7 @@ struct Function
HasDirectEval = 0x2,
UsesArgumentsObject = 0x4,
IsArrowFunction = 0x8,
+ IsGenerator = 0x20,
HasCatchOrWith = 0x10
};
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 4bc3940a02..d870c34101 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -308,6 +308,8 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->flags |= CompiledData::Function::IsStrict;
if (irFunction->isArrowFunction)
function->flags |= CompiledData::Function::IsArrowFunction;
+ if (irFunction->isGenerator)
+ function->flags |= CompiledData::Function::IsGenerator;
if (irFunction->hasTry || irFunction->hasWith)
function->flags |= CompiledData::Function::HasCatchOrWith;
function->nestedFunctionIndex =
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 89bdfc9d8e..9ce0d5fa1e 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -142,6 +142,7 @@ struct Context {
bool hasNestedFunctions = false;
bool isStrict = false;
bool isArrowFunction = false;
+ bool isGenerator = false;
bool usesThis = false;
bool hasTry = false;
bool hasWith = false;
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 5c606e7f7f..57f9105484 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -260,7 +260,7 @@ bool ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName)
{
if (_context->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode"));
- return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName ? ast : nullptr);
+ return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName);
}
void ScanFunctions::endVisit(FunctionExpression *)
@@ -289,7 +289,7 @@ bool ScanFunctions::visit(ObjectLiteral *ast)
bool ScanFunctions::visit(PropertyGetterSetter *ast)
{
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
- return enterFunction(ast, QString(), ast->formals, ast->functionBody, /*FunctionExpression*/nullptr);
+ return enterFunction(ast, QString(), ast->formals, ast->functionBody, /*enterName */ false);
}
void ScanFunctions::endVisit(PropertyGetterSetter *)
@@ -388,19 +388,23 @@ bool ScanFunctions::visit(Block *ast) {
return false;
}
-bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, StatementList *body, FunctionExpression *expr)
+bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, StatementList *body, bool enterName)
{
Context *outerContext = _context;
enterEnvironment(ast, FunctionCode);
+ FunctionExpression *expr = AST::cast<FunctionExpression *>(ast);
+ if (!expr)
+ expr = AST::cast<FunctionDeclaration *>(ast);
if (outerContext) {
outerContext->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
- if (expr) {
- if (!outerContext->addLocalVar(name, Context::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr)) {
+ if (enterName) {
+ if (!outerContext->addLocalVar(name, Context::FunctionDefinition, AST::VariableScope::Var, expr)) {
_cg->throwSyntaxError(ast->firstSourceLocation(), QStringLiteral("Identifier %1 has already been declared").arg(name));
return false;
}
+ outerContext->addLocalVar(name, Context::FunctionDefinition, AST::VariableScope::Var, expr);
}
if (name == QLatin1String("arguments"))
outerContext->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
@@ -408,8 +412,12 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
if (formals->containsName(QStringLiteral("arguments")))
_context->usesArgumentsObject = Context::ArgumentsObjectNotUsed;
- if (expr && expr->isArrowFunction)
- _context->isArrowFunction = true;
+ if (expr) {
+ if (expr->isArrowFunction)
+ _context->isArrowFunction = true;
+ else if (expr->isGenerator)
+ _context->isGenerator = true;
+ }
if (!name.isEmpty() && !formals->containsName(name))
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index cf79da2203..43fcc36897 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -136,7 +136,7 @@ protected:
bool visit(AST::Block *ast) override;
protected:
- bool enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::StatementList *body, AST::FunctionExpression *expr);
+ bool enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::StatementList *body, bool enterName);
void calcEscapingVariables();
// fields: