aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qv4compileddata_p.h2
-rw-r--r--src/qml/compiler/qv4compiler.cpp2
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h1
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp2
-rw-r--r--src/qml/jsruntime/qv4function_p.h1
-rw-r--r--src/qml/parser/qqmljs.g148
-rw-r--r--src/qml/parser/qqmljsast_p.h3
7 files changed, 140 insertions, 19 deletions
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 7f0b66c569..41c27ffcd4 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -210,7 +210,7 @@ struct Function
IsStrict = 0x1,
HasDirectEval = 0x2,
UsesArgumentsObject = 0x4,
-// Unused = 0x8,
+ IsArrowFunction = 0x8,
HasCatchOrWith = 0x10
};
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index c9e535c93f..bfb450d408 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -306,6 +306,8 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->flags |= CompiledData::Function::UsesArgumentsObject;
if (irFunction->isStrict)
function->flags |= CompiledData::Function::IsStrict;
+ if (irFunction->isArrowFunction)
+ function->flags |= CompiledData::Function::IsArrowFunction;
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 fef2b56055..89bdfc9d8e 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -141,6 +141,7 @@ struct Context {
bool hasDirectEval = false;
bool hasNestedFunctions = false;
bool isStrict = false;
+ bool isArrowFunction = 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 3f7211b95e..5c606e7f7f 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -408,6 +408,8 @@ 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 (!name.isEmpty() && !formals->containsName(name))
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index c8dbcec51d..d3206cc230 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 usesArgumentsObject() const { return compiledFunction->flags & CompiledData::Function::UsesArgumentsObject; }
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
+ inline bool isArrowFunction() const { return compiledFunction->flags & CompiledData::Function::IsArrowFunction; }
QQmlSourceLocation sourceLocation() const
{
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index fe8e744264..ecab053b4a 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -387,6 +387,7 @@ protected:
AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
AST::UiQualifiedPragmaId *reparseAsQualifiedPragmaId(AST::ExpressionNode *expr);
+ AST::FormalParameterList *reparseAsFormalParameterList(AST::ExpressionNode *expr);
void pushToken(int token);
int lookaheadToken(Lexer *lexer);
@@ -429,6 +430,14 @@ protected:
int functionNestingLevel = 0;
+ enum CoverExpressionType {
+ CE_Invalid,
+ CE_ParenthesizedExpression,
+ CE_FormalParameterList
+ };
+ AST::SourceLocation coverExpressionErrorLocation;
+ CoverExpressionType coverExpressionType = CE_Invalid;
+
QList<DiagnosticMessage> diagnostic_messages;
};
@@ -541,6 +550,34 @@ AST::UiQualifiedPragmaId *Parser::reparseAsQualifiedPragmaId(AST::ExpressionNode
return 0;
}
+AST::FormalParameterList *Parser::reparseAsFormalParameterList(AST::ExpressionNode *expr)
+{
+ AST::FormalParameterList *f = nullptr;
+ if (AST::Expression *commaExpr = AST::cast<AST::Expression *>(expr)) {
+ f = reparseAsFormalParameterList(commaExpr->left);
+ if (!f)
+ return nullptr;
+
+ expr = commaExpr->right;
+ }
+
+ AST::ExpressionNode *rhs = nullptr;
+ if (AST::BinaryExpression *assign = AST::cast<AST::BinaryExpression *>(expr)) {
+ if (assign->op != QSOperator::Assign)
+ return nullptr;
+ expr = assign->left;
+ rhs = assign->right;
+ }
+ AST::BindingElement *binding = nullptr;
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(expr)) {
+ binding = new (pool) AST::BindingElement(idExpr->name, rhs);
+ binding->identifierToken = idExpr->identifierToken;
+ }
+ if (!binding)
+ return nullptr;
+ return new (pool) AST::FormalParameterList(f, binding);
+}
+
void Parser::pushToken(int token)
{
last_token->token = yytoken;
@@ -1423,8 +1460,16 @@ PrimaryExpression: RegularExpressionLiteral;
PrimaryExpression: TemplateLiteral;
PrimaryExpression: CoverParenthesizedExpressionAndArrowParameterList;
+/.
+ case $rule_number: {
+ if (coverExpressionType != CE_ParenthesizedExpression) {
+ syntaxError(coverExpressionErrorLocation, "Expected token ')'.");
+ return false;
+ }
+ } break;
+./
--- ### Further restricted parsing of the CoverParenthesizedExpressionAndArrowParameterList to the one rule below when this is parsed as a primary expression!
+-- Parsing of the CoverParenthesizedExpressionAndArrowParameterList is restricted to the one rule below when this is parsed as a primary expression
CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN Expression_In T_RPAREN;
/.
case $rule_number: {
@@ -1432,14 +1477,42 @@ CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN Expression_In T_RPAR
node->lparenToken = loc(1);
node->rparenToken = loc(3);
sym(1).Node = node;
+ coverExpressionType = CE_ParenthesizedExpression;
} break;
./
CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN T_RPAREN;
-CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN T_ELLIPSIS BindingIdentifier T_RPAREN;
-CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN T_ELLIPSIS BindingPattern T_RPAREN;
-CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN Expression_In T_COMMA T_ELLIPSIS BindingIdentifier T_RPAREN;
-CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN Expression_In T_COMMA T_ELLIPSIS BindingPattern T_RPAREN;
+/.
+ case $rule_number: {
+ sym(1).Node = nullptr;
+ coverExpressionErrorLocation = loc(2);
+ coverExpressionType = CE_FormalParameterList;
+ } break;
+./
+
+CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN BindingRestElement T_RPAREN;
+/.
+ case $rule_number: {
+ AST::FormalParameterList *node = (new (pool) AST::FormalParameterList(nullptr, sym(2).Node))->finish();
+ sym(1).Node = node;
+ coverExpressionErrorLocation = loc(2);
+ coverExpressionType = CE_FormalParameterList;
+ } break;
+./
+
+CoverParenthesizedExpressionAndArrowParameterList: T_LPAREN Expression_In T_COMMA BindingRestElementOpt T_RPAREN;
+/.
+ case $rule_number: {
+ AST::FormalParameterList *list = reparseAsFormalParameterList(sym(2).Expression);
+ if (!list)
+ syntaxError(loc(1), "Invalid Arrow parameter list.");
+ if (sym(4).Node)
+ list = new (pool) AST::FormalParameterList(list, sym(4).Node);
+ coverExpressionErrorLocation = loc(4);
+ coverExpressionType = CE_FormalParameterList;
+ sym(1).Node = list->finish();
+ } break;
+./
Literal: T_NULL;
/.
@@ -3361,17 +3434,63 @@ FunctionRBrace: T_RBRACE;
FunctionBody: FunctionStatementList;
FunctionStatementList: StatementListOpt;
-ArrowFunction: ArrowParameters T_ARROW ConciseBody;
-/. case $rule_number: { UNIMPLEMENTED; } ./
-ArrowFunction_In: ArrowParameters T_ARROW ConciseBody_In;
-/. case $rule_number: { UNIMPLEMENTED; } ./
+ArrowFunction: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpression; -- [lookahead ≠ {]
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpression_In; -- [lookahead ≠ {]
+/.
+ case $rule_number: {
+ AST::ReturnStatement *ret = new (pool) AST::ReturnStatement(sym(4).Expression);
+ ret->returnToken = sym(4).Node->firstSourceLocation();
+ ret->semicolonToken = sym(4).Node->lastSourceLocation();
+ AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish();
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringRef(), sym(1).FormalParameterList, statements);
+ f->isArrowFunction = true;
+ f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1);
+ f->lbraceToken = sym(4).Node->firstSourceLocation();
+ f->rbraceToken = sym(4).Node->lastSourceLocation();
+ sym(1).Node = f;
+ } break;
+./
+
+ArrowFunction: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK FunctionLBrace FunctionBody FunctionRBrace;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK FunctionLBrace FunctionBody FunctionRBrace;
+/.
+ case $rule_number: {
+ AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringRef(), sym(1).FormalParameterList, sym(6).StatementList);
+ f->isArrowFunction = true;
+ f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1);
+ f->lbraceToken = loc(6);
+ f->rbraceToken = loc(7);
+ sym(1).Node = f;
+ } break;
+./
ArrowParameters: BindingIdentifier;
+/.
+ case $rule_number: {
+ AST::BindingElement *e = new (pool) AST::BindingElement(stringRef(1));
+ e->identifierToken = loc(1);
+ sym(1).FormalParameterList = (new (pool) AST::FormalParameterList(nullptr, e))->finish();
+ } break;
+./
+-- CoverParenthesizedExpressionAndArrowParameterList for ArrowParameters i being refined to:
+-- ArrowFormalParameters: T_LPAREN StrictFormalParameters T_RPAREN
ArrowParameters: CoverParenthesizedExpressionAndArrowParameterList;
-
--- ### CoverParenthesizedExpressionAndArrowParameterList for ArrowParameters refined to:
--- ArrowFormalParameters[Yield]: (StrictFormalParameters[?Yield])
+/.
+ case $rule_number: {
+ if (coverExpressionType != CE_FormalParameterList) {
+ AST::NestedExpression *ne = static_cast<AST::NestedExpression *>(sym(1).Node);
+ AST::FormalParameterList *list = reparseAsFormalParameterList(ne->expression);
+ if (!list) {
+ syntaxError(loc(1), "Invalid Arrow parameter list.");
+ return false;
+ }
+ sym(1).Node = list->finish();
+ }
+ } break;
+./
ConciseBodyLookahead: ;
/:
@@ -3384,11 +3503,6 @@ ConciseBodyLookahead: ;
} break;
./
-ConciseBody: ConciseBodyLookahead AssignmentExpression; -- [lookahead ≠ {]
-ConciseBody_In: ConciseBodyLookahead AssignmentExpression_In; -- [lookahead ≠ {]
-ConciseBody: ConciseBodyLookahead T_FORCE_BLOCK FunctionLBrace FunctionBody FunctionRBrace;
-ConciseBody_In: ConciseBodyLookahead T_FORCE_BLOCK FunctionLBrace FunctionBody FunctionRBrace;
-
MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace;
/. case $rule_number: { UNIMPLEMENTED; } ./
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 6c8a5c7af6..db41528a02 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -1327,7 +1327,7 @@ public:
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
- { return statement ? statement->firstSourceLocation() : statement->firstSourceLocation(); }
+ { return statement->firstSourceLocation(); }
SourceLocation lastSourceLocation() const override
{ return next ? next->lastSourceLocation() : statement->lastSourceLocation(); }
@@ -2061,6 +2061,7 @@ public:
// attributes
QStringRef name;
+ bool isArrowFunction = false;
FormalParameterList *formals;
StatementList *body;
SourceLocation functionToken;