From 1cb5e4059421f73b794ee045f47124275196e702 Mon Sep 17 00:00:00 2001 From: xucheng46 Date: Thu, 27 Oct 2022 03:45:46 +0000 Subject: [PATCH] Enable parser import/export type Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I5XZSK Test: parser tests, compiler tests, test262 Signed-off-by: xucheng46 Change-Id: I5cee1bc9c78376724d6b4a5fb633af330cc3217c --- es2panda/binder/binder.cpp | 2 +- es2panda/ir/module/exportNamedDeclaration.cpp | 3 +- es2panda/ir/module/exportNamedDeclaration.h | 14 +- es2panda/ir/module/importDeclaration.cpp | 5 +- es2panda/ir/module/importDeclaration.h | 13 +- es2panda/parser/parserImpl.h | 2 +- es2panda/parser/statementParser.cpp | 41 ++- .../parser/ts/test-export-type-expected.txt | 273 ++++++++++++++++++ es2panda/test/parser/ts/test-export-type.ts | 20 ++ .../parser/ts/test-import-type-expected.txt | 261 +++++++++++++++++ es2panda/test/parser/ts/test-import-type.ts | 20 ++ 11 files changed, 640 insertions(+), 14 deletions(-) create mode 100644 es2panda/test/parser/ts/test-export-type-expected.txt create mode 100644 es2panda/test/parser/ts/test-export-type.ts create mode 100644 es2panda/test/parser/ts/test-import-type-expected.txt create mode 100644 es2panda/test/parser/ts/test-import-type.ts diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index 6ad17db5ea..3ce0f603f9 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -120,7 +120,7 @@ void Binder::IdentifierAnalysis(ResolveBindingFlags flags) void Binder::ValidateExportDecl(const ir::ExportNamedDeclaration *exportDecl) { - if (exportDecl->Source() != nullptr || exportDecl->Decl() != nullptr) { + if (exportDecl->Source() != nullptr || exportDecl->Decl() != nullptr || exportDecl->IsType()) { return; } diff --git a/es2panda/ir/module/exportNamedDeclaration.cpp b/es2panda/ir/module/exportNamedDeclaration.cpp index b8a0f08ce9..b379ed7a27 100644 --- a/es2panda/ir/module/exportNamedDeclaration.cpp +++ b/es2panda/ir/module/exportNamedDeclaration.cpp @@ -42,7 +42,8 @@ void ExportNamedDeclaration::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ExportNamedDeclaration"}, {"declaration", AstDumper::Nullable(decl_)}, {"source", AstDumper::Nullable(source_)}, - {"specifiers", specifiers_}}); + {"specifiers", specifiers_}, + {"isType", AstDumper::Optional(IsType())}}); } void ExportNamedDeclaration::Compile(compiler::PandaGen *pg) const diff --git a/es2panda/ir/module/exportNamedDeclaration.h b/es2panda/ir/module/exportNamedDeclaration.h index d863428fe3..3185da787e 100644 --- a/es2panda/ir/module/exportNamedDeclaration.h +++ b/es2panda/ir/module/exportNamedDeclaration.h @@ -34,11 +34,12 @@ class ExportSpecifier; class ExportNamedDeclaration : public Statement { public: - explicit ExportNamedDeclaration(StringLiteral *source, ArenaVector &&specifiers) + explicit ExportNamedDeclaration(StringLiteral *source, ArenaVector &&specifiers, bool isType) : Statement(AstNodeType::EXPORT_NAMED_DECLARATION), source_(source), decl_(nullptr), - specifiers_(std::move(specifiers)) + specifiers_(std::move(specifiers)), + isType_(isType) { } @@ -46,7 +47,8 @@ public: : Statement(AstNodeType::EXPORT_NAMED_DECLARATION), source_(nullptr), decl_(decl), - specifiers_(std::move(specifiers)) + specifiers_(std::move(specifiers)), + isType_(false) { } @@ -70,6 +72,11 @@ public: return specifiers_; } + bool IsType() const + { + return isType_; + } + void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile(compiler::PandaGen *pg) const override; @@ -80,6 +87,7 @@ private: StringLiteral *source_; Statement *decl_; ArenaVector specifiers_; + bool isType_; }; } // namespace panda::es2panda::ir diff --git a/es2panda/ir/module/importDeclaration.cpp b/es2panda/ir/module/importDeclaration.cpp index b6f1165012..8c6a8afda7 100644 --- a/es2panda/ir/module/importDeclaration.cpp +++ b/es2panda/ir/module/importDeclaration.cpp @@ -31,7 +31,10 @@ void ImportDeclaration::Iterate(const NodeTraverser &cb) const void ImportDeclaration::Dump(ir::AstDumper *dumper) const { - dumper->Add({{"type", "ImportDeclaration"}, {"source", source_}, {"specifiers", specifiers_}}); + dumper->Add({{"type", "ImportDeclaration"}, + {"source", source_}, + {"specifiers", specifiers_}, + {"isType", AstDumper::Optional(IsType())}}); } void ImportDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} diff --git a/es2panda/ir/module/importDeclaration.h b/es2panda/ir/module/importDeclaration.h index 271f5f1c8f..a51e4fa5d5 100644 --- a/es2panda/ir/module/importDeclaration.h +++ b/es2panda/ir/module/importDeclaration.h @@ -34,8 +34,11 @@ class StringLiteral; class ImportDeclaration : public Statement { public: - explicit ImportDeclaration(StringLiteral *source, ArenaVector &&specifiers) - : Statement(AstNodeType::IMPORT_DECLARATION), source_(source), specifiers_(std::move(specifiers)) + explicit ImportDeclaration(StringLiteral *source, ArenaVector &&specifiers, bool isType) + : Statement(AstNodeType::IMPORT_DECLARATION), + source_(source), + specifiers_(std::move(specifiers)), + isType_(isType) { } @@ -49,6 +52,11 @@ public: return specifiers_; } + bool IsType() const + { + return isType_; + } + void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; @@ -58,6 +66,7 @@ public: private: StringLiteral *source_; ArenaVector specifiers_; + bool isType_; }; } // namespace panda::es2panda::ir diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index fc1663e5e9..2c45441d6e 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -409,7 +409,7 @@ private: ArenaVector decorators, bool isExportEquals = false); ir::ExportAllDeclaration *ParseExportAllDeclaration(const lexer::SourcePosition &startLoc); - ir::ExportNamedDeclaration *ParseExportNamedSpecifiers(const lexer::SourcePosition &startLoc); + ir::ExportNamedDeclaration *ParseExportNamedSpecifiers(const lexer::SourcePosition &startLoc, bool isType); ir::ExportNamedDeclaration *ParseNamedExportDeclaration(const lexer::SourcePosition &startLoc, ArenaVector &&decorators); ir::Identifier *ParseNamedExport(const lexer::Token &exportedToken); diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index aea10c255c..33ae6aa2b0 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -2345,7 +2345,8 @@ ir::ExportAllDeclaration *ParserImpl::ParseExportAllDeclaration(const lexer::Sou return exportDeclaration; } -ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer::SourcePosition &startLoc) +ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer::SourcePosition &startLoc, + bool isType) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat `{` character @@ -2396,9 +2397,11 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: } // record ExportEntry - AddExportNamedEntryItem(specifiers, source); + if (!isType) { + AddExportNamedEntryItem(specifiers, source); + } - auto *exportDeclaration = AllocNode(source, std::move(specifiers)); + auto *exportDeclaration = AllocNode(source, std::move(specifiers), isType); exportDeclaration->SetRange({startLoc, endPos}); ConsumeSemicolon(exportDeclaration); @@ -2528,6 +2531,19 @@ ir::Statement *ParserImpl::ParseExportDeclaration(StatementParsingFlags flags, lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); // eat `export` keyword + // won't set `isType` for type alias + bool isType = false; + if (Extension() == ScriptExtension::TS && + lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_TYPE) { + const auto savedPos = lexer_->Save(); + lexer_->NextToken(); // eat type + if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { + isType = true; + } else { + lexer_->Rewind(savedPos); + } + } + switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_DEFAULT: { // export default Id return ParseExportDefaultDeclaration(startLoc, std::move(decorators)); @@ -2536,7 +2552,7 @@ ir::Statement *ParserImpl::ParseExportDeclaration(StatementParsingFlags flags, return ParseExportAllDeclaration(startLoc); } case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { // export { ... } ... - return ParseExportNamedSpecifiers(startLoc); + return ParseExportNamedSpecifiers(startLoc, isType); } case lexer::TokenType::KEYW_IMPORT: { return ParseTsImportEqualsDeclaration(startLoc, true); @@ -2802,6 +2818,21 @@ ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); // eat import + bool isType = false; + if (Extension() == ScriptExtension::TS && + lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_TYPE) { + const auto savedPos = lexer_->Save(); + lexer_->NextToken(); // eat type + if ((lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && + lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM) || + lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE || + lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) { + isType = true; + } else { + lexer_->Rewind(savedPos); + } + } + ArenaVector specifiers(Allocator()->Adapter()); ir::StringLiteral *source = nullptr; @@ -2823,7 +2854,7 @@ ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) } lexer::SourcePosition endLoc = source->End(); - auto *importDeclaration = AllocNode(source, std::move(specifiers)); + auto *importDeclaration = AllocNode(source, std::move(specifiers), isType); importDeclaration->SetRange({startLoc, endLoc}); ConsumeSemicolon(importDeclaration); diff --git a/es2panda/test/parser/ts/test-export-type-expected.txt b/es2panda/test/parser/ts/test-export-type-expected.txt new file mode 100644 index 0000000000..0feb64bb1b --- /dev/null +++ b/es2panda/test/parser/ts/test-export-type-expected.txt @@ -0,0 +1,273 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 13 + }, + "end": { + "line": 17, + "column": 14 + } + } + }, + "typeAnnotation": { + "type": "TSNumberKeyword", + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + "source": null, + "specifiers": [], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + { + "type": "EmptyStatement", + "loc": { + "start": { + "line": 17, + "column": 23 + }, + "end": { + "line": 17, + "column": 24 + } + } + }, + { + "type": "TSTypeAliasDeclaration", + "id": { + "type": "Identifier", + "name": "b", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 6 + }, + "end": { + "line": 18, + "column": 7 + } + } + }, + "typeAnnotation": { + "type": "TSStringKeyword", + "loc": { + "start": { + "line": 18, + "column": 10 + }, + "end": { + "line": 18, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 17 + } + } + }, + { + "type": "EmptyStatement", + "loc": { + "start": { + "line": 18, + "column": 16 + }, + "end": { + "line": 18, + "column": 17 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": null, + "source": null, + "specifiers": [ + { + "type": "ExportSpecifier", + "local": { + "type": "Identifier", + "name": "b", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 14 + }, + "end": { + "line": 19, + "column": 15 + } + } + }, + "exported": { + "type": "Identifier", + "name": "b", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 14 + }, + "end": { + "line": 19, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 14 + }, + "end": { + "line": 19, + "column": 15 + } + } + } + ], + "isType": true, + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 19, + "column": 17 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": null, + "source": { + "type": "StringLiteral", + "value": "./C", + "loc": { + "start": { + "line": 20, + "column": 22 + }, + "end": { + "line": 20, + "column": 27 + } + } + }, + "specifiers": [ + { + "type": "ExportSpecifier", + "local": { + "type": "Identifier", + "name": "c", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 20, + "column": 15 + } + } + }, + "exported": { + "type": "Identifier", + "name": "c", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 20, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 14 + }, + "end": { + "line": 20, + "column": 15 + } + } + } + ], + "isType": true, + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 20, + "column": 28 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 21, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/ts/test-export-type.ts b/es2panda/test/parser/ts/test-export-type.ts new file mode 100644 index 0000000000..222885cb5a --- /dev/null +++ b/es2panda/test/parser/ts/test-export-type.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. + */ + + +export type a = number; +type b = string; +export type {b}; +export type {c} from "./C"; diff --git a/es2panda/test/parser/ts/test-import-type-expected.txt b/es2panda/test/parser/ts/test-import-type-expected.txt new file mode 100644 index 0000000000..4429fe297a --- /dev/null +++ b/es2panda/test/parser/ts/test-import-type-expected.txt @@ -0,0 +1,261 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./A", + "loc": { + "start": { + "line": 17, + "column": 22 + }, + "end": { + "line": 17, + "column": 27 + } + } + }, + "specifiers": [ + { + "type": "ImportSpecifier", + "local": { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 15 + } + } + }, + "imported": { + "type": "Identifier", + "name": "a", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 15 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 15 + } + } + } + ], + "isType": true, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 28 + } + } + }, + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./B", + "loc": { + "start": { + "line": 18, + "column": 20 + }, + "end": { + "line": 18, + "column": 25 + } + } + }, + "specifiers": [ + { + "type": "ImportDefaultSpecifier", + "local": { + "type": "Identifier", + "name": "b", + "decorators": [], + "loc": { + "start": { + "line": 18, + "column": 13 + }, + "end": { + "line": 18, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 13 + }, + "end": { + "line": 18, + "column": 14 + } + } + } + ], + "isType": true, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 26 + } + } + }, + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./C", + "loc": { + "start": { + "line": 19, + "column": 25 + }, + "end": { + "line": 19, + "column": 30 + } + } + }, + "specifiers": [ + { + "type": "ImportNamespaceSpecifier", + "local": { + "type": "Identifier", + "name": "c", + "decorators": [], + "loc": { + "start": { + "line": 19, + "column": 18 + }, + "end": { + "line": 19, + "column": 19 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 13 + }, + "end": { + "line": 19, + "column": 19 + } + } + } + ], + "isType": true, + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 19, + "column": 31 + } + } + }, + { + "type": "ImportDeclaration", + "source": { + "type": "StringLiteral", + "value": "./D", + "loc": { + "start": { + "line": 20, + "column": 18 + }, + "end": { + "line": 20, + "column": 23 + } + } + }, + "specifiers": [ + { + "type": "ImportDefaultSpecifier", + "local": { + "type": "Identifier", + "name": "type", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 8 + }, + "end": { + "line": 20, + "column": 12 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 8 + }, + "end": { + "line": 20, + "column": 12 + } + } + } + ], + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 20, + "column": 24 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 21, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/ts/test-import-type.ts b/es2panda/test/parser/ts/test-import-type.ts new file mode 100644 index 0000000000..6b5fbe4b80 --- /dev/null +++ b/es2panda/test/parser/ts/test-import-type.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. + */ + + +import type {a} from "./A"; +import type b from "./B"; +import type * as c from "./C"; +import type from "./D"; -- Gitee