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()->IsAmbientIndexer(); });
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 [this, ctx](ir::AstNode *ast) -> ir::AstNode * {
56 if (ast->IsClassDefinition()) {
57 return CreateIndexerMethodIfNeeded(ast->AsClassDefinition(), ctx);
58 }
59 return ast;
60 },
61 Name());
62
63 return true;
64 }
65
CreateMethodFunctionDefinition(ir::DummyNode *node, public_lib::Context *ctx, ir::MethodDefinitionKind funcKind)66 ir::MethodDefinition *CreateMethodFunctionDefinition(ir::DummyNode *node, public_lib::Context *ctx,
67 ir::MethodDefinitionKind funcKind)
68 {
69 auto parser = ctx->parser->AsETSParser();
70
71 auto const indexName = node->GetIndexName();
72 auto const returnType = node->GetReturnTypeLiteral()->AsETSTypeReferencePart()->Name()->AsIdentifier()->Name();
73 std::string sourceCode;
74 if (funcKind == ir::MethodDefinitionKind::GET) {
75 sourceCode = "$_get(" + std::string(indexName) + " : number) : " + std::string(returnType);
76 } else if (funcKind == ir::MethodDefinitionKind::SET) {
77 sourceCode =
78 "$_set(" + std::string(indexName) + " : number, " + "value : " + std::string(returnType) + " ) : void";
79 } else {
80 UNREACHABLE();
81 }
82
83 auto methodDefinition = parser->CreateFormattedClassMethodDefinition(sourceCode);
84
85 methodDefinition->SetRange(node->Range());
86 methodDefinition->SetParent(node->Parent());
87 methodDefinition->AddModifier(ir::ModifierFlags::DECLARE);
88 return methodDefinition->AsMethodDefinition();
89 }
90
CreateIndexerMethodIfNeeded(ir::ClassDefinition *classDef, public_lib::Context *ctx)91 ir::ClassDefinition *AmbientLowering::CreateIndexerMethodIfNeeded(ir::ClassDefinition *classDef,
92 public_lib::Context *ctx)
93 {
94 auto &classBody = classDef->Body();
95 auto it = classBody.begin();
96 // Only one DummyNode is allowed in classBody for now
97 ASSERT(std::count_if(classBody.begin(), classBody.end(), [](ir::AstNode *node) { return node->IsDummyNode(); }) <=
98 1);
99 while (it != classBody.end()) {
100 if ((*it)->IsDummyNode() && (*it)->AsDummyNode()->IsAmbientIndexer()) {
101 auto setDefinition =
102 CreateMethodFunctionDefinition((*it)->AsDummyNode(), ctx, ir::MethodDefinitionKind::SET);
103 auto getDefinition =
104 CreateMethodFunctionDefinition((*it)->AsDummyNode(), ctx, ir::MethodDefinitionKind::GET);
105
106 classBody.erase(it);
107 classBody.emplace_back(setDefinition);
108 classBody.emplace_back(getDefinition);
109 break;
110 }
111 ++it;
112 }
113
114 return classDef;
115 }
116 } // namespace ark::es2panda::compiler
117