• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 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 
22 namespace ark::es2panda::compiler {
Name() const23 std::string_view AmbientLowering::Name() const
24 {
25     static std::string const NAME = "AmbientLowering";
26     return NAME;
27 }
28 
Postcondition(public_lib::Context * ctx,const parser::Program * program)29 bool AmbientLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program)
30 {
31     for (auto &[_, extPrograms] : program->ExternalSources()) {
32         (void)_;
33         for (auto *extProg : extPrograms) {
34             if (!Postcondition(ctx, extProg)) {
35                 return false;
36             }
37         }
38     }
39 
40     return !program->Ast()->IsAnyChild(
41         [](const ir::AstNode *node) -> bool { return node->IsDummyNode() && node->AsDummyNode()->IsDeclareIndexer(); });
42 }
43 
Perform(public_lib::Context * ctx,parser::Program * program)44 bool AmbientLowering::Perform(public_lib::Context *ctx, parser::Program *program)
45 {
46     for (auto &[_, extPrograms] : program->ExternalSources()) {
47         (void)_;
48         for (auto *extProg : extPrograms) {
49             Perform(ctx, extProg);
50         }
51     }
52 
53     // Generate $_get and $_set for ambient Indexer
54     program->Ast()->TransformChildrenRecursively(
55         // CC-OFFNXT(G.FMT.14-CPP) project code style
56         [this, ctx](ir::AstNode *ast) -> ir::AstNode * {
57             if (ast->IsClassDefinition()) {
58                 return CreateIndexerMethodIfNeeded(ast->AsClassDefinition(), ctx);
59             }
60             return ast;
61         },
62         Name());
63 
64     return true;
65 }
66 
CreateMethodFunctionDefinition(ir::DummyNode * node,public_lib::Context * ctx,ir::MethodDefinitionKind funcKind)67 ir::MethodDefinition *CreateMethodFunctionDefinition(ir::DummyNode *node, public_lib::Context *ctx,
68                                                      ir::MethodDefinitionKind funcKind)
69 {
70     auto parser = ctx->parser->AsETSParser();
71 
72     auto const indexName = node->GetIndexName();
73     auto const returnType = node->GetReturnTypeLiteral()->AsETSTypeReferencePart()->Name()->AsIdentifier()->Name();
74     std::string sourceCode;
75     if (funcKind == ir::MethodDefinitionKind::GET) {
76         sourceCode = "$_get(" + std::string(indexName) + " : number) : " + std::string(returnType);
77     } else if (funcKind == ir::MethodDefinitionKind::SET) {
78         sourceCode =
79             "$_set(" + std::string(indexName) + " : number, " + "value : " + std::string(returnType) + " ) : void";
80     } else {
81         UNREACHABLE();
82     }
83 
84     auto methodDefinition = parser->CreateFormattedClassMethodDefinition(sourceCode);
85 
86     methodDefinition->SetRange(node->Range());
87     methodDefinition->SetParent(node->Parent());
88     methodDefinition->AddModifier(ir::ModifierFlags::DECLARE);
89     methodDefinition->AsMethodDefinition()->Function()->AddModifier(ir::ModifierFlags::DECLARE);
90     return methodDefinition->AsMethodDefinition();
91 }
92 
CreateIndexerMethodIfNeeded(ir::ClassDefinition * classDef,public_lib::Context * ctx)93 ir::ClassDefinition *AmbientLowering::CreateIndexerMethodIfNeeded(ir::ClassDefinition *classDef,
94                                                                   public_lib::Context *ctx)
95 {
96     auto &classBody = classDef->Body();
97     auto it = classBody.begin();
98     // Only one DummyNode is allowed in classBody for now
99     ASSERT(std::count_if(classBody.begin(), classBody.end(), [](ir::AstNode *node) { return node->IsDummyNode(); }) <=
100            1);
101     while (it != classBody.end()) {
102         if ((*it)->IsDummyNode() && (*it)->AsDummyNode()->IsDeclareIndexer()) {
103             auto setDefinition =
104                 CreateMethodFunctionDefinition((*it)->AsDummyNode(), ctx, ir::MethodDefinitionKind::SET);
105             auto getDefinition =
106                 CreateMethodFunctionDefinition((*it)->AsDummyNode(), ctx, ir::MethodDefinitionKind::GET);
107 
108             classBody.erase(it);
109             classBody.emplace_back(setDefinition);
110             classBody.emplace_back(getDefinition);
111             break;
112         }
113         ++it;
114     }
115 
116     return classDef;
117 }
118 }  // namespace ark::es2panda::compiler
119