diff --git a/es2panda/parser/parserImpl.cpp b/es2panda/parser/parserImpl.cpp index 2c48466b88bf78aeaf4fcb53e0f757294d141190..27c93813a7d2a2aa2fd7a140ecaf8bef67d11ad3 100644 --- a/es2panda/parser/parserImpl.cpp +++ b/es2panda/parser/parserImpl.cpp @@ -393,14 +393,16 @@ ir::Expression *ParserImpl::ParseTsTypeAnnotationElement(ir::Expression *typeAnn { switch (lexer_->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { - if (*options & (TypeAnnotationParsingOptions::IN_UNION | TypeAnnotationParsingOptions::IN_INTERSECTION)) { + if (*options & (TypeAnnotationParsingOptions::IN_MODIFIER | TypeAnnotationParsingOptions::IN_UNION | + TypeAnnotationParsingOptions::IN_INTERSECTION)) { break; } return ParseTsUnionType(typeAnnotation, *options & TypeAnnotationParsingOptions::RESTRICT_EXTENDS); } case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { - if (*options & TypeAnnotationParsingOptions::IN_INTERSECTION) { + if (*options & (TypeAnnotationParsingOptions::IN_MODIFIER | + TypeAnnotationParsingOptions::IN_INTERSECTION)) { break; } @@ -655,6 +657,7 @@ ir::Expression *ParserImpl::ParseTsTypeOperatorOrTypeReference() lexer::SourcePosition typeOperatorStart = lexer_->GetToken().Start(); lexer_->NextToken(); + options |= TypeAnnotationParsingOptions::IN_MODIFIER; ir::Expression *type = ParseTsTypeAnnotation(&options); if (!type->IsTSArrayType() && !type->IsTSTupleType()) { @@ -674,6 +677,7 @@ ir::Expression *ParserImpl::ParseTsTypeOperatorOrTypeReference() lexer::SourcePosition typeOperatorStart = lexer_->GetToken().Start(); lexer_->NextToken(); + options |= TypeAnnotationParsingOptions::IN_MODIFIER; ir::Expression *type = ParseTsTypeAnnotation(&options); auto *typeOperator = AllocNode(type, ir::TSOperatorType::KEYOF); @@ -1907,7 +1911,7 @@ void ParserImpl::ThrowIfPrivateIdent(ClassElmentDescriptor *desc, const char *ms } } -void ParserImpl::ValidateClassKey(ClassElmentDescriptor *desc) +void ParserImpl::ValidateClassKey(ClassElmentDescriptor *desc, bool isDeclare) { if ((desc->modifiers & ir::ModifierFlags::ASYNC) && (desc->methodKind == ir::MethodDefinitionKind::GET || desc->methodKind == ir::MethodDefinitionKind::SET)) { @@ -1935,12 +1939,12 @@ void ParserImpl::ValidateClassKey(ClassElmentDescriptor *desc) } else if (Extension() == ScriptExtension::TS) { ThrowSyntaxError("Static modifier can not appear on a constructor"); } - } else if (propNameStr.Is("prototype") && (desc->modifiers & ir::ModifierFlags::STATIC)) { + } else if (!isDeclare && propNameStr.Is("prototype") && (desc->modifiers & ir::ModifierFlags::STATIC)) { ThrowSyntaxError("Classes may not have static property named prototype"); } } -ir::Expression *ParserImpl::ParseClassKey(ClassElmentDescriptor *desc) +ir::Expression *ParserImpl::ParseClassKey(ClassElmentDescriptor *desc, bool isDeclare) { ir::Expression *propName = nullptr; if (lexer_->GetToken().IsKeyword()) { @@ -1949,7 +1953,7 @@ ir::Expression *ParserImpl::ParseClassKey(ClassElmentDescriptor *desc) switch (lexer_->GetToken().Type()) { case lexer::TokenType::LITERAL_IDENT: { - ValidateClassKey(desc); + ValidateClassKey(desc, isDeclare); propName = AllocNode(lexer_->GetToken().Ident(), Allocator()); propName->SetRange(lexer_->GetToken().Loc()); @@ -2319,7 +2323,7 @@ ir::Statement *ParserImpl::ParseClassElement(const ArenaVector context_.Status() |= ParserStatus::ALLOW_THIS_TYPE; } - ir::Expression *propName = ParseClassKey(&desc); + ir::Expression *propName = ParseClassKey(&desc, isDeclare); if (desc.methodKind == ir::MethodDefinitionKind::CONSTRUCTOR && !decorators.empty()) { ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); @@ -2422,7 +2426,7 @@ ir::MethodDefinition *ParserImpl::CreateImplicitConstructor(bool hasSuperClass, } auto *body = AllocNode(scope, std::move(statements)); - auto *func = AllocNode(scope, std::move(params), nullptr, body, nullptr, + auto *func = AllocNode(scope, std::move(params), nullptr, isDeclare ? nullptr : body, nullptr, ir::ScriptFunctionFlags::CONSTRUCTOR, isDeclare); scope->BindNode(func); paramScope->BindNode(func); @@ -2644,7 +2648,7 @@ ir::ClassDefinition *ParserImpl::ParseClassDefinition(bool isDeclaration, bool i } if (IsConstructor(property)) { - if (ctor) { + if (!isDeclare && ctor) { ThrowSyntaxError("Multiple constructor implementations are not allowed.", property->Start()); } ctor = property->AsMethodDefinition(); diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index da02569bca91421ac1952c2ef1ff373bc0608a96..aa97f60574e6020538857083b7480f364489e4a6 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -163,6 +163,7 @@ enum class TypeAnnotationParsingOptions { THROW_ERROR = 1 << 4, CAN_BE_TS_TYPE_PREDICATE = 1 << 5, BREAK_AT_NEW_LINE = 1 << 6, + IN_MODIFIER = 1 << 7, }; DEFINE_BITOPS(TypeAnnotationParsingOptions) @@ -262,10 +263,10 @@ private: ir::ModifierFlags ParseModifiers(); void ThrowIfPrivateIdent(ClassElmentDescriptor *desc, const char *msg); - void ValidateClassKey(ClassElmentDescriptor *desc); + void ValidateClassKey(ClassElmentDescriptor *desc, bool isDeclare); void ValidateClassMethodStart(ClassElmentDescriptor *desc, ir::Expression *typeAnnotation); - ir::Expression *ParseClassKey(ClassElmentDescriptor *desc); + ir::Expression *ParseClassKey(ClassElmentDescriptor *desc, bool isDeclare); void ValidateClassSetter(ClassElmentDescriptor *desc, const ArenaVector &properties, ir::Expression *propName, ir::ScriptFunction *func, bool hasDecorator, diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index a2c4b9b985bc1db1407f3a61b74fae66947859b6..ffa8688480bf9dd559572bc8f493b5feca1e6889 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -1009,7 +1009,7 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou ThrowSyntaxError("Unexpected token, expected identifier after 'function' keyword"); } - if (lexer_->GetToken().KeywordType() >= lexer::TokenType::KEYW_ARGUMENTS) { + if (!isDeclare && lexer_->GetToken().KeywordType() >= lexer::TokenType::KEYW_ARGUMENTS) { ThrowSyntaxError("Unexpected reserved word in strict mode."); } diff --git a/es2panda/test/parser/ts/test-keyword-declare-expected.txt b/es2panda/test/parser/ts/test-keyword-declare-expected.txt index 7f6134c906b6935b563eb89726503f265fe4f282..3efb1166b8b666ae55d2e0db1069f5a1f7d466cf 100644 --- a/es2panda/test/parser/ts/test-keyword-declare-expected.txt +++ b/es2panda/test/parser/ts/test-keyword-declare-expected.txt @@ -722,20 +722,7 @@ "async": false, "expression": false, "params": [], - "body": { - "type": "BlockStatement", - "statements": [], - "loc": { - "start": { - "line": 1, - "column": 1 - }, - "end": { - "line": 1, - "column": 1 - } - } - }, + "declare": true, "loc": { "start": { "line": 1, diff --git a/es2panda/test/parser/ts/test-type-annotation1-expected.txt b/es2panda/test/parser/ts/test-type-annotation1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c36ce341d71266edf6dd89682c8ea7b7e29fdb1 --- /dev/null +++ b/es2panda/test/parser/ts/test-type-annotation1-expected.txt @@ -0,0 +1,228 @@ +{ + "type": "Program", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "typeAnnotation": { + "type": "TSUnionType", + "types": [ + { + "type": "TSTypeOperator", + "operator": "readonly", + "typeAnnotation": { + "type": "TSArrayType", + "elementType": { + "type": "TSAnyKeyword", + "loc": { + "start": { + "line": 18, + "column": 18 + }, + "end": { + "line": 18, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 18 + }, + "end": { + "line": 18, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 23 + } + } + }, + { + "type": "TSNullKeyword", + "loc": { + "start": { + "line": 18, + "column": 26 + }, + "end": { + "line": 18, + "column": 30 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 30 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 6 + } + } + }, + "init": null, + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 6 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 6 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "b", + "typeAnnotation": { + "type": "TSUnionType", + "types": [ + { + "type": "TSTypeOperator", + "operator": "keyof", + "typeAnnotation": { + "type": "TSAnyKeyword", + "loc": { + "start": { + "line": 19, + "column": 15 + }, + "end": { + "line": 19, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 9 + }, + "end": { + "line": 19, + "column": 18 + } + } + }, + { + "type": "TSNullKeyword", + "loc": { + "start": { + "line": 19, + "column": 21 + }, + "end": { + "line": 19, + "column": 25 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 9 + }, + "end": { + "line": 19, + "column": 25 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "init": null, + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 19, + "column": 6 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 19, + "column": 6 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 21, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/ts/test-type-annotation1.ts b/es2panda/test/parser/ts/test-type-annotation1.ts new file mode 100644 index 0000000000000000000000000000000000000000..86cbfe0b863aeb081a3a72f6b0dacfdf204a69c9 --- /dev/null +++ b/es2panda/test/parser/ts/test-type-annotation1.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +// Test types with special keywords +let a : readonly any[] | null +let b : keyof any | null +