diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index 6ad17db5ea350ffa3e12de52896547e62e0982b1..3ce0f603f9af20fe6dee3a345b25406233214a2f 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 b8a0f08ce969c8e7967e1713b5e4a47573509762..b379ed7a273df8b4452aefd0ac70b16ea6d80a2c 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 d863428fe3dd64d543bec4d996a33730e1a02cb2..3185da787efe83a16888c9d12b9bac96575ea400 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 b6f11650128d8f8b10693d8d466f1d5929c45393..8c6a8afda7393dd5c38c5d8953836cd6d84805ab 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 271f5f1c8f973c8fe02b1f4f11e0ce65071e7f74..a51e4fa5d5b8de492f2d4f61cc79479a3073ef9c 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 fc1663e5e9896e5a37206eb8e04f5d10f6946299..2c45441d6e880423e2d63366485883ced5fa080b 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 aea10c255caa603bb9a10b3bfc2c429aa47a9345..33ae6aa2b027bdd2cfc7b6995ab2bd963ba7f00d 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 0000000000000000000000000000000000000000..0feb64bb1b1966b87e92abc2b92afc656422ba1f --- /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 0000000000000000000000000000000000000000..222885cb5a2e6ea6dbed691198c32fb89b433bb2 --- /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 0000000000000000000000000000000000000000..4429fe297a6e35215645e589f54388541737b1e9 --- /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 0000000000000000000000000000000000000000..6b5fbe4b80f3a95241cff3bb1ee603bb50fcf96a --- /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";