• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ambientLowering.h"
17 #include <string_view>
18 
19 #include "ir/expressions/dummyNode.h"
20 #include "ir/astNode.h"
21 #include "compiler/lowering/util.h"
22 
23 namespace ark::es2panda::compiler {
Name() const24 std::string_view AmbientLowering::Name() const
25 {
26     static std::string const NAME = "AmbientLowering";
27     return NAME;
28 }
29 
PostconditionForModule(public_lib::Context * ctx,const parser::Program * program)30 bool AmbientLowering::PostconditionForModule([[maybe_unused]] public_lib::Context *ctx, const parser::Program *program)
31 {
32     return !program->Ast()->IsAnyChild(
33         [](const ir::AstNode *node) -> bool { return node->IsDummyNode() && node->AsDummyNode()->IsDeclareIndexer(); });
34 }
35 
PerformForModule(public_lib::Context * ctx,parser::Program * program)36 bool AmbientLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program)
37 {
38     // Generate $_get and $_set for ambient Indexer
39     program->Ast()->TransformChildrenRecursively(
40         // CC-OFFNXT(G.FMT.14-CPP) project code style
41         [this, ctx](ir::AstNode *ast) -> ir::AstNode * {
42             if (ast->IsClassDefinition()) {
43                 return CreateIndexerMethodIfNeeded(ast->AsClassDefinition(), ctx);
44             }
45             if (ast->IsTSInterfaceBody()) {
46                 return CreateIndexerMethodIfNeeded(ast->AsTSInterfaceBody(), ctx);
47             }
48             return ast;
49         },
50         Name());
51 
52     return true;
53 }
54 
CreateMethodFunctionDefinition(ir::DummyNode * node,public_lib::Context * ctx,ir::MethodDefinitionKind funcKind)55 ir::MethodDefinition *CreateMethodFunctionDefinition(ir::DummyNode *node, public_lib::Context *ctx,
56                                                      ir::MethodDefinitionKind funcKind)
57 {
58     auto parser = ctx->parser->AsETSParser();
59 
60     auto indexName = node->GetIndexName();
61     auto const returnType = node->GetReturnTypeLiteral()->AsETSTypeReferencePart()->GetIdent();
62     if (returnType->IsErrorPlaceHolder()) {
63         return nullptr;
64     }
65     if (indexName == ERROR_LITERAL) {
66         indexName = "_";
67     }
68     std::string sourceCode;
69     if (funcKind == ir::MethodDefinitionKind::GET) {
70         sourceCode = "$_get(" + std::string(indexName) + " : number) : " + std::string(returnType->Name());
71     } else if (funcKind == ir::MethodDefinitionKind::SET) {
72         sourceCode = "$_set(" + std::string(indexName) + " : number, " + "value : " + std::string(returnType->Name()) +
73                      " ) : void";
74     } else {
75         ES2PANDA_UNREACHABLE();
76     }
77 
78     auto methodDefinition = parser->CreateFormattedClassMethodDefinition(sourceCode);
79 
80     // NOTE(kaskov): #23399 It is temporary solution, we set default SourcePosition in all nodes in generated code
81     compiler::SetSourceRangesRecursively(methodDefinition, node->Range());
82 
83     methodDefinition->SetParent(node->Parent());
84     methodDefinition->AddModifier(ir::ModifierFlags::DECLARE);
85     ES2PANDA_ASSERT(methodDefinition->AsMethodDefinition()->Function() != nullptr);
86     methodDefinition->AsMethodDefinition()->Function()->AddModifier(ir::ModifierFlags::DECLARE);
87     return methodDefinition->AsMethodDefinition();
88 }
89 
CreateIndexerMethodIfNeeded(ir::AstNode * ast,public_lib::Context * ctx)90 ir::AstNode *AmbientLowering::CreateIndexerMethodIfNeeded(ir::AstNode *ast, public_lib::Context *ctx)
91 {
92     if (!ast->IsClassDefinition() && !ast->IsTSInterfaceBody()) {
93         return ast;
94     }
95 
96     ArenaVector<ir::AstNode *> &classBody =
97         ast->IsClassDefinition() ? ast->AsClassDefinition()->Body() : ast->AsTSInterfaceBody()->Body();
98 
99     auto it = classBody.begin();
100     // Only one DummyNode is allowed in classBody for now
101     ES2PANDA_ASSERT(
102         std::count_if(classBody.begin(), classBody.end(), [](ir::AstNode *node) { return node->IsDummyNode(); }) <= 1);
103     while (it != classBody.end()) {
104         if ((*it)->IsDummyNode() && (*it)->AsDummyNode()->IsDeclareIndexer()) {
105             auto setDefinition =
106                 CreateMethodFunctionDefinition((*it)->AsDummyNode(), ctx, ir::MethodDefinitionKind::SET);
107             auto getDefinition =
108                 CreateMethodFunctionDefinition((*it)->AsDummyNode(), ctx, ir::MethodDefinitionKind::GET);
109 
110             classBody.erase(it);
111             if (setDefinition != nullptr && getDefinition != nullptr) {
112                 classBody.emplace_back(getDefinition);
113                 classBody.emplace_back(setDefinition);
114             }
115             break;
116         }
117         ++it;
118     }
119 
120     return ast;
121 }
122 }  // namespace ark::es2panda::compiler
123