diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index bb478ce458b109ed2e3063715d104dc1f9479a0d..39a45061df6a5f803f6f4a2b57b7a37945760afe 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -884,12 +884,13 @@ void ETSParser::ThrowIfVarDeclaration(VariableParsingFlags flags) ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::ModifierFlags modifiers) { ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY || - Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE); + Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE || + Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT); ArenaVector specifiers(Allocator()->Adapter()); if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) { ParseNameSpaceSpecifier(&specifiers, true); - } else { + } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { auto specs = ParseNamedSpecifiers(); if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM) { @@ -904,6 +905,8 @@ ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::Modifi result->AddModifier(modifiers); return result; } + } else { + return ParseSingleExport(modifiers); } // re-export directive @@ -1032,6 +1035,26 @@ ArenaVector ETSParser::ParseImportDeclarations() return statements; } +ir::ExportNamedDeclaration *ETSParser::ParseSingleExport(ir::ModifierFlags modifiers) +{ + lexer::Token token = Lexer()->GetToken(); + auto *exported = AllocNode(token.Ident(), Allocator()); + exported->SetReference(); + exported->SetRange(Lexer()->GetToken().Loc()); + + Lexer()->NextToken(); // eat exported variable name + + ArenaVector exports(Allocator()->Adapter()); + + exports.emplace_back(AllocNode(exported, ParseNamedExport(token))); + auto result = AllocNode(Allocator(), static_cast(nullptr), + std::move(exports)); + result->AddModifier(modifiers); + ConsumeSemicolon(result); + + return result; +} + ArenaVector ETSParser::ParseNamedSpecifiers() { // NOTE(user): handle qualifiedName in file bindings: qualifiedName '.' '*' diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index d5d8c6dd0435ad1ec729cc2df55b2f41e958f9ea..d0a7e697f255e4260905de5906156654e350f0d5 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -248,6 +248,7 @@ private: std::vector ParseSources(); std::tuple> ParseFromClause(bool requireFrom); ArenaVector ParseNamedSpecifiers(); + ir::ExportNamedDeclaration *ParseSingleExport(ir::ModifierFlags modifiers); ArenaVector ParseImportDeclarations(); parser::Program *ParseSource(const SourceFile &sourceFile); void AddExternalSource(const std::vector &programs); diff --git a/ets2panda/parser/ETSparserStatements.cpp b/ets2panda/parser/ETSparserStatements.cpp index 81961f9bc38acc9b3ed7f057cc9f05d5d63e6aa5..108e4f8d3dd273d1df493bee0d96fbd1f0d70b4f 100644 --- a/ets2panda/parser/ETSparserStatements.cpp +++ b/ets2panda/parser/ETSparserStatements.cpp @@ -138,6 +138,19 @@ ArenaVector ETSParser::ParseTopLevelStatements() return statements; } +static ir::Statement *ValidateExportableStatement(ETSParser *parser, ir::Statement *stmt, + ark::es2panda::ir::ModifierFlags memberModifiers) +{ + if (stmt != nullptr) { + if ((memberModifiers & ir::ModifierFlags::EXPORT_TYPE) != 0U && + !(stmt->IsClassDeclaration() || stmt->IsTSInterfaceDeclaration() || stmt->IsTSTypeAliasDeclaration())) { + parser->ThrowSyntaxError("Can only type export class or interface!", stmt->Start()); + } + stmt->AddModifier(memberModifiers); + } + return stmt; +} + ir::Statement *ETSParser::ParseTopLevelDeclStatement(StatementParsingFlags flags) { auto [memberModifiers, startLoc] = ParseMemberModifiers(); @@ -175,20 +188,16 @@ ir::Statement *ETSParser::ParseTopLevelDeclStatement(StatementParsingFlags flags } case lexer::TokenType::LITERAL_IDENT: { result = ParseIdentKeyword(); + if (result == nullptr && (memberModifiers & (ir::ModifierFlags::EXPORTED)) != 0U) { + return ParseExport(startLoc, memberModifiers); + } break; } default: { } } - if (result != nullptr) { - if ((memberModifiers & ir::ModifierFlags::EXPORT_TYPE) != 0U && - !(result->IsClassDeclaration() || result->IsTSInterfaceDeclaration() || - result->IsTSTypeAliasDeclaration())) { - ThrowSyntaxError("Can only type export class or interface!"); - } - result->AddModifier(memberModifiers); - } - return result; + + return ValidateExportableStatement(this, result, memberModifiers); } ir::Statement *ETSParser::ParseTopLevelStatement() diff --git a/ets2panda/test/compiler/ets/export_type_variable_at_definition-expected.txt b/ets2panda/test/compiler/ets/export_type_variable_at_definition-expected.txt index 10560edc38363584df4cec868fe0bd21b120ff2d..685c78436c85c3acd6e98d1a65c6be5dd5969abe 100644 --- a/ets2panda/test/compiler/ets/export_type_variable_at_definition-expected.txt +++ b/ets2panda/test/compiler/ets/export_type_variable_at_definition-expected.txt @@ -1 +1 @@ -SyntaxError: Can only type export class or interface! [export_type_variable_at_definition.sts:17:1] +SyntaxError: Can only type export class or interface! [export_type_variable_at_definition.sts:16:13] diff --git a/ets2panda/test/parser/ets/single_export/single_export_as_n-expected.txt b/ets2panda/test/parser/ets/single_export/single_export_as_n-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..6e5b4662369f24b11f3faeda719574b125dff891 --- /dev/null +++ b/ets2panda/test/parser/ets/single_export/single_export_as_n-expected.txt @@ -0,0 +1 @@ +SyntaxError: Unexpected token [single_export_as_n.sts:16:10] diff --git a/ets2panda/test/parser/ets/single_export/single_export_as_n.sts b/ets2panda/test/parser/ets/single_export/single_export_as_n.sts new file mode 100644 index 0000000000000000000000000000000000000000..9257a41168715ea911d16adf5d3bdff6e75d6c3c --- /dev/null +++ b/ets2panda/test/parser/ets/single_export/single_export_as_n.sts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024 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 a as A + +let a = 2; diff --git a/ets2panda/test/parser/ets/single_export/single_export_from_n-expected.txt b/ets2panda/test/parser/ets/single_export/single_export_from_n-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb2150a2fe9564ffad38d8e1de745f91a3f575f3 --- /dev/null +++ b/ets2panda/test/parser/ets/single_export/single_export_from_n-expected.txt @@ -0,0 +1 @@ +SyntaxError: Unexpected token [single_export_from_n.sts:13:10] diff --git a/ets2panda/test/parser/ets/single_export/single_export_from_n.sts b/ets2panda/test/parser/ets/single_export/single_export_from_n.sts new file mode 100644 index 0000000000000000000000000000000000000000..a5fe2bf6aaa48e32b27e3cc29df6cdc9e6bc15ed --- /dev/null +++ b/ets2panda/test/parser/ets/single_export/single_export_from_n.sts @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License");W + * 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 a from "./type" diff --git a/ets2panda/test/parser/ets/single_export/single_export_n-expected.txt b/ets2panda/test/parser/ets/single_export/single_export_n-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f2ee49160ef55a7dfd5f8e9f7e91ab4f314acf8 --- /dev/null +++ b/ets2panda/test/parser/ets/single_export/single_export_n-expected.txt @@ -0,0 +1 @@ +SyntaxError: Unexpected token [single_export_n.sts:16:9] diff --git a/ets2panda/test/parser/ets/single_export/single_export_n.sts b/ets2panda/test/parser/ets/single_export/single_export_n.sts new file mode 100644 index 0000000000000000000000000000000000000000..83d372af024853b07ca6d6192c3c083ae2e7242b --- /dev/null +++ b/ets2panda/test/parser/ets/single_export/single_export_n.sts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 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 v,m + +let v = 1 +let m = 2