diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index a914f8ad66a9f5933b7aa81757a056ca933f5573..93705974597eabb338863fd955d92e077aa3b3f5 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -189,6 +189,23 @@ ArenaVector GlobalClassHandler::TransformNamespaces(Aren return classDecls; } +void GlobalClassHandler::TransformBrokenNamespace(ir::AstNode *node, parser::Program *program) +{ + node->TransformChildrenRecursively( + // clang-format off + // CC-OFFNXT(G.FMT.14-CPP) project code style + [this, &program](ir::AstNode *child) -> ir::AstNode* { + if (child->IsETSModule() && child->AsETSModule()->IsNamespace()) { + auto res = TransformNamespace(child->AsETSModule(), program); + res->SetParent(child->Parent()); + return res; + } + return child; + }, + // clang-format on + "TransformBrokenNamespace"); +} + ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, parser::Program *program) { ir::ClassDeclaration *const globalDecl = CreateTransformedClass(ns); @@ -312,7 +329,6 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & CollectProgramGlobalClasses(globalProgram, namespaces); auto initializerBlockStmts = FormInitStaticBlockMethodStatements(globalProgram, moduleDependencies, std::move(initializerBlock)); - CollectExportedClasses(globalClass, globalProgram->Ast()->Statements()); // NOTE(vpukhov): stdlib checks are to be removed - do not extend the existing logic @@ -423,11 +439,12 @@ ArenaVector GlobalClassHandler::FormInitMethodStatements(parser FormDependentInitTriggers(statements, moduleDependencies); } for (const auto &[p, ps] : initStatements) { + for (auto st : ps) { + TransformBrokenNamespace(st, p); + st->SetParent(nullptr); + } statements.insert(statements.end(), ps.begin(), ps.end()); } - for (auto st : statements) { - st->SetParent(nullptr); - } return statements; } diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h index ae589327d1f9cafc16e003de9f9d4a35a80ae261..fc726e8dd6650907ffd8711b979694bb6250bfe8 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h @@ -76,6 +76,7 @@ private: ArenaVector> FormInitStaticBlockMethodStatements( parser::Program *program, const ModuleDependencies *moduleDependencies, ArenaVector &&initStatements); + void TransformBrokenNamespace(ir::AstNode *node, parser::Program *program); ArenaVector FormInitMethodStatements(parser::Program *program, const ModuleDependencies *moduleDependencies, diff --git a/ets2panda/parser/ETSFormattedParser.cpp b/ets2panda/parser/ETSFormattedParser.cpp index 93fac4b3e5590269a1692b433c089510359e52bc..4be9f1d50ca6cb62b7f4d36e1320a7b93d52e009 100644 --- a/ets2panda/parser/ETSFormattedParser.cpp +++ b/ets2panda/parser/ETSFormattedParser.cpp @@ -71,7 +71,7 @@ ir::Expression *ETSParser::ParseExpressionFormatPlaceholder() LogUnexpectedToken(lexer::TokenType::PUNCTUATOR_FORMAT); const auto &rangeToken = Lexer()->GetToken().Loc(); Lexer()->NextToken(); - return AllocBrokenType(rangeToken); + return AllocBrokenExpression(rangeToken); } ParserImpl::NodeFormatType nodeFormat = GetFormatPlaceholderType(); diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 6c905bafe65715c395e3d9e7a1b05d968b8dec95..f038afa6f25786da26b09e2ad4443873e5dbf95e 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -390,7 +390,7 @@ private: ir::ModifierFlags flags = ir::ModifierFlags::NONE) override; bool CheckInNamespaceContextIsExported(); ir::ETSModule *ParseNamespaceStatement(ir::ModifierFlags memberModifiers); - ir::ETSModule *ParseNamespace(ir::ModifierFlags flags); + ir::Statement *ParseNamespace(ir::ModifierFlags flags) override; ir::ETSModule *ParseNamespaceImp(ir::ModifierFlags flags); using NamespaceBody = std::tuple, lexer::SourceRange>; NamespaceBody ParseNamespaceBody(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags); diff --git a/ets2panda/parser/ETSparserNamespaces.cpp b/ets2panda/parser/ETSparserNamespaces.cpp index ea4a8feb4bad30cdaf3ca8bfcbcf73f4ac6995d2..53e582726f98edd951fc00f06292a2afa685bf3b 100644 --- a/ets2panda/parser/ETSparserNamespaces.cpp +++ b/ets2panda/parser/ETSparserNamespaces.cpp @@ -41,7 +41,7 @@ ir::ETSModule *ETSParser::ParseNamespaceStatement(ir::ModifierFlags memberModifi GetContext().Status() |= ParserStatus::IN_NAMESPACE; IncrementNamespaceNestedRank(); - ir::ETSModule *result = ParseNamespace(modifiers); + auto *result = ParseNamespace(modifiers); DecrementNamespaceNestedRank(); if (GetNamespaceNestedRank() == 0) { @@ -50,10 +50,10 @@ ir::ETSModule *ETSParser::ParseNamespaceStatement(ir::ModifierFlags memberModifi if ((memberModifiers & ir::ModifierFlags::DECLARE) != 0) { GetContext().Status() &= ~ParserStatus::IN_AMBIENT_CONTEXT; } - return result; + return result->AsETSModule(); } -ir::ETSModule *ETSParser::ParseNamespace(ir::ModifierFlags flags) +ir::Statement *ETSParser::ParseNamespace(ir::ModifierFlags flags) { if ((GetContext().Status() & ParserStatus::IN_NAMESPACE) == 0) { LogError(diagnostic::NAMESPACE_ONLY_TOP_OR_IN_NAMESPACE); diff --git a/ets2panda/parser/TypedParser.cpp b/ets2panda/parser/TypedParser.cpp index 8e8d168f738ef952117aee3af31ad8cae3275200..85634a4e63b208beb4e3e05def89d67a59fba2e6 100644 --- a/ets2panda/parser/TypedParser.cpp +++ b/ets2panda/parser/TypedParser.cpp @@ -166,7 +166,7 @@ ir::Statement *TypedParser::ParsePotentialExpressionStatement(StatementParsingFl } case lexer::TokenType::KEYW_NAMESPACE: { if (((GetContext().Status() & ParserStatus::IN_AMBIENT_CONTEXT) != 0U) || IsNamespaceDecl()) { - return ParseModuleDeclaration(); + return ParseNamespace(ir::ModifierFlags::NONE); } [[fallthrough]]; } @@ -221,6 +221,11 @@ ir::Statement *TypedParser::ParseModuleDeclaration([[maybe_unused]] StatementPar return ParseModuleOrNamespaceDeclaration(startLoc); } +ir::Statement *TypedParser::ParseNamespace([[maybe_unused]] ir::ModifierFlags flags) +{ + return ParseModuleDeclaration(); +} + ir::ArrowFunctionExpression *TypedParser::ParseGenericArrowFunction() { ArrowFunctionContext arrowFunctionContext(this, false); diff --git a/ets2panda/parser/TypedParser.h b/ets2panda/parser/TypedParser.h index 8101ab712324f90a8655a990b4220811eb90ba0a..bb1379b9e51586619e4f9a587faaf4e574a5a019 100644 --- a/ets2panda/parser/TypedParser.h +++ b/ets2panda/parser/TypedParser.h @@ -87,6 +87,7 @@ protected: // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParseModuleDeclaration(StatementParsingFlags flags = StatementParsingFlags::NONE) override; + virtual ir::Statement *ParseNamespace(ir::ModifierFlags flags); virtual void CheckIfTypeParameterNameIsReserved() {}; virtual ArenaVector ParseInterfaceExtendsClause(); virtual ir::Statement *ParseDeclareAndDecorators(StatementParsingFlags flags); diff --git a/ets2panda/test/ast/compiler/ets/binary_operator_neg.ets b/ets2panda/test/ast/compiler/ets/binary_operator_neg.ets new file mode 100644 index 0000000000000000000000000000000000000000..8b71c849f8ad5d88e633c11d47ad0de13bdd8ae8 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/binary_operator_neg.ets @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 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. + */ + +/* @@ label1 */@@/@ + +/* @@@ label1 Error SyntaxError: Unexpected token '@@'. */ +/* @@? 21:93 Error SyntaxError: Identifier expected, got 'end of stream'. */ +/* @@? 21:93 Error SyntaxError: Unexpected token 'end of stream'. */ +/* @@? 21:93 Error SyntaxError: Annotations are not allowed on this type of declaration. */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/classproperty_init_neg.ets b/ets2panda/test/ast/compiler/ets/classproperty_init_neg.ets new file mode 100644 index 0000000000000000000000000000000000000000..65fa3f5ea6928280df37aa218cf0baa3ff0c0a35 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/classproperty_init_neg.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 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. + */ + +class A {b5 : boolean = /* @@ label1 */7;} + +/* @@@ label1 Error TypeError: Type 'int' cannot be assigned to type 'boolean' */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/invalid_namespace_neg.ets b/ets2panda/test/ast/compiler/ets/invalid_namespace_neg.ets new file mode 100644 index 0000000000000000000000000000000000000000..2f3707f2acf87959d1beed916ef47f23830e600c --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/invalid_namespace_neg.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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 C{ + { + let y: number = + /* @@ label1 */} + + namespace C { + let xsx = 1 + } +} + +/* @@@ label1 Error SyntaxError: Unexpected token '}'. */ +/* @@? 28:1 Error SyntaxError: Unexpected token. */ diff --git a/ets2panda/test/ast/compiler/ets/invalid_namespace_neg2.ets b/ets2panda/test/ast/compiler/ets/invalid_namespace_neg2.ets new file mode 100644 index 0000000000000000000000000000000000000000..c7941e4248b1d7fc9f997fb803fba3db4fd1d678 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/invalid_namespace_neg2.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 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. + */ + +{ + /* @@ label1 */namespace C { + let my:number = 1 + } +} + +/* @@@ label1 Error SyntaxError: Namespace is allowed only at the top level or inside a namespace. */