diff --git a/es2panda/parser/transformer/transformer.cpp b/es2panda/parser/transformer/transformer.cpp index 5a3d1325525d6146e849df3db3d9b6ef3ae571ca..5bcd58da78ad60cf9f5fc3ae3657d6d2bae935c5 100644 --- a/es2panda/parser/transformer/transformer.cpp +++ b/es2panda/parser/transformer/transformer.cpp @@ -19,7 +19,6 @@ #include "binder/scope.h" #include "ir/base/catchClause.h" -#include "ir/base/classDefinition.h" #include "ir/base/classProperty.h" #include "ir/base/classStaticBlock.h" #include "ir/base/decorator.h" @@ -200,11 +199,19 @@ ir::UpdateNodes Transformer::VisitTSNode(ir::AstNode *childNode) switch (childNode->Type()) { case ir::AstNodeType::IDENTIFIER: { auto *ident = childNode->AsIdentifier(); - if (!ident->IsReference() || (!IsTsModule() && !IsTsEnum())) { + if (!ident->IsReference() || (!IsTsModule() && !IsTsEnum() && !InClass())) { return VisitTSNodes(childNode); } auto name = ident->Name(); + if (InClass()) { + auto *classDefinition = GetClassReference(name); + auto aliasName = GetClassAliasName(name, classDefinition); + if (classDefinition != nullptr && aliasName != name) { + ident->SetName(aliasName); + } + } + if (IsTsEnum()) { auto scope = FindEnumMemberScope(name); if (scope) { @@ -306,7 +313,8 @@ ir::UpdateNodes Transformer::VisitTSNode(ir::AstNode *childNode) if (node->Definition()->Declare()) { return node; } - DuringClass duringClass(&classList_, node->Definition()->GetName()); + DuringClass duringClass(&classList_, node->Definition()->GetName(), + CreateClassAliasName(node), node->Definition()); node = VisitTSNodes(node)->AsClassDeclaration(); auto res = VisitClassDeclaration(node); SetOriginalNode(res, childNode); @@ -315,7 +323,8 @@ ir::UpdateNodes Transformer::VisitTSNode(ir::AstNode *childNode) } case ir::AstNodeType::CLASS_EXPRESSION: { auto *node = childNode->AsClassExpression(); - DuringClass duringClass(&classList_, node->Definition()->GetName()); + DuringClass duringClass(&classList_, node->Definition()->GetName(), + node->Definition()->GetName(), node->Definition()); node = VisitTSNodes(node)->AsClassExpression(); auto res = VisitClassExpression(node); SetOriginalNode(res, childNode); @@ -507,6 +516,35 @@ void Transformer::VisitComputedProperty(ir::ClassDefinition *node) } } +const ir::ClassDefinition *Transformer::GetClassReference(util::StringView name) const +{ + auto *scope = Scope(); + while (scope != nullptr) { + auto *v = scope->FindLocal(name, binder::ResolveBindingOptions::BINDINGS); + if (v != nullptr) { + if (v->Declaration() != nullptr && v->Declaration()->Node() != nullptr && + v->Declaration()->Node()->IsClassDefinition()) { + ASSERT(v->Declaration()->Node()->AsClassDefinition()->GetName() == name); + return v->Declaration()->Node()->AsClassDefinition(); + } else { + return nullptr; + } + } + + scope = scope->Parent(); + } + + return nullptr; +} + +util::StringView Transformer::CreateClassAliasName(ir::ClassDeclaration *node) +{ + if (node->HasDecorators()) { + return CreateUniqueName(std::string(NEW_VAR_PREFIX) + std::string(NEW_VAR_HEAD)); + } + return node->Definition()->GetName(); +} + void Transformer::VisitPrivateElement(ir::ClassDefinition *node) { /* @@ -1031,10 +1069,13 @@ ir::UpdateNodes Transformer::VisitClassDeclaration(ir::ClassDeclaration *node) std::vector res; bool hasClassDecorators = node->HasDecorators(); if (hasClassDecorators) { - auto definiton = node->Definition(); - auto *clsExpression = AllocNode(definiton); + auto aliasName = GetClassAliasName(); + res.push_back(CreateVariableDeclarationWithIdentify(aliasName, VariableParsingFlags::VAR, nullptr, false)); + auto *clsExpression = AllocNode(node->Definition()); + auto *assignExpr = AllocNode(CreateReferenceIdentifier(aliasName), clsExpression, + lexer::TokenType::PUNCTUATOR_SUBSTITUTION); res.push_back(CreateVariableDeclarationWithIdentify(name, VariableParsingFlags::LET, node, false, - clsExpression, false)); + assignExpr, false)); } else { res.push_back(node); } @@ -1554,7 +1595,10 @@ std::vector Transformer::CreateClassDecorators(ir::ClassDeclarati auto left = CreateReferenceIdentifier(name); auto id = CreateReferenceIdentifier(name); auto right = AllocNode(callExpr, id, lexer::TokenType::PUNCTUATOR_LOGICAL_OR); - auto *assignExpr = AllocNode(left, right, + auto middle = CreateReferenceIdentifier(GetClassAliasName()); + auto innerAssignExpr = AllocNode(middle, right, + lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + auto *assignExpr = AllocNode(left, innerAssignExpr, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); res.push_back(AllocNode(assignExpr)); diff --git a/es2panda/parser/transformer/transformer.h b/es2panda/parser/transformer/transformer.h index 3d252dee445a4f85a1ec2b8389a79cca76350a12..2a699f879a5f0b609bd760ba685e9ffbaacf09f9 100644 --- a/es2panda/parser/transformer/transformer.h +++ b/es2panda/parser/transformer/transformer.h @@ -21,6 +21,7 @@ #include "binder/binder.h" #include "binder/scope.h" #include "ir/astNode.h" +#include "ir/base/classDefinition.h" #include "ir/base/methodDefinition.h" #include "parser/module/sourceTextModuleRecord.h" #include "parser/parserFlags.h" @@ -43,6 +44,8 @@ using ComputedPropertyMap = std::unordered_map *classList, util::StringView name) + explicit DuringClass(ArenaVector *classList, util::StringView name, + util::StringView aliasName, ir::ClassDefinition *node) { classList_ = classList; - classList_->push_back({name, 0, &bindNameMap_, &computedPropertyMap_}); + classList_->push_back({name, aliasName, node, 0, &bindNameMap_, &computedPropertyMap_}); } ~DuringClass() @@ -136,6 +140,8 @@ private: util::StringView name); void VisitPrivateElement(ir::ClassDefinition *node); void VisitComputedProperty(ir::ClassDefinition *node); + util::StringView CreateClassAliasName(ir::ClassDeclaration *node); + const ir::ClassDefinition *GetClassReference(util::StringView name) const; size_t GetInsertPosForConstructor(ir::ClassDefinition *node); void FindSuperCall(const ir::AstNode *parent, bool *hasSuperCall); void FindSuperCallInCtorChildNode(const ir::AstNode *childNode, bool *hasSuperCall); @@ -254,6 +260,11 @@ private: return (tsEnumList_.size() != 0); } + bool InClass() const + { + return (classList_.size() != 0); + } + template T *AllocNode(Args &&... args) { @@ -347,6 +358,25 @@ private: return res->second; } + util::StringView GetClassAliasName() const + { + return classList_.back().aliasName; + } + + util::StringView GetClassAliasName(util::StringView originName, const ir::ClassDefinition *node) const + { + if (node == nullptr) { + return originName; + } + + for (int i = classList_.size() - 1; i >= 0; i--) { + if (classList_[i].node == node) { + return classList_[i].aliasName; + } + } + return originName; + } + Program *program_; ArenaVector tsModuleList_; ArenaVector tsEnumList_; diff --git a/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-22-expected.txt b/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-22-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb101b641b9bd8575e3f9813b83abaa7bb616890 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-22-expected.txt @@ -0,0 +1,2 @@ +true +true diff --git a/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-22.ts b/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-22.ts new file mode 100644 index 0000000000000000000000000000000000000000..04879232217c86faa8bd9399039fa86aca4bcec0 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-22.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + + +function Observed(constructor_: any, _?: any) { + return class extends constructor_ { } +} + +@Observed +class Person { + addMeta() { + return new Person(); + } +} + +let personone = new Person(); +let persontwo = personone.addMeta(); +print(personone instanceof Person); +print(persontwo instanceof Person); diff --git a/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-23-expected.txt b/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-23-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6b49492c1f79b2c9d56e511d8bad1252a192d0a --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-23-expected.txt @@ -0,0 +1,2 @@ +test +1 diff --git a/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-23.ts b/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-23.ts new file mode 100644 index 0000000000000000000000000000000000000000..65294d78002e93d7ac071a67f96fd4afa5a28232 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/decorators/test-ts-decorators-23.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + + +function f(constructor: Function) { print("test"); } + +@f +class Person { + foo() { + class Person { static a = 1 } + function test() { + print(Person.a); + } + test(); + } +} + +let p = new Person(); +p.foo();