diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index 474a24b0e0586935f133e39ac2110b31fbdf4b2b..13a5518276479c1db3c53eed00c5fbadfcdda686 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -131,12 +131,19 @@ void Binder::ValidateExportDecl(const ir::ExportNamedDeclaration *exportDecl) for (auto *it : exportDecl->Specifiers()) { auto localName = it->AsExportSpecifier()->Local()->Name(); if (scope_->IsTSModuleScope()) { - if (scope_->FindLocal(localName, ResolveBindingOptions::ALL) == nullptr && - !scope_->InLocalTSBindings(localName) && - !scope_->AsTSModuleScope()->InExportBindings(localName)) { - ThrowUndeclaredExport(it->AsExportSpecifier()->Local()->Start(), localName); + auto currentScope = scope_; + while (currentScope != nullptr) { + if (currentScope->FindLocal(localName, ResolveBindingOptions::ALL) != nullptr || + (currentScope->IsTSModuleScope() && (currentScope->InLocalTSBindings(localName) || + currentScope->AsTSModuleScope()->InExportBindings(localName)))) { + break; + } + currentScope = currentScope->Parent(); } - continue; + if (currentScope != nullptr) { + continue; + } + ThrowUndeclaredExport(it->AsExportSpecifier()->Local()->Start(), localName); } ASSERT(topScope_ == scope_); if (scope_->FindLocal(localName) == nullptr) { diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index 32f3d2db356419ad52f715d578a70b56748e7667..240f5bc21da279d676dba48f8f6e690b97e53e2e 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -2448,6 +2448,11 @@ ir::ExportAllDeclaration *ParserImpl::ParseExportAllDeclaration(const lexer::Sou ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer::SourcePosition &startLoc, bool isType) { + if (Extension() == ScriptExtension::TS && context_.IsTsModule() && + !(context_.Status() & ParserStatus::IN_AMBIENT_CONTEXT)) { + ThrowSyntaxError("Export declarations are not permitted in a namespace."); + } + lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat `{` character ArenaVector specifiers(Allocator()->Adapter()); diff --git a/es2panda/test/parser/ts/test-export-declaration1-expected.txt b/es2panda/test/parser/ts/test-export-declaration1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..24846224d39b794da037df089aee46685bd88414 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration1-expected.txt @@ -0,0 +1,130 @@ +{ + "type": "Program", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 6 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 10 + } + } + } + ], + "kind": "var", + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 11 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": null, + "source": null, + "specifiers": [ + { + "type": "ExportSpecifier", + "local": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 10 + } + } + }, + "exported": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 10 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 12 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 19, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/ts/test-export-declaration1.ts b/es2panda/test/parser/ts/test-export-declaration1.ts new file mode 100644 index 0000000000000000000000000000000000000000..a95638e9a10cc08458bf80498b8b15b43ae03580 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration1.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + + +var a = 1; +export {a}; diff --git a/es2panda/test/parser/ts/test-export-declaration2-expected.txt b/es2panda/test/parser/ts/test-export-declaration2-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1de94e4431551c941b4ecaffc1bf35af3e15f7b --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration2-expected.txt @@ -0,0 +1,289 @@ +{ + "type": "Program", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 6 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 17, + "column": 9 + }, + "end": { + "line": 17, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 10 + } + } + } + ], + "kind": "var", + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 11 + } + } + }, + { + "type": "TSModuleDeclaration", + "id": { + "type": "Identifier", + "name": "ns", + "loc": { + "start": { + "line": 18, + "column": 19 + }, + "end": { + "line": 18, + "column": 21 + } + } + }, + "body": { + "type": "TSModuleBlock", + "body": [ + { + "type": "ExportNamedDeclaration", + "declaration": null, + "source": null, + "specifiers": [ + { + "type": "ExportSpecifier", + "local": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 19, + "column": 13 + }, + "end": { + "line": 19, + "column": 14 + } + } + }, + "exported": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 19, + "column": 13 + }, + "end": { + "line": 19, + "column": 14 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 13 + }, + "end": { + "line": 19, + "column": 14 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 19, + "column": 16 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 22 + }, + "end": { + "line": 20, + "column": 2 + } + } + }, + "declare": true, + "global": false, + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 22, + "column": 4 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "b", + "loc": { + "start": { + "line": 22, + "column": 5 + }, + "end": { + "line": 22, + "column": 6 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 22, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 5 + }, + "end": { + "line": 22, + "column": 10 + } + } + } + ], + "kind": "var", + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 22, + "column": 11 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": null, + "source": null, + "specifiers": [ + { + "type": "ExportSpecifier", + "local": { + "type": "Identifier", + "name": "b", + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 10 + } + } + }, + "exported": { + "type": "Identifier", + "name": "b", + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 9 + }, + "end": { + "line": 23, + "column": 10 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 23, + "column": 12 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 25, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/ts/test-export-declaration2.ts b/es2panda/test/parser/ts/test-export-declaration2.ts new file mode 100644 index 0000000000000000000000000000000000000000..885219d3424397f3005297552f1647f00b623667 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration2.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + + +var a = 1; +declare namespace ns { + export {a}; +} + +var b = 1; +export {b}; + diff --git a/es2panda/test/parser/ts/test-export-declaration3-expected.txt b/es2panda/test/parser/ts/test-export-declaration3-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..f0efba0903d30cf4e63e72aa1da210564de6253b --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration3-expected.txt @@ -0,0 +1,392 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSModuleDeclaration", + "id": { + "type": "Identifier", + "name": "ns1", + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 14 + } + } + }, + "body": { + "type": "TSModuleBlock", + "body": [ + { + "type": "TSModuleDeclaration", + "id": { + "type": "Identifier", + "name": "ns2", + "loc": { + "start": { + "line": 18, + "column": 23 + }, + "end": { + "line": 18, + "column": 26 + } + } + }, + "body": { + "type": "TSModuleBlock", + "body": [ + { + "type": "ExportNamedDeclaration", + "declaration": null, + "source": null, + "specifiers": [ + { + "type": "ExportSpecifier", + "local": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 18 + } + } + }, + "exported": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 19, + "column": 17 + }, + "end": { + "line": 19, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 19, + "column": 9 + }, + "end": { + "line": 19, + "column": 20 + } + } + } + ], + "loc": { + "start": { + "line": 18, + "column": 27 + }, + "end": { + "line": 20, + "column": 6 + } + } + }, + "declare": true, + "global": false, + "loc": { + "start": { + "line": 18, + "column": 13 + }, + "end": { + "line": 21, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 15 + }, + "end": { + "line": 21, + "column": 2 + } + } + }, + "declare": false, + "global": false, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 23, + "column": 10 + } + } + }, + { + "type": "TSModuleDeclaration", + "id": { + "type": "Identifier", + "name": "ns1", + "loc": { + "start": { + "line": 23, + "column": 11 + }, + "end": { + "line": 23, + "column": 14 + } + } + }, + "body": { + "type": "TSModuleBlock", + "body": [ + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "a", + "loc": { + "start": { + "line": 24, + "column": 16 + }, + "end": { + "line": 24, + "column": 17 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 24, + "column": 20 + }, + "end": { + "line": 24, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 16 + }, + "end": { + "line": 24, + "column": 21 + } + } + } + ], + "kind": "var", + "loc": { + "start": { + "line": 24, + "column": 12 + }, + "end": { + "line": 24, + "column": 22 + } + } + }, + "source": null, + "specifiers": [], + "loc": { + "start": { + "line": 24, + "column": 5 + }, + "end": { + "line": 24, + "column": 22 + } + } + } + ], + "loc": { + "start": { + "line": 23, + "column": 15 + }, + "end": { + "line": 25, + "column": 2 + } + } + }, + "declare": false, + "global": false, + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 27, + "column": 4 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "b", + "loc": { + "start": { + "line": 27, + "column": 5 + }, + "end": { + "line": 27, + "column": 6 + } + } + }, + "init": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 27, + "column": 9 + }, + "end": { + "line": 27, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 27, + "column": 5 + }, + "end": { + "line": 27, + "column": 10 + } + } + } + ], + "kind": "var", + "loc": { + "start": { + "line": 27, + "column": 1 + }, + "end": { + "line": 27, + "column": 11 + } + } + }, + { + "type": "ExportNamedDeclaration", + "declaration": null, + "source": null, + "specifiers": [ + { + "type": "ExportSpecifier", + "local": { + "type": "Identifier", + "name": "b", + "loc": { + "start": { + "line": 28, + "column": 9 + }, + "end": { + "line": 28, + "column": 10 + } + } + }, + "exported": { + "type": "Identifier", + "name": "b", + "loc": { + "start": { + "line": 28, + "column": 9 + }, + "end": { + "line": 28, + "column": 10 + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 9 + }, + "end": { + "line": 28, + "column": 10 + } + } + } + ], + "loc": { + "start": { + "line": 28, + "column": 1 + }, + "end": { + "line": 28, + "column": 12 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 29, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/ts/test-export-declaration3.ts b/es2panda/test/parser/ts/test-export-declaration3.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e002f4a6dbdc00beb2ca32d99800fda75bc35f7 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration3.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + + +namespace ns1 { + declare namespace ns2 { + export {a}; + } +} + +namespace ns1 { + export var a = 1; +} + +var b = 1; +export {b}; diff --git a/es2panda/test/parser/ts/test-export-declaration4-expected.txt b/es2panda/test/parser/ts/test-export-declaration4-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..41aff89ac3f7ca0ef5f3a123652941c5bea5b842 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration4-expected.txt @@ -0,0 +1 @@ +SyntaxError: Export name 'a' is not defined. [test-export-declaration4.ts:18:13] diff --git a/es2panda/test/parser/ts/test-export-declaration4.ts b/es2panda/test/parser/ts/test-export-declaration4.ts new file mode 100644 index 0000000000000000000000000000000000000000..44c91379e90f4fc388b99514e72db4e81d65fef5 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration4.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + + +declare namespace ns { + export {a}; +} + +var b = 1; +export {b}; diff --git a/es2panda/test/parser/ts/test-export-declaration5-expected.txt b/es2panda/test/parser/ts/test-export-declaration5-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb89b799093759f1548e8d09d6308935bd0e4916 --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration5-expected.txt @@ -0,0 +1 @@ +SyntaxError: Export declarations are not permitted in a namespace. [test-export-declaration5.ts:19:12] diff --git a/es2panda/test/parser/ts/test-export-declaration5.ts b/es2panda/test/parser/ts/test-export-declaration5.ts new file mode 100644 index 0000000000000000000000000000000000000000..91a7bdb6c58000009a9d60dbde7b1e2646b9eeeb --- /dev/null +++ b/es2panda/test/parser/ts/test-export-declaration5.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. + */ + + +namespace ns { + var a; + export {a}; +} diff --git a/es2panda/test/test_tsc_ignore_list.txt b/es2panda/test/test_tsc_ignore_list.txt index 100737b8d4c54e8fd00d21aae2e5304f51a45d43..761f6a12a60d378dd107004dcfa7ae526836406a 100644 --- a/es2panda/test/test_tsc_ignore_list.txt +++ b/es2panda/test/test_tsc_ignore_list.txt @@ -12,7 +12,6 @@ es2panda/test/TypeScript/tests/cases/compiler/genericRecursiveImplicitConstructo es2panda/test/TypeScript/tests/cases/compiler/globalIsContextualKeyword.ts es2panda/test/TypeScript/tests/cases/compiler/inferenceErasedSignatures.ts es2panda/test/TypeScript/tests/cases/compiler/isLiteral1.ts -es2panda/test/TypeScript/tests/cases/compiler/noCircularDefinitionOnExportOfPrivateInMergedNamespace.ts es2panda/test/TypeScript/tests/cases/compiler/isLiteral2.ts es2panda/test/TypeScript/tests/cases/compiler/letAsIdentifier2.ts es2panda/test/TypeScript/tests/cases/compiler/letInVarDeclOfForIn_ES5.ts