diff options
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 1 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 148 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 3 |
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; |