diff options
Diffstat (limited to 'src/qml/parser')
-rw-r--r-- | src/qml/parser/parser.pri | 2 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 245 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast.cpp | 82 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 232 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastfwd_p.h | 3 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastvisitor_p.h | 9 | ||||
-rw-r--r-- | src/qml/parser/qqmljsengine_p.h | 3 | ||||
-rw-r--r-- | src/qml/parser/qqmljslexer.cpp | 2 | ||||
-rw-r--r-- | src/qml/parser/qqmljsmemorypool_p.h | 256 |
9 files changed, 458 insertions, 376 deletions
diff --git a/src/qml/parser/parser.pri b/src/qml/parser/parser.pri index 2c0175c94b..e15730f5d1 100644 --- a/src/qml/parser/parser.pri +++ b/src/qml/parser/parser.pri @@ -4,11 +4,9 @@ HEADERS += \ $$PWD/qqmljsastvisitor_p.h \ $$PWD/qqmljsengine_p.h \ $$PWD/qqmljslexer_p.h \ - $$PWD/qqmljsmemorypool_p.h \ $$PWD/qqmljsglobal_p.h \ $$PWD/qqmljskeywords_p.h \ $$PWD/qqmljsengine_p.h \ - $$PWD/qqmljsglobal_p.h \ $$PWD/qqmljssourcelocation_p.h SOURCES += \ diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index daaa402ef1..bdc4a0bb46 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -299,6 +299,9 @@ public: AST::ExportsList *ExportsList; AST::ExportClause *ExportClause; AST::ExportDeclaration *ExportDeclaration; + AST::TypeAnnotation *TypeAnnotation; + AST::TypeArgumentList *TypeArgumentList; + AST::Type *Type; AST::UiProgram *UiProgram; AST::UiHeaderItemList *UiHeaderItemList; @@ -424,6 +427,8 @@ protected: diagnostic_messages.append(compileError(location, message)); } + bool ensureNoFunctionTypeAnnotations(AST::TypeAnnotation *returnTypeAnnotation, AST::FormalParameterList *formals); + protected: Engine *driver; MemoryPool *pool; @@ -594,6 +599,21 @@ int Parser::lookaheadToken(Lexer *lexer) return yytoken; } +bool Parser::ensureNoFunctionTypeAnnotations(AST::TypeAnnotation *returnValueAnnotation, AST::FormalParameterList *formals) +{ + for (auto formal = formals; formal; formal = formal->next) { + if (formal->element && formal->element->typeAnnotation) { + syntaxError(formal->element->typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in function parameters in JavaScript functions"); + return false; + } + } + if (returnValueAnnotation) { + syntaxError(returnValueAnnotation->firstSourceLocation(), "Type annotations are not permitted for the return value of JavaScript functions"); + return false; + } + return true; +} + //#define PARSER_DEBUG bool Parser::parse(int startToken) @@ -1086,6 +1106,17 @@ UiParameterListOpt: UiParameterList; } break; ./ +UiParameterList: QmlIdentifier T_COLON UiPropertyType; +/. + case $rule_number: { + AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(3).UiQualifiedId->finish(), stringRef(1)); + node->identifierToken = loc(1); + node->colonToken = loc(2); + node->propertyTypeToken = loc(3); + sym(1).Node = node; + } break; +./ + UiParameterList: UiPropertyType QmlIdentifier; /. case $rule_number: { @@ -1096,6 +1127,18 @@ UiParameterList: UiPropertyType QmlIdentifier; } break; ./ +UiParameterList: UiParameterList T_COMMA QmlIdentifier T_COLON UiPropertyType; +/. + case $rule_number: { + AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, sym(5).UiQualifiedId->finish(), stringRef(3)); + node->propertyTypeToken = loc(5); + node->commaToken = loc(2); + node->identifierToken = loc(3); + node->colonToken = loc(4); + sym(1).Node = node; + } break; +./ + UiParameterList: UiParameterList T_COMMA UiPropertyType QmlIdentifier; /. case $rule_number: { @@ -1355,7 +1398,7 @@ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON Expre } break; ./ -UiObjectMember: FunctionDeclaration; +UiObjectMember: FunctionDeclarationWithTypes; /. case $rule_number: { sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); @@ -1471,6 +1514,63 @@ IdentifierReference: JsIdentifier; BindingIdentifier: IdentifierReference; -------------------------------------------------------------------------------------------------------- +-- Types +-------------------------------------------------------------------------------------------------------- + +TypeArguments: Type; +/. + case $rule_number: { + sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).Type); + } break; +./ + +TypeArguments: TypeArguments T_COMMA Type; +/. + case $rule_number: { + sym(1).TypeArgumentList = new (pool) AST::TypeArgumentList(sym(1).TypeArgumentList, sym(3).Type); + } break; +./ + +Type: UiQualifiedId T_LT TypeArguments T_GT; +/. + case $rule_number: { + sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId, sym(3).TypeArgumentList->finish()); + } break; +./ + +Type: T_RESERVED_WORD; +/. + case $rule_number: { + 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; +/. + case $rule_number: { + sym(1).Type = new (pool) AST::Type(sym(1).UiQualifiedId); + } break; +./ + +TypeAnnotation: T_COLON Type; +/. + case $rule_number: { + sym(1).TypeAnnotation = new (pool) AST::TypeAnnotation(sym(2).Type); + sym(1).TypeAnnotation->colonToken = loc(1); + } break; +./ + +TypeAnnotationOpt: TypeAnnotation; +TypeAnnotationOpt: ; +/. + case $rule_number: { + sym(1).TypeAnnotation = nullptr; + } break; +./ + +-------------------------------------------------------------------------------------------------------- -- Expressions -------------------------------------------------------------------------------------------------------- @@ -2851,7 +2951,14 @@ VarDeclaration: Var VariableDeclarationList; VarDeclaration_In: Var VariableDeclarationList_In; /. case $rule_number: { - AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(sym(1).scope)); + AST::VariableDeclarationList *declarations = sym(2).VariableDeclarationList->finish(sym(1).scope); + for (auto it = declarations; it; it = it->next) { + if (it->declaration && it->declaration->typeAnnotation) { + syntaxError(it->declaration->typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in variable declarations"); + return false; + } + } + AST::VariableStatement *node = new (pool) AST::VariableStatement(declarations); node->declarationKindToken = loc(1); sym(1).Node = node; } break; @@ -2888,22 +2995,22 @@ VariableDeclarationList_In: VariableDeclarationList_In T_COMMA VariableDeclarati } break; ./ -LexicalBinding: BindingIdentifier InitializerOpt; +LexicalBinding: BindingIdentifier TypeAnnotationOpt InitializerOpt; /. case $rule_number: Q_FALLTHROUGH(); ./ -LexicalBinding_In: BindingIdentifier InitializerOpt_In; +LexicalBinding_In: BindingIdentifier TypeAnnotationOpt InitializerOpt_In; /. case $rule_number: Q_FALLTHROUGH(); ./ -VariableDeclaration: BindingIdentifier InitializerOpt; +VariableDeclaration: BindingIdentifier TypeAnnotationOpt InitializerOpt; /. case $rule_number: Q_FALLTHROUGH(); ./ -VariableDeclaration_In: BindingIdentifier InitializerOpt_In; +VariableDeclaration_In: BindingIdentifier TypeAnnotationOpt InitializerOpt_In; /. case $rule_number: { - auto *node = new (pool) AST::PatternElement(stringRef(1), sym(2).Expression); + auto *node = new (pool) AST::PatternElement(stringRef(1), sym(2).TypeAnnotation, sym(3).Expression); node->identifierToken = loc(1); sym(1).Node = node; // if initializer is an anonymous function expression, we need to assign identifierref as it's name - if (auto *f = asAnonymousFunctionDefinition(sym(2).Expression)) + if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) f->name = stringRef(1); - if (auto *c = asAnonymousClassDefinition(sym(2).Expression)) + if (auto *c = asAnonymousClassDefinition(sym(3).Expression)) c->name = stringRef(1); } break; ./ @@ -3053,15 +3160,15 @@ BindingProperty: PropertyName T_COLON BindingPattern InitializerOpt_In; } break; ./ -BindingElement: BindingIdentifier InitializerOpt_In; +BindingElement: BindingIdentifier TypeAnnotationOpt InitializerOpt_In; /. case $rule_number: { - AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1), sym(2).Expression); + AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(1), sym(2).TypeAnnotation, sym(3).Expression); node->identifierToken = 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)) + if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) f->name = stringRef(1); - if (auto *c = asAnonymousClassDefinition(sym(2).Expression)) + if (auto *c = asAnonymousClassDefinition(sym(3).Expression)) c->name = stringRef(1); sym(1).Node = node; } break; @@ -3078,7 +3185,7 @@ BindingElement: BindingPattern InitializerOpt_In; BindingRestElement: T_ELLIPSIS BindingIdentifier; /. case $rule_number: { - AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(2), nullptr, AST::PatternElement::RestElement); + AST::PatternElement *node = new (pool) AST::PatternElement(stringRef(2), /*type annotation*/nullptr, nullptr, AST::PatternElement::RestElement); node->identifierToken = loc(2); sym(1).Node = node; } break; @@ -3268,12 +3375,16 @@ IterationStatement: T_FOR T_LPAREN ForDeclaration InOrOf Expression_In T_RPAREN } break; ./ -ForDeclaration: LetOrConst BindingIdentifier; +ForDeclaration: LetOrConst BindingIdentifier TypeAnnotationOpt; /. case $rule_number: Q_FALLTHROUGH(); ./ -ForDeclaration: Var BindingIdentifier; +ForDeclaration: Var BindingIdentifier TypeAnnotationOpt; /. case $rule_number: { - auto *node = new (pool) AST::PatternElement(stringRef(2), nullptr); + if (auto typeAnnotation = sym(3).TypeAnnotation) { + syntaxError(typeAnnotation->firstSourceLocation(), "Type annotations are not permitted in variable declarations"); + return false; + } + auto *node = new (pool) AST::PatternElement(stringRef(2), sym(3).TypeAnnotation, nullptr); node->identifierToken = loc(2); node->scope = sym(1).scope; node->isForDeclaration = true; @@ -3560,59 +3671,85 @@ DebuggerStatement: T_DEBUGGER T_SEMICOLON; -- otherwise conflict. Function: T_FUNCTION %prec REDUCE_HERE; -FunctionDeclaration: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace; +FunctionDeclaration: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace; /. case $rule_number: { - AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList); + if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList)) + return false; + AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList, + /*type annotation*/nullptr); node->functionToken = loc(1); node->identifierToken = loc(2); node->lparenToken = loc(3); node->rparenToken = loc(5); - node->lbraceToken = loc(6); - node->rbraceToken = loc(8); + node->lbraceToken = loc(7); + node->rbraceToken = loc(9); sym(1).Node = node; } break; ./ +FunctionDeclarationWithTypes: Function BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace; +/. + case $rule_number: { + AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList, + sym(6).TypeAnnotation); + node->functionToken = loc(1); + node->identifierToken = loc(2); + node->lparenToken = loc(3); + node->rparenToken = loc(5); + node->lbraceToken = loc(7); + node->rbraceToken = loc(9); + sym(1).Node = node; + } break; +./ FunctionDeclaration_Default: FunctionDeclaration; -FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace; +FunctionDeclaration_Default: Function T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace; /. case $rule_number: { - AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList); + if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList)) + return false; + AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList, + /*type annotation*/nullptr); node->functionToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); - node->lbraceToken = loc(5); - node->rbraceToken = loc(7); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); sym(1).Node = node; } break; ./ -FunctionExpression: T_FUNCTION BindingIdentifier T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace; +FunctionExpression: T_FUNCTION BindingIdentifier T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace; /. case $rule_number: { - AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList); + if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList)) + return false; + AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList, + /*type annotation*/nullptr); node->functionToken = loc(1); if (! stringRef(2).isNull()) node->identifierToken = loc(2); node->lparenToken = loc(3); node->rparenToken = loc(5); - node->lbraceToken = loc(6); - node->rbraceToken = loc(8); + node->lbraceToken = loc(7); + node->rbraceToken = loc(9); sym(1).Node = node; } break; ./ -FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace; +FunctionExpression: T_FUNCTION T_LPAREN FormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace; /. case $rule_number: { - AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).StatementList); + if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList)) + return false; + AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(7).StatementList, + /*type annotation*/nullptr); node->functionToken = loc(1); node->lparenToken = loc(2); node->rparenToken = loc(4); - node->lbraceToken = loc(5); - node->rbraceToken = loc(7); + node->lbraceToken = loc(6); + node->rbraceToken = loc(8); sym(1).Node = node; } break; ./ @@ -3722,7 +3859,7 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK Fun ArrowParameters: BindingIdentifier; /. case $rule_number: { - AST::PatternElement *e = new (pool) AST::PatternElement(stringRef(1), nullptr, AST::PatternElement::Binding); + AST::PatternElement *e = new (pool) AST::PatternElement(stringRef(1), /*type annotation*/nullptr, nullptr, AST::PatternElement::Binding); e->identifierToken = loc(1); sym(1).FormalParameterList = (new (pool) AST::FormalParameterList(nullptr, e))->finish(pool); } break; @@ -3756,30 +3893,34 @@ ConciseBodyLookahead: ; } break; ./ -MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN FunctionLBrace FunctionBody FunctionRBrace; +MethodDefinition: PropertyName T_LPAREN StrictFormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace; /. case $rule_number: { - AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(1), sym(3).FormalParameterList, sym(6).StatementList); + if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, sym(3).FormalParameterList)) + return false; + AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(1), sym(3).FormalParameterList, sym(7).StatementList); f->functionToken = sym(1).PropertyName->firstSourceLocation(); f->lparenToken = loc(2); f->rparenToken = loc(4); - f->lbraceToken = loc(5); - f->rbraceToken = loc(7); + f->lbraceToken = loc(6); + f->rbraceToken = loc(8); AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, f, AST::PatternProperty::Method); node->colonToken = loc(2); sym(1).Node = node; } break; ./ -MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_RPAREN FunctionLBrace GeneratorBody GeneratorRBrace; +MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_RPAREN TypeAnnotationOpt FunctionLBrace GeneratorBody GeneratorRBrace; /. case $rule_number: { - AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList); + if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList)) + return false; + AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList); f->functionToken = sym(2).PropertyName->firstSourceLocation(); f->lparenToken = loc(3); f->rparenToken = loc(5); - f->lbraceToken = loc(6); - f->rbraceToken = loc(8); + f->lbraceToken = loc(7); + 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); @@ -3788,30 +3929,34 @@ MethodDefinition: T_STAR PropertyName GeneratorLParen StrictFormalParameters T_R ./ -MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN FunctionLBrace FunctionBody FunctionRBrace; +MethodDefinition: T_GET PropertyName T_LPAREN T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace; /. case $rule_number: { - AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), nullptr, sym(6).StatementList); + if (!ensureNoFunctionTypeAnnotations(sym(5).TypeAnnotation, /*formals*/nullptr)) + return false; + AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), nullptr, sym(7).StatementList); f->functionToken = sym(2).PropertyName->firstSourceLocation(); f->lparenToken = loc(3); f->rparenToken = loc(4); - f->lbraceToken = loc(5); - f->rbraceToken = loc(7); + 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; ./ -MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN FunctionLBrace FunctionBody FunctionRBrace; +MethodDefinition: T_SET PropertyName T_LPAREN PropertySetParameterList T_RPAREN TypeAnnotationOpt FunctionLBrace FunctionBody FunctionRBrace; /. case $rule_number: { - AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).StatementList); + if (!ensureNoFunctionTypeAnnotations(sym(6).TypeAnnotation, sym(4).FormalParameterList)) + return false; + AST::FunctionExpression *f = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(8).StatementList); f->functionToken = sym(2).PropertyName->firstSourceLocation(); f->lparenToken = loc(3); f->rparenToken = loc(5); - f->lbraceToken = loc(6); - f->rbraceToken = loc(8); + 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; diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 1bc0e6e364..700c191499 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -131,7 +131,7 @@ FormalParameterList *ExpressionNode::reparseAsFormalParameterList(MemoryPool *po } AST::PatternElement *binding = nullptr; if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(expr)) { - binding = new (pool) AST::PatternElement(idExpr->name, rhs); + binding = new (pool) AST::PatternElement(idExpr->name, /*type annotation*/nullptr, rhs); binding->identifierToken = idExpr->identifierToken; } else if (AST::Pattern *p = expr->patternCast()) { SourceLocation loc; @@ -961,6 +961,7 @@ void FunctionDeclaration::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(formals, visitor); + accept(typeAnnotation, visitor); accept(body, visitor); } @@ -971,6 +972,7 @@ void FunctionExpression::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(formals, visitor); + accept(typeAnnotation, visitor); accept(body, visitor); } @@ -982,9 +984,9 @@ FunctionExpression *FunctionExpression::asFunctionDefinition() return this; } -QStringList FormalParameterList::formals() const +BoundNames FormalParameterList::formals() const { - QStringList formals; + BoundNames formals; int i = 0; for (const FormalParameterList *it = this; it; it = it->next) { if (it->element) { @@ -992,18 +994,18 @@ QStringList FormalParameterList::formals() const int duplicateIndex = formals.indexOf(name); if (duplicateIndex >= 0) { // change the name of the earlier argument to enforce the lookup semantics from the spec - formals[duplicateIndex] += QLatin1String("#") + QString::number(i); + formals[duplicateIndex].id += QLatin1String("#") + QString::number(i); } - formals += name; + formals += {name, it->element->typeAnnotation}; } ++i; } return formals; } -QStringList FormalParameterList::boundNames() const +BoundNames FormalParameterList::boundNames() const { - QStringList names; + BoundNames names; for (const FormalParameterList *it = this; it; it = it->next) { if (it->element) it->element->boundNames(&names); @@ -1271,6 +1273,35 @@ void UiQualifiedId::accept0(Visitor *visitor) visitor->endVisit(this); } +void Type::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(typeId, visitor); + accept(typeArguments, visitor); + } + + visitor->endVisit(this); +} + +void TypeArgumentList::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + for (TypeArgumentList *it = this; it; it = it->next) + accept(it->typeId, visitor); + } + + visitor->endVisit(this); +} + +void TypeAnnotation::accept0(Visitor *visitor) +{ + if (visitor->visit(this)) { + accept(type, visitor); + } + + visitor->endVisit(this); +} + void UiImport::accept0(Visitor *visitor) { if (visitor->visit(this)) { @@ -1339,13 +1370,14 @@ void PatternElement::accept0(Visitor *visitor) { if (visitor->visit(this)) { accept(bindingTarget, visitor); + accept(typeAnnotation, visitor); accept(initializer, visitor); } visitor->endVisit(this); } -void PatternElement::boundNames(QStringList *names) +void PatternElement::boundNames(BoundNames *names) { if (bindingTarget) { if (PatternElementList *e = elementList()) @@ -1353,7 +1385,7 @@ void PatternElement::boundNames(QStringList *names) else if (PatternPropertyList *p = propertyList()) p->boundNames(names); } else { - names->append(bindingIdentifier.toString()); + names->append({bindingIdentifier.toString(), typeAnnotation}); } } @@ -1369,7 +1401,7 @@ void PatternElementList::accept0(Visitor *visitor) visitor->endVisit(this); } -void PatternElementList::boundNames(QStringList *names) +void PatternElementList::boundNames(BoundNames *names) { for (PatternElementList *it = this; it; it = it->next) { if (it->element) @@ -1382,13 +1414,14 @@ void PatternProperty::accept0(Visitor *visitor) if (visitor->visit(this)) { accept(name, visitor); accept(bindingTarget, visitor); + accept(typeAnnotation, visitor); accept(initializer, visitor); } visitor->endVisit(this); } -void PatternProperty::boundNames(QStringList *names) +void PatternProperty::boundNames(BoundNames *names) { PatternElement::boundNames(names); } @@ -1404,7 +1437,7 @@ void PatternPropertyList::accept0(Visitor *visitor) visitor->endVisit(this); } -void PatternPropertyList::boundNames(QStringList *names) +void PatternPropertyList::boundNames(BoundNames *names) { for (PatternPropertyList *it = this; it; it = it->next) it->property->boundNames(names); @@ -1478,6 +1511,31 @@ void UiVersionSpecifier::accept0(Visitor *visitor) } visitor->endVisit(this); } + +QString Type::toString() const +{ + QString result; + toString(&result); + return result; +} + +void Type::toString(QString *out) const +{ + for (QQmlJS::AST::UiQualifiedId *it = typeId; it; it = it->next) { + out->append(it->name); + + if (it->next) + out->append(QLatin1Char('.')); + } + + if (typeArguments) { + out->append(QLatin1Char('<')); + if (auto subType = static_cast<TypeArgumentList*>(typeArguments)->typeId) + subType->toString(out); + out->append(QLatin1Char('>')); + }; +} + } } // namespace QQmlJS::AST QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index 606137b67d..1502298d14 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -53,7 +53,8 @@ #include "qqmljsastvisitor_p.h" #include "qqmljsglobal_p.h" -#include "qqmljsmemorypool_p.h" + +#include <private/qqmljsmemorypool_p.h> #include <QtCore/qstring.h> @@ -233,6 +234,9 @@ public: Kind_PatternElementList, Kind_PatternProperty, Kind_PatternPropertyList, + Kind_Type, + Kind_TypeArgumentList, + Kind_TypeAnnotation, Kind_UiArrayBinding, Kind_UiImport, @@ -303,6 +307,131 @@ public: int kind = Kind_Undefined; }; + +class QML_PARSER_EXPORT UiQualifiedId: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiQualifiedId) + + UiQualifiedId(const QStringRef &name) + : next(this), name(name) + { kind = K; } + + UiQualifiedId(UiQualifiedId *previous, const QStringRef &name) + : name(name) + { + kind = K; + next = previous->next; + previous->next = this; + } + + UiQualifiedId *finish() + { + UiQualifiedId *head = next; + next = nullptr; + return head; + } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return identifierToken; } + + SourceLocation lastSourceLocation() const override + { return next ? next->lastSourceLocation() : identifierToken; } + +// attributes + UiQualifiedId *next; + QStringRef name; + SourceLocation identifierToken; +}; + +class QML_PARSER_EXPORT Type: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(Type) + + Type(UiQualifiedId *typeId, Node *typeArguments = nullptr) + : typeId(typeId) + , typeArguments(typeArguments) + { kind = K; } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return typeId->firstSourceLocation(); } + + SourceLocation lastSourceLocation() const override + { return typeArguments ? typeArguments->lastSourceLocation() : typeId->lastSourceLocation(); } + + QString toString() const; + void toString(QString *out) const; + +// attributes + UiQualifiedId *typeId; + Node *typeArguments; // TypeArgumentList +}; + + +class QML_PARSER_EXPORT TypeArgumentList: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(TypeArgumentList) + + TypeArgumentList(Type *typeId) + : typeId(typeId) + , next(nullptr) + { kind = K; } + + TypeArgumentList(TypeArgumentList *previous, Type *typeId) + : typeId(typeId) + { + kind = K; + next = previous->next; + previous->next = this; + } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return typeId->firstSourceLocation(); } + + SourceLocation lastSourceLocation() const override + { return next ? next->lastSourceLocation() : typeId->lastSourceLocation(); } + + inline TypeArgumentList *finish() + { + TypeArgumentList *front = next; + next = nullptr; + return front; + } + +// attributes + Type *typeId; + TypeArgumentList *next; +}; + +class QML_PARSER_EXPORT TypeAnnotation: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(TypeAnnotation) + + TypeAnnotation(Type *type) + : type(type) + { kind = K; } + + void accept0(Visitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return colonToken; } + + SourceLocation lastSourceLocation() const override + { return type->lastSourceLocation(); } + +// attributes + Type *type; + SourceLocation colonToken; +}; class QML_PARSER_EXPORT ExpressionNode: public Node { public: @@ -704,6 +833,34 @@ public: SourceLocation propertyNameToken; }; +struct QML_PARSER_EXPORT BoundName +{ + QString id; + TypeAnnotation *typeAnnotation = nullptr; + BoundName(const QString &id, TypeAnnotation *typeAnnotation) + : id(id), typeAnnotation(typeAnnotation) + {} + BoundName() = default; + QString typeName() const { return typeAnnotation ? typeAnnotation->type->toString() : QString(); } +}; + +struct BoundNames : public QVector<BoundName> +{ + int indexOf(const QString &name, int from = 0) const + { + auto found = std::find_if(constBegin() + from, constEnd(), + [name](const BoundName &it) { return it.id == name; }); + if (found == constEnd()) + return -1; + return found - constBegin(); + } + + bool contains(const QString &name) const + { + return indexOf(name) != -1; + } +}; + class QML_PARSER_EXPORT PatternElement : public Node { public: @@ -728,8 +885,9 @@ public: : initializer(i), type(t) { kind = K; } - PatternElement(const QStringRef &n, ExpressionNode *i = nullptr, Type t = Binding) + PatternElement(const QStringRef &n, TypeAnnotation *typeAnnotation = nullptr, ExpressionNode *i = nullptr, Type t = Binding) : bindingIdentifier(n), initializer(i), type(t) + , typeAnnotation(typeAnnotation) { Q_ASSERT(t >= RestElement); kind = K; @@ -749,7 +907,7 @@ public: { return identifierToken.isValid() ? identifierToken : (bindingTarget ? bindingTarget->firstSourceLocation() : initializer->firstSourceLocation()); } SourceLocation lastSourceLocation() const override - { return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : identifierToken); } + { return initializer ? initializer->lastSourceLocation() : (bindingTarget ? bindingTarget->lastSourceLocation() : (typeAnnotation ? typeAnnotation->lastSourceLocation() : identifierToken)); } ExpressionNode *destructuringTarget() const { return bindingTarget; } Pattern *destructuringPattern() const { return bindingTarget ? bindingTarget->patternCast() : nullptr; } @@ -759,7 +917,7 @@ public: bool isVariableDeclaration() const { return scope != VariableScope::NoScope; } bool isLexicallyScoped() const { return scope == VariableScope::Let || scope == VariableScope::Const; } - virtual void boundNames(QStringList *names); + virtual void boundNames(BoundNames *names); // attributes SourceLocation identifierToken; @@ -767,6 +925,7 @@ public: ExpressionNode *bindingTarget = nullptr; ExpressionNode *initializer = nullptr; Type type = Literal; + TypeAnnotation *typeAnnotation = nullptr; // when used in a VariableDeclarationList VariableScope scope = VariableScope::NoScope; bool isForDeclaration = false; @@ -796,7 +955,7 @@ public: void accept0(Visitor *visitor) override; - void boundNames(QStringList *names); + void boundNames(BoundNames *names); SourceLocation firstSourceLocation() const override { return elision ? elision->firstSourceLocation() : element->firstSourceLocation(); } @@ -819,7 +978,7 @@ public: { kind = K; } PatternProperty(PropertyName *name, const QStringRef &n, ExpressionNode *i = nullptr) - : PatternElement(n, i), name(name) + : PatternElement(n, /*type annotation*/nullptr, i), name(name) { kind = K; } PatternProperty(PropertyName *name, Pattern *pattern, ExpressionNode *i = nullptr) @@ -836,7 +995,7 @@ public: return loc.isValid() ? loc : name->lastSourceLocation(); } - void boundNames(QStringList *names) override; + void boundNames(BoundNames *names) override; bool convertLiteralToAssignmentPattern(MemoryPool *pool, SourceLocation *errorLocation, QString *errorMessage) override; // attributes @@ -864,7 +1023,7 @@ public: void accept0(Visitor *visitor) override; - void boundNames(QStringList *names); + void boundNames(BoundNames *names); inline PatternPropertyList *finish () { @@ -2154,8 +2313,9 @@ class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode public: QQMLJS_DECLARE_AST_NODE(FunctionExpression) - FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b): - name (n), formals (f), body (b) + FunctionExpression(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr): + name (n), formals (f), body (b), + typeAnnotation(typeAnnotation) { kind = K; } void accept0(Visitor *visitor) override; @@ -2174,6 +2334,7 @@ public: bool isGenerator = false; FormalParameterList *formals; StatementList *body; + TypeAnnotation *typeAnnotation; SourceLocation functionToken; SourceLocation identifierToken; SourceLocation lparenToken; @@ -2187,8 +2348,8 @@ class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression public: QQMLJS_DECLARE_AST_NODE(FunctionDeclaration) - FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b): - FunctionExpression(n, f, b) + FunctionDeclaration(const QStringRef &n, FormalParameterList *f, StatementList *b, TypeAnnotation *typeAnnotation = nullptr): + FunctionExpression(n, f, b, typeAnnotation) { kind = K; } void accept0(Visitor *visitor) override; @@ -2258,9 +2419,9 @@ public: return false; } - QStringList formals() const; + BoundNames formals() const; - QStringList boundNames() const; + BoundNames boundNames() const; void accept0(Visitor *visitor) override; @@ -2809,44 +2970,6 @@ public: SourceLocation semicolonToken; }; -class QML_PARSER_EXPORT UiQualifiedId: public Node -{ -public: - QQMLJS_DECLARE_AST_NODE(UiQualifiedId) - - UiQualifiedId(const QStringRef &name) - : next(this), name(name) - { kind = K; } - - UiQualifiedId(UiQualifiedId *previous, const QStringRef &name) - : name(name) - { - kind = K; - next = previous->next; - previous->next = this; - } - - UiQualifiedId *finish() - { - UiQualifiedId *head = next; - next = nullptr; - return head; - } - - void accept0(Visitor *visitor) override; - - SourceLocation firstSourceLocation() const override - { return identifierToken; } - - SourceLocation lastSourceLocation() const override - { return next ? next->lastSourceLocation() : identifierToken; } - -// attributes - UiQualifiedId *next; - QStringRef name; - SourceLocation identifierToken; -}; - class QML_PARSER_EXPORT UiImport: public Node { public: @@ -3114,10 +3237,10 @@ public: void accept0(Visitor *) override; SourceLocation firstSourceLocation() const override - { return propertyTypeToken; } + { return colonToken.isValid() ? identifierToken : propertyTypeToken; } SourceLocation lastSourceLocation() const override - { return next ? next->lastSourceLocation() : identifierToken; } + { return next ? next->lastSourceLocation() : (colonToken.isValid() ? propertyTypeToken : identifierToken); } inline UiParameterList *finish () { @@ -3133,6 +3256,7 @@ public: SourceLocation commaToken; SourceLocation propertyTypeToken; SourceLocation identifierToken; + SourceLocation colonToken; }; class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index 6fe108e425..05226fd043 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -158,6 +158,9 @@ class NestedExpression; class ClassExpression; class ClassDeclaration; class ClassElementList; +class TypeArgumentList; +class Type; +class TypeAnnotation; // ui elements class UiProgram; diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index f3732cbba8..7146cd00ac 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -403,6 +403,15 @@ public: virtual bool visit(DebuggerStatement *) { return true; } virtual void endVisit(DebuggerStatement *) {} + virtual bool visit(Type *) { return true; } + virtual void endVisit(Type *) {} + + virtual bool visit(TypeArgumentList *) { return true; } + virtual void endVisit(TypeArgumentList *) {} + + virtual bool visit(TypeAnnotation *) { return true; } + virtual void endVisit(TypeAnnotation *) {} + virtual void throwRecursionDepthError() = 0; quint16 recursionDepth() const { return m_recursionDepth; } diff --git a/src/qml/parser/qqmljsengine_p.h b/src/qml/parser/qqmljsengine_p.h index 6a754fc236..8a3e2db6a1 100644 --- a/src/qml/parser/qqmljsengine_p.h +++ b/src/qml/parser/qqmljsengine_p.h @@ -52,9 +52,10 @@ // #include "qqmljsglobal_p.h" -#include "qqmljsmemorypool_p.h" #include "qqmljssourcelocation_p.h" +#include <private/qqmljsmemorypool_p.h> + #include <QtCore/qstring.h> #include <QtCore/qset.h> diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index 165925d2a2..1e0ac72bd1 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -39,10 +39,10 @@ #include "qqmljslexer_p.h" #include "qqmljsengine_p.h" -#include "qqmljsmemorypool_p.h" #include "qqmljskeywords_p.h" #include <private/qqmljsdiagnosticmessage_p.h> +#include <private/qqmljsmemorypool_p.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qvarlengtharray.h> diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h deleted file mode 100644 index e7b1f46414..0000000000 --- a/src/qml/parser/qqmljsmemorypool_p.h +++ /dev/null @@ -1,256 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QQMLJSMEMORYPOOL_P_H -#define QQMLJSMEMORYPOOL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qqmljsglobal_p.h" - -#include <QtCore/qglobal.h> -#include <QtCore/qshareddata.h> -#include <QtCore/qdebug.h> - -#include <cstring> - -QT_BEGIN_NAMESPACE - -namespace QQmlJS { - -class Managed; - -class QML_PARSER_EXPORT MemoryPool : public QSharedData -{ - MemoryPool(const MemoryPool &other); - void operator =(const MemoryPool &other); - -public: - MemoryPool() {} - - ~MemoryPool() - { - if (_blocks) { - for (int i = 0; i < _allocatedBlocks; ++i) { - if (char *b = _blocks[i]) - free(b); - } - - free(_blocks); - } - qDeleteAll(strings); - } - - inline void *allocate(size_t size) - { - size = (size + 7) & ~size_t(7); - if (Q_LIKELY(_ptr && (_ptr + size < _end))) { - void *addr = _ptr; - _ptr += size; - return addr; - } - return allocate_helper(size); - } - - void reset() - { - _blockCount = -1; - _ptr = _end = nullptr; - } - - template <typename Tp> Tp *New() { return new (this->allocate(sizeof(Tp))) Tp(); } - template <typename Tp, typename... Ta> Tp *New(Ta... args) - { return new (this->allocate(sizeof(Tp))) Tp(args...); } - - QStringRef newString(const QString &string) { - strings.append(new QString(string)); - return QStringRef(strings.last()); - } - -private: - Q_NEVER_INLINE void *allocate_helper(size_t size) - { - size_t currentBlockSize = DEFAULT_BLOCK_SIZE; - while (Q_UNLIKELY(size >= currentBlockSize)) - currentBlockSize *= 2; - - if (++_blockCount == _allocatedBlocks) { - if (! _allocatedBlocks) - _allocatedBlocks = DEFAULT_BLOCK_COUNT; - else - _allocatedBlocks *= 2; - - _blocks = reinterpret_cast<char **>(realloc(_blocks, sizeof(char *) * size_t(_allocatedBlocks))); - Q_CHECK_PTR(_blocks); - - for (int index = _blockCount; index < _allocatedBlocks; ++index) - _blocks[index] = nullptr; - } - - char *&block = _blocks[_blockCount]; - - if (! block) { - block = reinterpret_cast<char *>(malloc(currentBlockSize)); - Q_CHECK_PTR(block); - } - - _ptr = block; - _end = _ptr + currentBlockSize; - - void *addr = _ptr; - _ptr += size; - return addr; - } - -private: - char **_blocks = nullptr; - int _allocatedBlocks = 0; - int _blockCount = -1; - char *_ptr = nullptr; - char *_end = nullptr; - QVector<QString*> strings; - - enum - { - DEFAULT_BLOCK_SIZE = 8 * 1024, - DEFAULT_BLOCK_COUNT = 8 - }; -}; - -class QML_PARSER_EXPORT Managed -{ - Q_DISABLE_COPY(Managed) -public: - Managed() = default; - ~Managed() = default; - - void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); } - void operator delete(void *) {} - void operator delete(void *, MemoryPool *) {} -}; - -template <typename T> -class FixedPoolArray -{ - T *data; - int count = 0; - -public: - FixedPoolArray() - : data(nullptr) - {} - - FixedPoolArray(MemoryPool *pool, int size) - { allocate(pool, size); } - - void allocate(MemoryPool *pool, int size) - { - count = size; - data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T))); - } - - void allocate(MemoryPool *pool, const QVector<T> &vector) - { - count = vector.count(); - data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T))); - - if (QTypeInfo<T>::isComplex) { - for (int i = 0; i < count; ++i) - new (data + i) T(vector.at(i)); - } else { - memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T)); - } - } - - template <typename Container> - void allocate(MemoryPool *pool, const Container &container) - { - count = container.count(); - data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T))); - typename Container::ConstIterator it = container.constBegin(); - for (int i = 0; i < count; ++i) - new (data + i) T(*it++); - } - - int size() const - { return count; } - - const T &at(int index) const { - Q_ASSERT(index >= 0 && index < count); - return data[index]; - } - - T &at(int index) { - Q_ASSERT(index >= 0 && index < count); - return data[index]; - } - - T &operator[](int index) { - return at(index); - } - - - int indexOf(const T &value) const { - for (int i = 0; i < count; ++i) - if (data[i] == value) - return i; - return -1; - } - - const T *begin() const { return data; } - const T *end() const { return data + count; } - - T *begin() { return data; } - T *end() { return data + count; } -}; - -} // namespace QQmlJS - -QT_END_NAMESPACE - -#endif |