diff options
Diffstat (limited to 'src/qml/parser/qqmljs.g')
-rw-r--r-- | src/qml/parser/qqmljs.g | 966 |
1 files changed, 625 insertions, 341 deletions
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index e28899883f..32b609f5ff 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -1,41 +1,5 @@ ----------------------------------------------------------------------------- --- -- Copyright (C) 2016 The Qt Company Ltd. --- Contact: http://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$ --- ----------------------------------------------------------------------------- +-- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only %parser QQmlJSGrammar %decl qqmljsparser_p.h @@ -73,13 +37,15 @@ %token T_VAR "var" T_VOID "void" T_WHILE "while" %token T_WITH "with" T_XOR "^" T_XOR_EQ "^=" %token T_NULL "null" T_TRUE "true" T_FALSE "false" -%token T_CONST "const" T_LET "let" +%token T_CONST "const" T_LET "let" T_AT "@" %token T_DEBUGGER "debugger" %token T_RESERVED_WORD "reserved word" %token T_MULTILINE_STRING_LITERAL "multiline string literal" %token T_COMMENT "comment" %token T_COMPATIBILITY_SEMICOLON %token T_ARROW "=>" +%token T_QUESTION_QUESTION "??" +%token T_QUESTION_DOT "?." %token T_ENUM "enum" %token T_ELLIPSIS "..." %token T_YIELD "yield" @@ -90,6 +56,7 @@ %token T_EXPORT "export" %token T_FROM "from" %token T_REQUIRED "required" +%token T_COMPONENT "component" --- template strings %token T_NO_SUBSTITUTION_TEMPLATE"(no subst template)" @@ -106,8 +73,19 @@ %token T_GET "get" %token T_SET "set" +-- token representing no token +%token T_NONE + %token T_ERROR +-- states for line by line parsing +%token T_EOL +%token T_PARTIAL_COMMENT "non closed multiline comment" +%token T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL "multiline single quote string literal" +%token T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL "multiline double quote string literal" +%token T_PARTIAL_TEMPLATE_HEAD "(template head)" +%token T_PARTIAL_TEMPLATE_MIDDLE "(template middle)" + --- feed tokens %token T_FEED_UI_PROGRAM %token T_FEED_UI_OBJECT_MEMBER @@ -122,50 +100,16 @@ %token T_FOR_LOOKAHEAD_OK "(for lookahead ok)" --%left T_PLUS T_MINUS -%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS T_REQUIRED +%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS T_REQUIRED T_COMPONENT %nonassoc REDUCE_HERE %right T_THEN T_ELSE +%right T_WITHOUTAS T_AS %start TopLevel -/./**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +/.// Copyright (C) 2016 The Qt Company Ltd. +// Contact: https://www.qt.io/licensing/ +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -179,44 +123,9 @@ ./ -/:/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ +/:// Copyright (C) 2016 The Qt Company Ltd. +// Contact: https://www.qt.io/licensing/ +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // @@ -303,14 +212,15 @@ public: AST::ExportClause *ExportClause; AST::ExportDeclaration *ExportDeclaration; AST::TypeAnnotation *TypeAnnotation; - AST::TypeArgumentList *TypeArgumentList; AST::Type *Type; AST::UiProgram *UiProgram; AST::UiHeaderItemList *UiHeaderItemList; + AST::UiPragmaValueList *UiPragmaValueList; AST::UiPragma *UiPragma; AST::UiImport *UiImport; AST::UiParameterList *UiParameterList; + AST::UiPropertyAttributes *UiPropertyAttributes; AST::UiPublicMember *UiPublicMember; AST::UiObjectDefinition *UiObjectDefinition; AST::UiObjectInitializer *UiObjectInitializer; @@ -323,6 +233,8 @@ public: AST::UiQualifiedId *UiQualifiedId; AST::UiEnumMemberList *UiEnumMemberList; AST::UiVersionSpecifier *UiVersionSpecifier; + AST::UiAnnotation *UiAnnotation; + AST::UiAnnotationList *UiAnnotationList; }; public: @@ -385,10 +297,22 @@ public: { return diagnosticMessage().message; } inline int errorLineNumber() const - { return diagnosticMessage().line; } + { return diagnosticMessage().loc.startLine; } inline int errorColumnNumber() const - { return diagnosticMessage().column; } + { return diagnosticMessage().loc.startColumn; } + + inline bool identifierInsertionEnabled() const + { return m_identifierInsertionEnabled; } + + inline void setIdentifierInsertionEnabled(bool enable) + { m_identifierInsertionEnabled = enable; } + + inline bool incompleteBindingsEnabled() const + { return m_incompleteBindingsEnabled; } + + inline void setIncompleteBindingsEnabled(bool enable) + { m_incompleteBindingsEnabled = enable; } protected: bool parse(int startToken); @@ -398,35 +322,35 @@ protected: inline Value &sym(int index) { return sym_stack [tos + index - 1]; } - inline QStringRef &stringRef(int index) + inline QStringView &stringRef(int index) { return string_stack [tos + index - 1]; } - inline QStringRef &rawStringRef(int index) + inline QStringView &rawStringRef(int index) { return rawString_stack [tos + index - 1]; } - inline AST::SourceLocation &loc(int index) + inline SourceLocation &loc(int index) { return location_stack [tos + index - 1]; } AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr); void pushToken(int token); + void pushTokenWithEmptyLocation(int token); int lookaheadToken(Lexer *lexer); - static DiagnosticMessage compileError(const AST::SourceLocation &location, + static DiagnosticMessage compileError(const SourceLocation &location, const QString &message, QtMsgType kind = QtCriticalMsg) { DiagnosticMessage error; - error.line = location.startLine; - error.column = location.startColumn; + error.loc = location; error.message = message; error.type = kind; return error; } - void syntaxError(const AST::SourceLocation &location, const char *message) { + void syntaxError(const SourceLocation &location, const char *message) { diagnostic_messages.append(compileError(location, QLatin1String(message))); } - void syntaxError(const AST::SourceLocation &location, const QString &message) { + void syntaxError(const SourceLocation &location, const QString &message) { diagnostic_messages.append(compileError(location, message)); } @@ -439,9 +363,9 @@ protected: int stack_size = 0; Value *sym_stack = nullptr; int *state_stack = nullptr; - AST::SourceLocation *location_stack = nullptr; - QVector<QStringRef> string_stack; - QVector<QStringRef> rawString_stack; + SourceLocation *location_stack = nullptr; + std::vector<QStringView> string_stack; + std::vector<QStringView> rawString_stack; AST::Node *program = nullptr; @@ -451,33 +375,37 @@ protected: struct SavedToken { int token; double dval; - AST::SourceLocation loc; - QStringRef spell; - QStringRef raw; + SourceLocation loc; + QStringView spell; + QStringView raw; }; int yytoken = -1; double yylval = 0.; - QStringRef yytokenspell; - QStringRef yytokenraw; - AST::SourceLocation yylloc; - AST::SourceLocation yyprevlloc; + QStringView yytokenspell; + QStringView yytokenraw; + SourceLocation yylloc; + SourceLocation yyprevlloc; + int yyprevtoken = -1; SavedToken token_buffer[TOKEN_BUFFER_SIZE]; SavedToken *first_token = nullptr; SavedToken *last_token = nullptr; int functionNestingLevel = 0; + int classNestingLevel = 0; enum CoverExpressionType { CE_Invalid, CE_ParenthesizedExpression, CE_FormalParameterList }; - AST::SourceLocation coverExpressionErrorLocation; + SourceLocation coverExpressionErrorLocation; CoverExpressionType coverExpressionType = CE_Invalid; QList<DiagnosticMessage> diagnostic_messages; + bool m_identifierInsertionEnabled = false; + bool m_incompleteBindingsEnabled = false; }; } // end of namespace QQmlJS @@ -519,7 +447,7 @@ void Parser::reallocateStack() sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value))); state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int))); - location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation))); + location_stack = reinterpret_cast<SourceLocation*> (realloc(location_stack, stack_size * sizeof(SourceLocation))); string_stack.resize(stack_size); rawString_stack.resize(stack_size); } @@ -539,9 +467,9 @@ Parser::~Parser() } } -static inline AST::SourceLocation location(Lexer *lexer) +static inline SourceLocation location(Lexer *lexer) { - AST::SourceLocation loc; + SourceLocation loc; loc.offset = lexer->tokenOffset(); loc.length = lexer->tokenLength(); loc.startLine = lexer->tokenStartLine(); @@ -551,13 +479,15 @@ static inline AST::SourceLocation location(Lexer *lexer) AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) { - QVarLengthArray<QStringRef, 4> nameIds; - QVarLengthArray<AST::SourceLocation, 4> locations; + QVarLengthArray<QStringView, 4> nameIds; + QVarLengthArray<SourceLocation, 4> locations; + QVarLengthArray<SourceLocation, 4> dotLocations; AST::ExpressionNode *it = expr; while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) { nameIds.append(m->name); locations.append(m->identifierToken); + dotLocations.append(m->dotToken); it = m->base; } @@ -569,6 +499,7 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) for (int i = nameIds.size() - 1; i != -1; --i) { currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]); currentId->identifierToken = locations[i]; + currentId->dotToken = dotLocations[i]; } return currentId->finish(); @@ -590,9 +521,19 @@ void Parser::pushToken(int token) yytoken = token; } +void Parser::pushTokenWithEmptyLocation(int token) +{ + pushToken(token); + yylloc = yyprevlloc; + yylloc.offset += yylloc.length; + yylloc.startColumn += yylloc.length; + yylloc.length = 0; +} + int Parser::lookaheadToken(Lexer *lexer) { if (yytoken < 0) { + yyprevtoken = yytoken; yytoken = lexer->lex(); yylval = lexer->tokenValue(); yytokenspell = lexer->tokenSpell(); @@ -688,6 +629,7 @@ bool Parser::parse(int startToken) #endif if (action > 0) { if (action != ACCEPT_STATE) { + yyprevtoken = yytoken; yytoken = -1; sym(1).dval = yylval; stringRef(1) = yytokenspell; @@ -736,7 +678,7 @@ TopLevel: T_FEED_JS_EXPRESSION Expression; } break; ./ -TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember; +TopLevel: T_FEED_UI_OBJECT_MEMBER UiAnnotatedObjectMember; /. case $rule_number: { sym(1).Node = sym(2).Node; @@ -805,20 +747,56 @@ UiHeaderItemList: UiHeaderItemList UiImport; ./ PragmaId: JsIdentifier; +PragmaValue: JsIdentifier + | T_STRING_LITERAL; Semicolon: T_AUTOMATIC_SEMICOLON; Semicolon: T_SEMICOLON; +UiPragmaValueList: PragmaValue; +/. + case $rule_number: { + AST::UiPragmaValueList *list + = new (pool) AST::UiPragmaValueList(stringRef(1)); + list->location = loc(1); + sym(1).Node = list; + } break; +./ + +UiPragmaValueList: UiPragmaValueList T_COMMA PragmaValue; +/. + case $rule_number: { + AST::UiPragmaValueList *list + = new (pool) AST::UiPragmaValueList(sym(1).UiPragmaValueList, stringRef(3)); + list->location = loc(3); + sym(1).Node = list; + } break; +./ + UiPragma: T_PRAGMA PragmaId Semicolon; /. case $rule_number: { AST::UiPragma *pragma = new (pool) AST::UiPragma(stringRef(2)); pragma->pragmaToken = loc(1); + pragma->pragmaIdToken = loc(2); pragma->semicolonToken = loc(3); sym(1).Node = pragma; } break; ./ +UiPragma: T_PRAGMA PragmaId T_COLON UiPragmaValueList Semicolon; +/. + case $rule_number: { + AST::UiPragma *pragma = new (pool) AST::UiPragma( + stringRef(2), sym(4).UiPragmaValueList->finish()); + pragma->pragmaToken = loc(1); + pragma->pragmaIdToken = loc(2); + pragma->colonToken = loc(3); + pragma->semicolonToken = loc(5); + sym(1).Node = pragma; + } break; +./ + ImportId: MemberExpression; UiImport: UiImportHead Semicolon; @@ -831,7 +809,15 @@ UiImport: UiImportHead Semicolon; UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER; /. case $rule_number: { - auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, sym(3).dval); + const int major = sym(1).dval; + const int minor = sym(3).dval; + if (!QTypeRevision::isValidSegment(major) || !QTypeRevision::isValidSegment(minor)) { + diagnostic_messages.append( + compileError(loc(1), + QLatin1String("Invalid version. Version numbers must be >= 0 and < 255."))); + return false; + } + auto version = new (pool) AST::UiVersionSpecifier(major, minor); version->majorToken = loc(1); version->minorToken = loc(3); sym(1).UiVersionSpecifier = version; @@ -842,7 +828,14 @@ UiVersionSpecifier: T_VERSION_NUMBER T_DOT T_VERSION_NUMBER; UiVersionSpecifier: T_VERSION_NUMBER; /. case $rule_number: { - auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, 0); + const int major = sym(1).dval; + if (!QTypeRevision::isValidSegment(major)) { + diagnostic_messages.append( + compileError(loc(1), + QLatin1String("Invalid major version. Version numbers must be >= 0 and < 255."))); + return false; + } + auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval); version->majorToken = loc(1); sym(1).UiVersionSpecifier = version; } break; @@ -910,21 +903,92 @@ Empty: ; } break; ./ -UiRootMember: UiObjectDefinition; +UiRootMember: UiAnnotatedObject; /. case $rule_number: { sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); } break; ./ -UiObjectMemberList: UiObjectMember; +UiSimpleQualifiedId: T_IDENTIFIER; +/. + case $rule_number: { + AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1)); + node->identifierToken = loc(1); + sym(1).Node = node; + } break; +./ + +UiSimpleQualifiedId: UiSimpleQualifiedId T_DOT T_IDENTIFIER; +/. + case $rule_number: { + AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); + node->dotToken = loc(2); + node->identifierToken = loc(3); + sym(1).Node = node; + } break; +./ + +UiAnnotationObjectDefinition: UiSimpleQualifiedId UiObjectInitializer; +/. + case $rule_number: { + if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) { + sym(1).UiQualifiedId = qualifiedId; + } else { + sym(1).UiQualifiedId = 0; + + diagnostic_messages.append(compileError(loc(1), + QLatin1String("Expected a qualified name id"))); + + return false; + } + AST::UiAnnotation *node = new (pool) AST::UiAnnotation(sym(1).UiQualifiedId, sym(2).UiObjectInitializer); + sym(1).Node = node; + } break; +./ + +UiAnnotation: T_AT UiAnnotationObjectDefinition; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; +} break; +./ + + +UiAnnotationList: UiAnnotation; +/. + case $rule_number: { + sym(1).Node = new (pool) AST::UiAnnotationList(sym(1).UiAnnotation); + } break; +./ + +UiAnnotationList: UiAnnotationList UiAnnotation; +/. + case $rule_number: { + AST::UiAnnotationList *node = new (pool) AST::UiAnnotationList(sym(1).UiAnnotationList, sym(2).UiAnnotation); + sym(1).Node = node; + } break; +./ + +UiAnnotatedObject: UiAnnotationList UiObjectDefinition; +/. + case $rule_number: { + AST::UiObjectDefinition *node = sym(2).UiObjectDefinition; + node->annotations = sym(1).UiAnnotationList->finish(); + sym(1).Node = node; + } break; +./ + +UiAnnotatedObject: UiObjectDefinition; + +UiObjectMemberList: UiAnnotatedObjectMember; /. case $rule_number: { sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember); } break; ./ -UiObjectMemberList: UiObjectMemberList UiObjectMember; +UiObjectMemberList: UiObjectMemberList UiAnnotatedObjectMember; /. case $rule_number: { AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(sym(1).UiObjectMemberList, sym(2).UiObjectMember); @@ -976,6 +1040,17 @@ UiObjectDefinition: UiQualifiedId UiObjectInitializer; } break; ./ +UiAnnotatedObjectMember: UiAnnotationList UiObjectMember; +/. + case $rule_number: { + AST::UiObjectMember *node = sym(2).UiObjectMember; + node->annotations = sym(1).UiAnnotationList->finish(); + sym(1).Node = sym(2).Node; + } break; +./ + +UiAnnotatedObjectMember: UiObjectMember; + UiObjectMember: UiObjectDefinition; UiObjectMember: UiQualifiedId T_COLON ExpressionStatementLookahead T_LBRACKET UiArrayMemberList T_RBRACKET; @@ -1011,15 +1086,27 @@ UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer; ./ -UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE; -/. case $rule_number: Q_FALLTHROUGH(); ./ -UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE; +UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_RBRACE Semicolon; /. case $rule_number: { AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish()); l->lbraceToken = loc(1); l->rbraceToken = loc(4); AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l); + node->semicolonToken = loc(5); + sym(1).Node = node; + } break; +./ + + +UiObjectLiteral: T_LBRACE ExpressionStatementLookahead UiPropertyDefinitionList T_COMMA T_RBRACE Semicolon; +/. + case $rule_number: { + AST::ObjectPattern *l = new (pool) AST::ObjectPattern(sym(3).PatternPropertyList->finish()); + l->lbraceToken = loc(1); + l->rbraceToken = loc(5); + AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(l); + node->semicolonToken = loc(6); sym(1).Node = node; } break; ./ @@ -1064,6 +1151,20 @@ case $rule_number: } break; ./ +UiObjectMember: UiQualifiedId Semicolon; +/. + case $rule_number: { + if (!m_incompleteBindingsEnabled) { + diagnostic_messages.append(compileError(loc(1), QLatin1String("Incomplete binding, expected token `:` or `{`"))); + return false; + } + AST::EmptyStatement *statement = new (pool) AST::EmptyStatement; + statement->semicolonToken = loc(2); + AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(sym(1).UiQualifiedId, statement); + sym(1).Node = node; + } break; +./ + UiPropertyType: T_VAR; /. case $rule_number: Q_FALLTHROUGH(); ./ UiPropertyType: T_RESERVED_WORD; @@ -1100,10 +1201,10 @@ UiParameterListOpt: UiParameterList; } break; ./ -UiParameterList: QmlIdentifier T_COLON UiPropertyType; +UiParameterList: QmlIdentifier T_COLON Type; /. case $rule_number: { - AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).UiQualifiedId->finish(), stringRef(1)); + AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).Type, stringRef(1)); node->identifierToken = loc(1); node->colonToken = loc(2); node->propertyTypeToken = loc(3); @@ -1111,20 +1212,20 @@ UiParameterList: QmlIdentifier T_COLON UiPropertyType; } break; ./ -UiParameterList: UiPropertyType QmlIdentifier; +UiParameterList: Type QmlIdentifier; /. case $rule_number: { - AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiQualifiedId->finish(), stringRef(2)); + AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).Type, stringRef(2)); node->propertyTypeToken = loc(1); node->identifierToken = loc(2); sym(1).Node = node; } break; ./ -UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType; +UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON Type; /. case $rule_number: { - AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).UiQualifiedId->finish(), stringRef(3)); + AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).Type, stringRef(3)); node->propertyTypeToken = loc(5); node->commaToken = loc(2); node->identifierToken = loc(3); @@ -1133,10 +1234,10 @@ UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType; } break; ./ -UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier; +UiParameterList: UiParameterList T_COMMA Type QmlIdentifier; /. case $rule_number: { - AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).UiQualifiedId->finish(), stringRef(4)); + AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(3).Type, stringRef(4)); node->propertyTypeToken = loc(3); node->commaToken = loc(2); node->identifierToken = loc(4); @@ -1149,7 +1250,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN Semic case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2)); node->type = AST::UiPublicMember::Signal; - node->propertyToken = loc(1); + node->setPropertyToken(loc(1)); node->typeToken = loc(2); node->identifierToken = loc(2); node->parameters = sym(4).UiParameterList; @@ -1163,7 +1264,7 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon; case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(nullptr, stringRef(2)); node->type = AST::UiPublicMember::Signal; - node->propertyToken = loc(1); + node->setPropertyToken(loc(1)); node->typeToken = loc(2); node->identifierToken = loc(2); node->semicolonToken = loc(3); @@ -1171,89 +1272,124 @@ UiObjectMember: T_SIGNAL T_IDENTIFIER Semicolon; } break; ./ -UiObjectMemberListPropertyNoInitialiser: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon; +------------------------------------------------------------------------------- +-- There is some ambiguity in whether required default property should be parsed +-- as required (default (property)) or as ((required (default)) property) +-- by reducing after each attribute modifier, we ensure that T_PROPERTY (which +-- is always available is used as the base case (so we only have to allocate the +-- node in the T_PROPERY case, and all other rules can assume that the node is +-- already available). +-------------------------------------------------------------------------------- + +AttrRequired: T_REQUIRED %prec REDUCE_HERE; +AttrReadonly: T_READONLY %prec REDUCE_HERE; +AttrDefault: T_DEFAULT %prec REDUCE_HERE; + +UiPropertyAttributes: AttrRequired UiPropertyAttributes; /. case $rule_number: { - AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6)); - node->typeModifier = stringRef(2); - node->propertyToken = loc(1); - node->typeModifierToken = loc(2); - node->typeToken = loc(4); - node->identifierToken = loc(6); - node->semicolonToken = loc(7); - sym(1).Node = node; + AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes; + if (node->isRequired()) + diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'required' attribute is not allowed."), QtCriticalMsg)); + node->m_requiredToken = loc(1); + sym(1).UiPropertyAttributes = node; } break; ./ -UiObjectMember: UiObjectMemberListPropertyNoInitialiser; - -UiObjectMember: T_READONLY UiObjectMemberListPropertyNoInitialiser; +UiPropertyAttributes: AttrDefault UiPropertyAttributes; /. case $rule_number: { - AST::UiPublicMember *node = sym(2).UiPublicMember; - node->isReadonlyMember = true; - node->readonlyToken = loc(1); - sym(1).Node = node; + AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes; + if (node->isDefaultMember()) + diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'default' attribute is not allowed."), QtCriticalMsg)); + node->m_defaultToken = loc(1); + sym(1).UiPropertyAttributes = node; } break; ./ -UiObjectMemberPropertyNoInitialiser: T_PROPERTY UiPropertyType QmlIdentifier Semicolon; +UiPropertyAttributes: AttrReadonly UiPropertyAttributes; /. case $rule_number: { - AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3)); - node->propertyToken = loc(1); - node->typeToken = loc(2); - node->identifierToken = loc(3); - node->semicolonToken = loc(4); - sym(1).Node = node; + AST::UiPropertyAttributes *node = sym(2).UiPropertyAttributes; + if (node->isReadonly()) + diagnostic_messages.append(compileError(node->requiredToken(), QLatin1String("Duplicated 'readonly' attribute is not allowed."), QtCriticalMsg)); + node->m_readonlyToken = loc(1); + sym(1).UiPropertyAttributes = node; } break; ./ +UiPropertyAttributes: T_PROPERTY; +/. + case $rule_number: { + AST::UiPropertyAttributes *node = new (pool) AST::UiPropertyAttributes(); + node->m_propertyToken = loc(1); + sym(1).UiPropertyAttributes = node; + } break; +./ -UiObjectMember: UiObjectMemberPropertyNoInitialiser; - -UiObjectMember: T_DEFAULT UiObjectMemberPropertyNoInitialiser; +UiObjectMemberListPropertyNoInitialiser: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier Semicolon; /. case $rule_number: { - AST::UiPublicMember *node = sym(2).UiPublicMember; - node->isDefaultMember = true; - node->defaultToken = loc(1); + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6)); + auto attributes = sym(1).UiPropertyAttributes; + node->setAttributes(attributes); + if (attributes->isReadonly()) + diagnostic_messages.append(compileError(attributes->readonlyToken(), QLatin1String("Read-only properties require an initializer."), QtWarningMsg)); + node->typeModifier = stringRef(2); + node->typeModifierToken = loc(2); + node->typeToken = loc(4); + node->identifierToken = loc(6); + node->semicolonToken = loc(7); sym(1).Node = node; } break; ./ -UiObjectMember: T_DEFAULT UiObjectMemberListPropertyNoInitialiser; +UiObjectMember: UiObjectMemberListPropertyNoInitialiser; + +UiObjectMemberPropertyNoInitialiser: UiPropertyAttributes UiPropertyType QmlIdentifier Semicolon; /. case $rule_number: { - AST::UiPublicMember *node = sym(2).UiPublicMember; - node->isDefaultMember = true; - node->defaultToken = loc(1); + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3)); + auto attributes = sym(1).UiPropertyAttributes; + if (attributes->isReadonly()) + diagnostic_messages.append(compileError(attributes->readonlyToken(), QLatin1String("Read-only properties require an initializer."), QtCriticalMsg)); + node->setAttributes(attributes); + node->typeToken = loc(2); + node->identifierToken = loc(3); + node->semicolonToken = loc(4); sym(1).Node = node; } break; ./ + +UiObjectMember: UiObjectMemberPropertyNoInitialiser; + OptionalSemicolon: | Semicolon; /. /* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/ ./ -UiObjectMember: T_REQUIRED UiObjectMemberPropertyNoInitialiser; +UiRequired: T_REQUIRED QmlIdentifier Semicolon; /. case $rule_number: { - AST::UiPublicMember *node = sym(2).UiPublicMember; + AST::UiRequired *node = new (pool) AST::UiRequired(stringRef(2)); node->requiredToken = loc(1); - node->isRequired = true; + node->semicolonToken = loc(3); sym(1).Node = node; } break; ./ +UiObjectMember: UiRequired; -UiObjectMemberWithScriptStatement: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon; +UiObjectMemberWithScriptStatement: UiPropertyAttributes UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement); - node->propertyToken = loc(1); + auto attributes = sym(1).UiPropertyAttributes; + if (attributes->isRequired()) + diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg)); + node->setAttributes(attributes); node->typeToken = loc(2); node->identifierToken = loc(3); node->colonToken = loc(4); @@ -1261,47 +1397,48 @@ UiObjectMemberWithScriptStatement: T_PROPERTY UiPropertyType QmlIdentifier T_COL } break; ./ -UiObjectMember: UiObjectMemberWithScriptStatement; - -UiObjectMember: T_READONLY UiObjectMemberWithScriptStatement; +UiObjectMemberWithScriptStatement: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon; /. case $rule_number: { - AST::UiPublicMember *node = sym(2).UiPublicMember; - node->isReadonlyMember = true; - node->readonlyToken = loc(1); + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6), sym(8).Statement); + node->typeModifier = stringRef(2); + auto attributes = sym(1).UiPropertyAttributes; + if (attributes->isRequired()) + diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg)); + node->setAttributes(attributes); + node->typeModifierToken = loc(2); + node->typeToken = loc(4); + node->identifierToken = loc(6); + node->colonToken = loc(7); sym(1).Node = node; } break; ./ -UiObjectMember: T_DEFAULT UiObjectMemberWithScriptStatement; -/. - case $rule_number: { - AST::UiPublicMember *node = sym(2).UiPublicMember; - node->isDefaultMember = true; - node->defaultToken = loc(1); - sym(1).Node = node; - } break; -./ +UiObjectMember: UiObjectMemberWithScriptStatement; -UiObjectMemberWithArray: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon; +UiObjectMemberWithArray: UiPropertyAttributes T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON ExpressionStatementLookahead T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6)); + auto attributes = sym(1).UiPropertyAttributes; + if (attributes->isRequired()) + diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtCriticalMsg)); + node->setAttributes(attributes); node->typeModifier = stringRef(2); - node->propertyToken = loc(1); node->typeModifierToken = loc(2); node->typeToken = loc(4); node->identifierToken = loc(6); node->semicolonToken = loc(7); // insert a fake ';' before ':' + node->colonToken = loc(7); AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6)); propertyName->identifierToken = loc(6); - propertyName->next = 0; + propertyName->next = nullptr; - AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(9).UiArrayMemberList->finish()); + AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish()); binding->colonToken = loc(7); - binding->lbracketToken = loc(8); - binding->rbracketToken = loc(10); + binding->lbracketToken = loc(9); + binding->rbracketToken = loc(11); node->binding = binding; @@ -1311,28 +1448,22 @@ UiObjectMemberWithArray: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIde UiObjectMember: UiObjectMemberWithArray; -UiObjectMember: T_READONLY UiObjectMemberWithArray; -/. - case $rule_number: { - AST::UiPublicMember *node = sym(2).UiPublicMember; - node->isReadonlyMember = true; - node->readonlyToken = loc(1); - sym(1).Node = node; - } break; -./ - -UiObjectMemberExpressionStatementLookahead: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon; +UiObjectMemberExpressionStatementLookahead: UiPropertyAttributes UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon; /. case $rule_number: { AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3)); - node->propertyToken = loc(1); + auto attributes = sym(1).UiPropertyAttributes; + if (attributes->isRequired()) + diagnostic_messages.append(compileError(attributes->requiredToken(), QLatin1String("Required properties with initializer do not make sense."), QtWarningMsg)); + node->setAttributes(attributes); node->typeToken = loc(2); node->identifierToken = loc(3); node->semicolonToken = loc(4); // insert a fake ';' before ':' + node->colonToken = loc(4); AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3)); propertyName->identifierToken = loc(3); - propertyName->next = 0; + propertyName->next = nullptr; AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding( propertyName, sym(6).UiQualifiedId, sym(7).UiObjectInitializer); @@ -1346,16 +1477,6 @@ UiObjectMemberExpressionStatementLookahead: T_PROPERTY UiPropertyType QmlIdentif UiObjectMember: UiObjectMemberExpressionStatementLookahead; -UiObjectMember: T_READONLY UiObjectMemberExpressionStatementLookahead; -/. - case $rule_number: { - AST::UiPublicMember *node = sym(2).UiPublicMember; - node->isReadonlyMember = true; - node->readonlyToken = loc(1); - sym(1).Node = node; - } break; -./ - UiObjectMember: GeneratorDeclaration; /. case $rule_number: { @@ -1406,12 +1527,28 @@ UiObjectMember: T_ENUM T_IDENTIFIER T_LBRACE EnumMemberList T_RBRACE; case $rule_number: { AST::UiEnumDeclaration *enumDeclaration = new (pool) AST::UiEnumDeclaration(stringRef(2), sym(4).UiEnumMemberList->finish()); enumDeclaration->enumToken = loc(1); + enumDeclaration->identifierToken = loc(2); + enumDeclaration->lbraceToken = loc(3); enumDeclaration->rbraceToken = loc(5); sym(1).Node = enumDeclaration; break; } ./ +UiObjectMember: T_COMPONENT T_IDENTIFIER T_COLON UiObjectDefinition; +/. + case $rule_number: { + if (!stringRef(2).front().isUpper()) { + diagnostic_messages.append(compileError(loc(2), + QLatin1String("Type name must be upper case"), QtWarningMsg)); + } + auto inlineComponent = new (pool) AST::UiInlineComponent(stringRef(2), sym(4).UiObjectDefinition); + inlineComponent->componentToken = loc(1); + inlineComponent->identifierToken = loc(2); + sym(1).Node = inlineComponent; + } break; +./ + EnumMemberList: T_IDENTIFIER; /. case $rule_number: { @@ -1433,6 +1570,18 @@ EnumMemberList: T_IDENTIFIER T_EQ T_NUMERIC_LITERAL; } ./ + +EnumMemberList: T_IDENTIFIER T_EQ T_MINUS T_NUMERIC_LITERAL; +/. + case $rule_number: { + AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1), -sym(4).dval); + node->memberToken = loc(1); + node->valueToken = combine(loc(3), loc(4)); + sym(1).Node = node; + break; + } +./ + EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER; /. case $rule_number: { @@ -1454,29 +1603,43 @@ EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_NUMERIC_LITERAL; } ./ -QmlIdentifier: T_IDENTIFIER; -QmlIdentifier: T_PROPERTY; -QmlIdentifier: T_SIGNAL; -QmlIdentifier: T_READONLY; -QmlIdentifier: T_ON; -QmlIdentifier: T_GET; -QmlIdentifier: T_SET; -QmlIdentifier: T_FROM; -QmlIdentifier: T_OF; -QmlIdentifier: T_REQUIRED; - -JsIdentifier: T_IDENTIFIER; -JsIdentifier: T_PROPERTY; -JsIdentifier: T_SIGNAL; -JsIdentifier: T_READONLY; -JsIdentifier: T_ON; -JsIdentifier: T_GET; -JsIdentifier: T_SET; -JsIdentifier: T_FROM; -JsIdentifier: T_STATIC; -JsIdentifier: T_OF; -JsIdentifier: T_AS; -JsIdentifier: T_REQUIRED; + +EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_MINUS T_NUMERIC_LITERAL; +/. + case $rule_number: { + AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3), -sym(6).dval); + node->memberToken = loc(3); + node->valueToken = combine(loc(5), loc(6)); + sym(1).Node = node; + break; + } +./ + +QmlIdentifier: T_IDENTIFIER + | T_PROPERTY + | T_SIGNAL + | T_READONLY + | T_ON + | T_GET + | T_SET + | T_FROM + | T_OF + | T_REQUIRED + | T_COMPONENT; + +JsIdentifier: T_IDENTIFIER + | T_PROPERTY + | T_SIGNAL + | T_READONLY + | T_ON + | T_GET + | T_SET + | T_FROM + | T_STATIC + | T_OF + | T_AS + | T_REQUIRED + | T_COMPONENT; IdentifierReference: JsIdentifier; BindingIdentifier: IdentifierReference; @@ -1485,28 +1648,35 @@ BindingIdentifier: IdentifierReference; -- Types -------------------------------------------------------------------------------------------------------- -TypeArguments: Type; +Type: UiQualifiedId T_LT SimpleType T_GT; /. case $rule_number: { - sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).Type); + sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).Type); } break; ./ -TypeArguments: TypeArguments T_COMMA Type; +Type: SimpleType; + +SimpleType: T_RESERVED_WORD; /. case $rule_number: { - sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).TypeArgumentList, sym(3).Type); + AST::UiQualifiedId *id = new (pool) AST::UiQualifiedId(stringRef(1)); + id->identifierToken = loc(1); + sym(1).Type = new (pool) AST::Type(id->finish()); } break; ./ -Type: UiQualifiedId T_LT TypeArguments T_GT; +SimpleType: UiQualifiedId; /. case $rule_number: { - sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).TypeArgumentList->finish()); + sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId); } break; ./ -Type: T_RESERVED_WORD; +SimpleType: T_VAR; +/. case $rule_number: Q_FALLTHROUGH(); ./ + +SimpleType: T_VOID; /. case $rule_number: { AST::UiQualifiedId *id = new (pool) AST::UiQualifiedId(stringRef(1)); @@ -1515,13 +1685,6 @@ Type: T_RESERVED_WORD; } break; ./ -Type: UiQualifiedId; -/. - case $rule_number: { - sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId); - } break; -./ - TypeAnnotation: T_COLON Type; /. case $rule_number: { @@ -1893,7 +2056,6 @@ PropertyDefinition: IdentifierReference; AST::IdentifierExpression *expr = new (pool) AST::IdentifierExpression(stringRef(1)); expr->identifierToken = loc(1); AST::PatternProperty *node = new (pool) AST::PatternProperty(name, expr); - node->colonToken = loc(2); sym(1).Node = node; } break; ./ @@ -1914,8 +2076,8 @@ CoverInitializedName: IdentifierReference Initializer_In; if (auto *c = asAnonymousClassDefinition(sym(2).Expression)) c->name = stringRef(1); AST::BinaryExpression *assignment = new (pool) AST::BinaryExpression(left, QSOperator::Assign, sym(2).Expression); + assignment->operatorToken = loc(2); AST::PatternProperty *node = new (pool) AST::PatternProperty(name, assignment); - node->colonToken = loc(1); sym(1).Node = node; } break; @@ -2028,7 +2190,9 @@ Initializer: T_EQ AssignmentExpression; Initializer_In: T_EQ AssignmentExpression_In; /. case $rule_number: { - sym(1) = sym(2); + auto node = new (pool) AST::InitializerExpression(sym(2).Expression); + node->equalToken = loc(1); + sym(1).Expression = node; } break; ./ @@ -2046,7 +2210,14 @@ InitializerOpt: Initializer; InitializerOpt_In: Initializer_In; TemplateLiteral: T_NO_SUBSTITUTION_TEMPLATE; -/. case $rule_number: Q_FALLTHROUGH(); ./ +/. + case $rule_number: { + AST::TemplateLiteral *node = new (pool) AST::TemplateLiteral(stringRef(1), rawStringRef(1), nullptr); + node->literalToken = loc(1); + node->hasNoSubstitution = true; + sym(1).Node = node; + } break; +./ TemplateSpans: T_TEMPLATE_TAIL; /. @@ -2094,7 +2265,16 @@ MemberExpression: MemberExpression T_LBRACKET Expression_In T_RBRACKET; sym(1).Node = node; } break; ./ - +MemberExpression: MemberExpression T_QUESTION_DOT T_LBRACKET Expression_In T_RBRACKET; +/. + case $rule_number: { + AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(4).Expression); + node->lbracketToken = loc(3); + node->rbracketToken = loc(5); + node->isOptional = true; + sym(1).Node = node; + } break; +./ -- the identifier has to be "target", catched at codegen time NewTarget: T_NEW T_DOT T_IDENTIFIER; @@ -2117,6 +2297,17 @@ MemberExpression: MemberExpression T_DOT IdentifierName; } break; ./ +MemberExpression: MemberExpression T_QUESTION_DOT IdentifierName; +/. + case $rule_number: { + AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); + node->dotToken = loc(2); + node->identifierToken = loc(3); + node->isOptional = true; + sym(1).Node = node; + } break; +./ + MemberExpression: MetaProperty; MemberExpression: T_NEW MemberExpression T_LPAREN Arguments T_RPAREN; @@ -2165,6 +2356,17 @@ CallExpression: MemberExpression T_LPAREN Arguments T_RPAREN; } break; ./ +CallExpression: MemberExpression T_QUESTION_DOT T_LPAREN Arguments T_RPAREN; +/. + case $rule_number: { + AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(4).ArgumentList); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->isOptional = true; + sym(1).Node = node; + } break; +./ + CallExpression: Super T_LPAREN Arguments T_RPAREN; /. case $rule_number: Q_FALLTHROUGH(); ./ CallExpression: CallExpression T_LPAREN Arguments T_RPAREN; @@ -2177,6 +2379,18 @@ CallExpression: CallExpression T_LPAREN Arguments T_RPAREN; } break; ./ +CallExpression: CallExpression T_QUESTION_DOT T_LPAREN Arguments T_RPAREN; +/. + case $rule_number: { + AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(4).ArgumentList); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->isOptional = true; + sym(1).Node = node; + } break; +./ + + CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET; /. case $rule_number: { @@ -2187,6 +2401,17 @@ CallExpression: CallExpression T_LBRACKET Expression_In T_RBRACKET; } break; ./ +CallExpression: CallExpression T_QUESTION_DOT T_LBRACKET Expression_In T_RBRACKET; +/. + case $rule_number: { + AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(4).Expression); + node->lbracketToken = loc(3); + node->rbracketToken = loc(5); + node->isOptional = true; + sym(1).Node = node; + } break; +./ + CallExpression: CallExpression T_DOT IdentifierName; /. case $rule_number: { @@ -2197,6 +2422,17 @@ CallExpression: CallExpression T_DOT IdentifierName; } break; ./ +CallExpression: CallExpression T_QUESTION_DOT IdentifierName; +/. + case $rule_number: { + AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); + node->dotToken = loc(2); + node->identifierToken = loc(3); + node->isOptional = true; + sym(1).Node = node; + } break; +./ + Arguments: ; /. case $rule_number: { @@ -2490,6 +2726,12 @@ RelationalOperator: T_INSTANCEOF; sym(1).ival = QSOperator::InstanceOf; } break; ./ +RelationalOperator: T_AS; +/. + case $rule_number: { + sym(1).ival = QSOperator::As; + } break; +./ RelationalExpression_In: RelationalExpression_In T_IN ShiftExpression; /. @@ -2611,13 +2853,48 @@ LogicalORExpression_In: LogicalORExpression_In T_OR_OR LogicalANDExpression_In; } break; ./ +CoalesceExpression: LogicalORExpression; +CoalesceExpression_In: LogicalORExpression_In; + +CoalesceExpression: CoalesceExpression T_QUESTION_QUESTION LogicalORExpression; +/. case $rule_number: Q_FALLTHROUGH(); ./ +CoalesceExpression_In: CoalesceExpression_In T_QUESTION_QUESTION LogicalORExpression_In; +/. + case $rule_number: { + + auto *lhs = sym(1).Expression; + auto *rhs = sym(3).Expression; -ConditionalExpression: LogicalORExpression; -ConditionalExpression_In: LogicalORExpression_In; + // Check if lhs or rhs contain || or && -ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression; + if (lhs->binaryExpressionCast() != nullptr) { + auto *binaryExpr = lhs->binaryExpressionCast(); + if (binaryExpr->op == QSOperator::And || binaryExpr->op == QSOperator::Or) { + syntaxError(binaryExpr->operatorToken, "Left-hand side may not contain || or &&"); + return false; + } + } + + if (rhs->binaryExpressionCast() != nullptr) { + auto *binaryExpr = rhs->binaryExpressionCast(); + if (binaryExpr->op == QSOperator::And || binaryExpr->op == QSOperator::Or) { + syntaxError(binaryExpr->operatorToken, "Right-hand side may not contain || or &&"); + return false; + } + } + + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(lhs, QSOperator::Coalesce, rhs); + node->operatorToken = loc(2); + sym(1).Node = node; + } break; +./ + +ConditionalExpression: CoalesceExpression; +ConditionalExpression_In: CoalesceExpression_In; + +ConditionalExpression: CoalesceExpression T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression; /. case $rule_number: Q_FALLTHROUGH(); ./ -ConditionalExpression_In: LogicalORExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In; +ConditionalExpression_In: CoalesceExpression_In T_QUESTION AssignmentExpression_In T_COLON AssignmentExpression_In; /. case $rule_number: { AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); @@ -2641,9 +2918,12 @@ AssignmentExpression: LeftHandSideExpression T_EQ AssignmentExpression; AssignmentExpression_In: LeftHandSideExpression T_EQ AssignmentExpression_In; /. case $rule_number: { + if (sym(1).Expression->containsOptionalChain()) { + syntaxError(loc(1), QStringLiteral("Optional chains are not permitted on the left-hand-side in assignments")); + } // need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral if (AST::Pattern *p = sym(1).Expression->patternCast()) { - AST::SourceLocation errorLoc; + SourceLocation errorLoc; QString errorMsg; if (!p->convertLiteralToAssignmentPattern(pool, &errorLoc, &errorMsg)) { syntaxError(errorLoc, errorMsg); @@ -2671,6 +2951,9 @@ AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpres AssignmentExpression_In: LeftHandSideExpression AssignmentOperator AssignmentExpression_In; /. case $rule_number: { + if (sym(1).Expression->containsOptionalChain()) { + syntaxError(loc(1), QStringLiteral("Optional chains are not permitted on the left-hand-side in assignments")); + } AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; @@ -3099,14 +3382,15 @@ BindingElisionElement: ElisionOpt BindingElement; BindingProperty: BindingIdentifier InitializerOpt_In; /. case $rule_number: { - AST::StringLiteralPropertyName *name = new (pool) AST::StringLiteralPropertyName(stringRef(1)); + AST::IdentifierPropertyName *name = new (pool) AST::IdentifierPropertyName(stringRef(1)); name->propertyNameToken = loc(1); // if initializer is an anonymous function expression, we need to assign identifierref as it's name if (auto *f = asAnonymousFunctionDefinition(sym(2).Expression)) f->name = stringRef(1); if (auto *c = asAnonymousClassDefinition(sym(2).Expression)) c->name = stringRef(1); - sym(1).Node = new (pool) AST::PatternProperty(name, stringRef(1), sym(2).Expression); + AST::PatternProperty *node = new (pool) AST::PatternProperty(name, stringRef(1), sym(2).Expression); + sym(1).Node = node; } break; ./ @@ -3114,6 +3398,8 @@ BindingProperty: PropertyName T_COLON BindingIdentifier InitializerOpt_In; /. case $rule_number: { AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, stringRef(3), sym(4).Expression); + node->colonToken = loc(2); + node->identifierToken = loc(3); sym(1).Node = node; } break; ./ @@ -3122,6 +3408,7 @@ BindingProperty: PropertyName T_COLON BindingPattern InitializerOpt_In; /. case $rule_number: { AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Pattern, sym(4).Expression); + node->colonToken = loc(2); sym(1).Node = node; } break; ./ @@ -3281,6 +3568,11 @@ IterationStatement: T_FOR T_LPAREN LexicalDeclaration T_SEMICOLON ExpressionOpt_ AST::ForStatement *node = new (pool) AST::ForStatement( static_cast<AST::VariableStatement *>(sym(3).Node)->declarations, sym(5).Expression, sym(7).Expression, sym(9).Statement); + if (node->declarations) { + AST::PatternElement *pe = node->declarations->declaration; + pe->isForDeclaration = true; + pe->declarationKindToken = loc(3); + } node->forToken = loc(1); node->lparenToken = loc(2); node->firstSemicolonToken = loc(4); @@ -3309,7 +3601,7 @@ IterationStatement: T_FOR T_LPAREN LeftHandSideExpression InOrOf Expression_In T case $rule_number: { // need to convert the LHS to an AssignmentPattern if it was an Array/ObjectLiteral if (AST::Pattern *p = sym(3).Expression->patternCast()) { - AST::SourceLocation errorLoc; + SourceLocation errorLoc; QString errorMsg; if (!p->convertLiteralToAssignmentPattern(pool, &errorLoc, &errorMsg)) { syntaxError(errorLoc, errorMsg); @@ -3352,6 +3644,7 @@ ForDeclaration: Var BindingIdentifier TypeAnnotationOpt; node->identifierToken = loc(2); node->scope = sym(1).scope; node->isForDeclaration = true; + node->declarationKindToken = loc(1); sym(1).Node = node; } break; ./ @@ -3364,6 +3657,7 @@ ForDeclaration: Var BindingPattern; auto *node = new (pool) AST::PatternElement(sym(2).Pattern, nullptr); node->scope = sym(1).scope; node->isForDeclaration = true; + node->declarationKindToken = loc(1); sym(1).Node = node; } break; ./ @@ -3392,7 +3686,7 @@ ContinueStatement: T_CONTINUE IdentifierReference Semicolon; BreakStatement: T_BREAK Semicolon; /. case $rule_number: { - AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef()); + AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringView()); node->breakToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; @@ -3666,7 +3960,7 @@ FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN TypeAnn case $rule_number: { if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList)) return false; - AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList, + AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringView(), sym(3).FormalParameterList, sym(7).StatementList, /*type annotation*/nullptr); node->functionToken = loc(1); node->lparenToken = loc(2); @@ -3700,7 +3994,7 @@ FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN TypeAnnotation case $rule_number: { if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList)) return false; - AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList, + AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringView(), sym(3).FormalParameterList, sym(7).StatementList, /*type annotation*/nullptr); node->functionToken = loc(1); node->lparenToken = loc(2); @@ -3787,14 +4081,14 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpress /. 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(); + ret->returnToken = sym(4).Node->firstSourceLocation().startZeroLengthLocation(); + ret->semicolonToken = sym(4).Node->lastSourceLocation().endZeroLengthLocation(driver->code()); AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish(); - AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringRef(), sym(1).FormalParameterList, statements); + AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), 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(); + f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().startZeroLengthLocation() : loc(1).startZeroLengthLocation(); + f->lbraceToken = sym(4).Node->firstSourceLocation().startZeroLengthLocation(); + f->rbraceToken = sym(4).Node->lastSourceLocation().endZeroLengthLocation(driver->code()); sym(1).Node = f; } break; ./ @@ -3804,10 +4098,10 @@ ArrowFunction: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK Functi 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); + AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), 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->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation().startZeroLengthLocation() : loc(1).startZeroLengthLocation(); + f->lbraceToken = loc(5); f->rbraceToken = loc(7); sym(1).Node = f; } break; @@ -3880,7 +4174,6 @@ MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_R f->rbraceToken = loc(9); f->isGenerator = true; AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Method); - node->colonToken = loc(2); sym(1).Node = node; } break; ./ @@ -3898,7 +4191,6 @@ MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN TypeAnnotationOpt Functio f->lbraceToken = loc(6); f->rbraceToken = loc(8); AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Getter); - node->colonToken = loc(2); sym(1).Node = node; } break; ./ @@ -3915,7 +4207,6 @@ MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN f->lbraceToken = loc(7); f->rbraceToken = loc(9); AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(2).PropertyName, f, AST::PatternProperty::Setter); - node->colonToken = loc(2); sym(1).Node = node; } break; ./ @@ -3965,7 +4256,7 @@ GeneratorDeclaration_Default: GeneratorDeclaration; GeneratorDeclaration_Default: FunctionStar GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace; /. case $rule_number: { - AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList); + AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringView(), sym(3).FormalParameterList, sym(6).StatementList); node->functionToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); @@ -3995,7 +4286,7 @@ GeneratorExpression: T_FUNCTION_STAR BindingIdentifier GeneratorLParen FormalPar GeneratorExpression: T_FUNCTION_STAR GeneratorLParen FormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace; /. case $rule_number: { - AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList); + AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringView(), sym(3).FormalParameterList, sym(6).StatementList); node->functionToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); @@ -4070,7 +4361,7 @@ ClassExpression: T_CLASS BindingIdentifier ClassHeritageOpt ClassLBrace ClassBod ClassDeclaration_Default: T_CLASS ClassHeritageOpt ClassLBrace ClassBodyOpt ClassRBrace; /. case $rule_number: { - AST::ClassDeclaration *node = new (pool) AST::ClassDeclaration(QStringRef(), sym(2).Expression, sym(4).ClassElementList); + AST::ClassDeclaration *node = new (pool) AST::ClassDeclaration(QStringView(), sym(2).Expression, sym(4).ClassElementList); node->classToken = loc(1); node->lbraceToken = loc(3); node->rbraceToken = loc(5); @@ -4081,7 +4372,7 @@ ClassDeclaration_Default: T_CLASS ClassHeritageOpt ClassLBrace ClassBodyOpt Clas ClassExpression: T_CLASS ClassHeritageOpt ClassLBrace ClassBodyOpt ClassRBrace; /. case $rule_number: { - AST::ClassExpression *node = new (pool) AST::ClassExpression(QStringRef(), sym(2).Expression, sym(4).ClassElementList); + AST::ClassExpression *node = new (pool) AST::ClassExpression(QStringView(), sym(2).Expression, sym(4).ClassElementList); node->classToken = loc(1); node->lbraceToken = loc(3); node->rbraceToken = loc(5); @@ -4094,16 +4385,16 @@ ClassDeclaration_Default: ClassDeclaration; ClassLBrace: T_LBRACE; /. case $rule_number: { - lexer->setStaticIsKeyword(true); + if (++classNestingLevel == 1) + lexer->setStaticIsKeyword(true); } break; ./ ClassRBrace: T_RBRACE; -/. case $rule_number: ./ -ClassStaticQualifier: T_STATIC; /. case $rule_number: { - lexer->setStaticIsKeyword(false); + if (--classNestingLevel == 0) + lexer->setStaticIsKeyword(false); } break; ./ @@ -4158,10 +4449,9 @@ ClassElement: MethodDefinition; } break; ./ -ClassElement: ClassStaticQualifier MethodDefinition; +ClassElement: T_STATIC MethodDefinition; /. case $rule_number: { - lexer->setStaticIsKeyword(true); AST::ClassElementList *node = new (pool) AST::ClassElementList(sym(2).PatternProperty, true); sym(1).Node = node; } break; @@ -4356,7 +4646,10 @@ ImportsList: ImportsList T_COMMA ImportSpecifier; } break; ./ -ImportSpecifier: ImportedBinding; +-- When enconutering an IdentifierReference it can resolve to both ImportedBinding and IdentifierName +-- Using %right and %prec, we tell qlalr that it should not reduce immediately, but rather shift +-- so that we have a chance of actually parsing the correct rule if there is an "as" identifier +ImportSpecifier: ImportedBinding %prec T_WITHOUTAS; /. case $rule_number: { auto importSpecifier = new (pool) AST::ImportSpecifier(stringRef(1)); @@ -4543,35 +4836,26 @@ ExportSpecifier: IdentifierName T_AS IdentifierName; if (first_token == last_token) { const int errorState = state_stack[tos]; + // automatic insertion of missing identifiers after dots + if (yytoken != -1 && m_identifierInsertionEnabled && t_action(errorState, T_IDENTIFIER) && yyprevtoken == T_DOT) { +#ifdef PARSER_DEBUG + qDebug() << "Inserting missing identifier between" << spell[yyprevtoken] << "and" + << spell[yytoken]; +#endif + pushTokenWithEmptyLocation(T_IDENTIFIER); + action = errorState; + goto _Lcheck_token; + } + + // automatic insertion of `;' if (yytoken != -1 && ((t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) || t_action(errorState, T_COMPATIBILITY_SEMICOLON))) { #ifdef PARSER_DEBUG qDebug() << "Inserting automatic semicolon."; #endif - SavedToken &tk = token_buffer[0]; - tk.token = yytoken; - tk.dval = yylval; - tk.spell = yytokenspell; - tk.raw = yytokenraw; - tk.loc = yylloc; - - yylloc = yyprevlloc; - yylloc.offset += yylloc.length; - yylloc.startColumn += yylloc.length; - yylloc.length = 0; - - //const QString msg = QCoreApplication::translate("QQmlParser", "Missing `;'"); - //diagnostic_messages.append(compileError(yyloc, msg, QtWarningMsg)); - - first_token = &token_buffer[0]; - last_token = &token_buffer[1]; - - yytoken = T_SEMICOLON; - yylval = 0; - + pushTokenWithEmptyLocation(T_SEMICOLON); action = errorState; - goto _Lcheck_token; } |