From 603842bd581c976bd48b0eb1109d0f2a6812e0fe Mon Sep 17 00:00:00 2001 From: songqi Date: Tue, 14 Feb 2023 15:57:33 +0800 Subject: [PATCH] Fix parser of abstract and declare class modifiers in some scenarios Issue: I6F1LE Tests: parser/compiler/tsc/test262 Signed-off-by: songqi Change-Id: I470574c9547971f4a2a909886bd629ec3635871a --- es2panda/parser/statementParser.cpp | 33 + .../ts-test-export-abstract-class.ts | 23 + ...st-import-abstract-class-exec-expected.txt | 1 + .../ts-test-import-abstract-class-exec.ts | 26 + ...est-class-modifier-keywords-1-expected.txt | 1 + .../ts/test-class-modifier-keywords-1.ts | 17 + ...est-class-modifier-keywords-2-expected.txt | 644 ++++++++++++++++++ .../ts/test-class-modifier-keywords-2.ts | 21 + ...est-class-modifier-keywords-3-expected.txt | 1 + .../ts/test-class-modifier-keywords-3.ts | 17 + 10 files changed, 784 insertions(+) create mode 100644 es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-export-abstract-class.ts create mode 100644 es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-import-abstract-class-exec-expected.txt create mode 100644 es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-import-abstract-class-exec.ts create mode 100644 es2panda/test/parser/ts/test-class-modifier-keywords-1-expected.txt create mode 100644 es2panda/test/parser/ts/test-class-modifier-keywords-1.ts create mode 100644 es2panda/test/parser/ts/test-class-modifier-keywords-2-expected.txt create mode 100644 es2panda/test/parser/ts/test-class-modifier-keywords-2.ts create mode 100644 es2panda/test/parser/ts/test-class-modifier-keywords-3-expected.txt create mode 100644 es2panda/test/parser/ts/test-class-modifier-keywords-3.ts diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index e8f67909e3..e3ad20e0a9 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -206,6 +206,14 @@ ir::Statement *ParserImpl::ParseStatement(StatementParsingFlags flags) const auto startPos = lexer_->Save(); lexer_->NextToken(); // eat abstract keyword + if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE) { + if (isDeclare) { + ThrowSyntaxError("'declare' modifier already seen."); + } + lexer_->NextToken(); + isDeclare = true; + } + if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_CLASS) { lexer_->Rewind(startPos); } else { @@ -2361,6 +2369,13 @@ ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const le } else if (Extension() == ScriptExtension::TS && lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_INTERFACE) { declNode = ParseTsInterfaceDeclaration(); + } else if (Extension() == ScriptExtension::TS && + lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ABSTRACT) { + lexer_->NextToken(); + if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_CLASS) { + ThrowSyntaxError("Unexpected token, expected 'class'."); + } + declNode = ParseClassDeclaration(false, std::move(decorators), false, true, true); } else { declNode = ParseExpression(); Binder()->AddDecl(declNode->Start(), binder::DeclarationFlags::EXPORT, @@ -2563,6 +2578,24 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: context_.Status() = savedStatus; break; } + case lexer::TokenType::KEYW_ABSTRACT: { + lexer_->NextToken(); // eat abstract keyword + + if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE) { + if (isDeclare) { + ThrowSyntaxError("'declare' modifier already seen."); + } + lexer_->NextToken(); + isDeclare = true; + } + + if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_CLASS) { + ThrowSyntaxError("Unexpected token, expected 'class'."); + } + decl = ParseClassDeclaration(true, std::move(decorators), + isDeclare || IsDtsFile(), true, !isTsModule); + break; + } default: { break; } diff --git a/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-export-abstract-class.ts b/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-export-abstract-class.ts new file mode 100644 index 0000000000..ff3959333f --- /dev/null +++ b/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-export-abstract-class.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 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. + */ + + +export abstract class Animal { + name: string; + constructor(name: string) { + this.name = name; + } + abstract sayHello():void; +} diff --git a/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-import-abstract-class-exec-expected.txt b/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-import-abstract-class-exec-expected.txt new file mode 100644 index 0000000000..2690d58c49 --- /dev/null +++ b/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-import-abstract-class-exec-expected.txt @@ -0,0 +1 @@ +Tactic say hello. diff --git a/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-import-abstract-class-exec.ts b/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-import-abstract-class-exec.ts new file mode 100644 index 0000000000..ac26b2c1bb --- /dev/null +++ b/es2panda/test/compiler/ts/projects/ts_abstract_class_project_1/ts-test-import-abstract-class-exec.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 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. + */ + + +import { Animal } from './ts-test-export-abstract-class'; + +class Dog extends Animal{ + sayHello() { + print(`${this.name} say hello.`); + } +} + +var dog = new Dog("Tactic"); +dog.sayHello(); diff --git a/es2panda/test/parser/ts/test-class-modifier-keywords-1-expected.txt b/es2panda/test/parser/ts/test-class-modifier-keywords-1-expected.txt new file mode 100644 index 0000000000..c28a528bfa --- /dev/null +++ b/es2panda/test/parser/ts/test-class-modifier-keywords-1-expected.txt @@ -0,0 +1 @@ +SyntaxError: 'declare' modifier already seen. [test-class-modifier-keywords-1.ts:17:18] diff --git a/es2panda/test/parser/ts/test-class-modifier-keywords-1.ts b/es2panda/test/parser/ts/test-class-modifier-keywords-1.ts new file mode 100644 index 0000000000..91aea3e718 --- /dev/null +++ b/es2panda/test/parser/ts/test-class-modifier-keywords-1.ts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 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. + */ + + +declare abstract declare class A {} diff --git a/es2panda/test/parser/ts/test-class-modifier-keywords-2-expected.txt b/es2panda/test/parser/ts/test-class-modifier-keywords-2-expected.txt new file mode 100644 index 0000000000..544fda85c0 --- /dev/null +++ b/es2panda/test/parser/ts/test-class-modifier-keywords-2-expected.txt @@ -0,0 +1,644 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "loc": { + "start": { + "line": 17, + "column": 24 + }, + "end": { + "line": 17, + "column": 25 + } + } + }, + "superClass": null, + "implements": [], + "constructor": { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "declare": true, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 28 + } + } + }, + "body": [], + "indexSignatures": [], + "loc": { + "start": { + "line": 17, + "column": 26 + }, + "end": { + "line": 17, + "column": 28 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 18 + }, + "end": { + "line": 17, + "column": 28 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "B", + "loc": { + "start": { + "line": 18, + "column": 23 + }, + "end": { + "line": 18, + "column": 24 + } + } + }, + "superClass": null, + "implements": [], + "constructor": { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 18, + "column": 27 + } + } + }, + "body": [], + "indexSignatures": [], + "loc": { + "start": { + "line": 18, + "column": 25 + }, + "end": { + "line": 18, + "column": 27 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 17 + }, + "end": { + "line": 18, + "column": 27 + } + } + }, + "source": null, + "specifiers": [], + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 27 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "C", + "loc": { + "start": { + "line": 19, + "column": 22 + }, + "end": { + "line": 19, + "column": 23 + } + } + }, + "superClass": null, + "implements": [], + "constructor": { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "declare": true, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 16 + }, + "end": { + "line": 19, + "column": 26 + } + } + }, + "body": [], + "indexSignatures": [], + "loc": { + "start": { + "line": 19, + "column": 24 + }, + "end": { + "line": 19, + "column": 26 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 16 + }, + "end": { + "line": 19, + "column": 26 + } + } + }, + "source": null, + "specifiers": [], + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 19, + "column": 26 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "D", + "loc": { + "start": { + "line": 20, + "column": 31 + }, + "end": { + "line": 20, + "column": 32 + } + } + }, + "superClass": null, + "implements": [], + "constructor": { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "declare": true, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 25 + }, + "end": { + "line": 20, + "column": 35 + } + } + }, + "body": [], + "indexSignatures": [], + "loc": { + "start": { + "line": 20, + "column": 33 + }, + "end": { + "line": 20, + "column": 35 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 25 + }, + "end": { + "line": 20, + "column": 35 + } + } + }, + "source": null, + "specifiers": [], + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 20, + "column": 35 + } + } + }, + { + "type": "ExportDefaultDeclaration", + "declaration": { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "E", + "loc": { + "start": { + "line": 21, + "column": 31 + }, + "end": { + "line": 21, + "column": 32 + } + } + }, + "superClass": null, + "implements": [], + "constructor": { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 25 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "body": [], + "indexSignatures": [], + "loc": { + "start": { + "line": 21, + "column": 33 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 25 + }, + "end": { + "line": 21, + "column": 35 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 1 + }, + "end": { + "line": 21, + "column": 35 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 22, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/ts/test-class-modifier-keywords-2.ts b/es2panda/test/parser/ts/test-class-modifier-keywords-2.ts new file mode 100644 index 0000000000..803260fc9a --- /dev/null +++ b/es2panda/test/parser/ts/test-class-modifier-keywords-2.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 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. + */ + + +abstract declare class A {} +export abstract class B {} +export declare class C {} +export abstract declare class D {} +export default abstract class E {} diff --git a/es2panda/test/parser/ts/test-class-modifier-keywords-3-expected.txt b/es2panda/test/parser/ts/test-class-modifier-keywords-3-expected.txt new file mode 100644 index 0000000000..b594e737b2 --- /dev/null +++ b/es2panda/test/parser/ts/test-class-modifier-keywords-3-expected.txt @@ -0,0 +1 @@ +SyntaxError: Unexpected token, expected 'class'. [test-class-modifier-keywords-3.ts:17:25] diff --git a/es2panda/test/parser/ts/test-class-modifier-keywords-3.ts b/es2panda/test/parser/ts/test-class-modifier-keywords-3.ts new file mode 100644 index 0000000000..9930531173 --- /dev/null +++ b/es2panda/test/parser/ts/test-class-modifier-keywords-3.ts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 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. + */ + + +export default abstract func(); -- Gitee