1 /*
2 * Copyright (c) 2021-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 //
17 // desc: Object index access syntax is translated to the call of special setter (in case of assignment):
18 // "obj[i] = val; => obj.S_set(i, val);"
19 // or getter (in all the other cases):
20 // "...obj[i]... => ...obj.S_get(i)..."
21 // methods.
22 //
23
24 #include "objectIndexAccess.h"
25
26 #include "checker/ETSchecker.h"
27 #include "compiler/lowering/util.h"
28 #include "parser/ETSparser.h"
29
30 namespace ark::es2panda::compiler {
ProcessIndexSetAccess(parser::ETSParser * parser,checker::ETSChecker * checker,ir::AssignmentExpression * assignmentExpression) const31 ir::Expression *ObjectIndexLowering::ProcessIndexSetAccess(parser::ETSParser *parser, checker::ETSChecker *checker,
32 ir::AssignmentExpression *assignmentExpression) const
33 {
34 // Note! We assume that parser and checker phase nave been already passed correctly, thus the class has
35 // required accessible index method[s] and all the types are properly resolved.
36 static std::string const CALL_EXPRESSION =
37 std::string {"@@E1."} + std::string {compiler::Signatures::SET_INDEX_METHOD} + "(@@E2, @@E3)";
38
39 // Parse ArkTS code string and create and process corresponding AST node(s)
40 auto *const memberExpression = assignmentExpression->Left()->AsMemberExpression();
41 auto *const loweringResult = parser->CreateFormattedExpression(
42 CALL_EXPRESSION, memberExpression->Object(), memberExpression->Property(), assignmentExpression->Right());
43 loweringResult->SetParent(assignmentExpression->Parent());
44 loweringResult->SetRange(assignmentExpression->Range());
45
46 CheckLoweredNode(checker->VarBinder()->AsETSBinder(), checker, loweringResult);
47 return loweringResult;
48 }
49
ProcessIndexGetAccess(parser::ETSParser * parser,checker::ETSChecker * checker,ir::MemberExpression * memberExpression) const50 ir::Expression *ObjectIndexLowering::ProcessIndexGetAccess(parser::ETSParser *parser, checker::ETSChecker *checker,
51 ir::MemberExpression *memberExpression) const
52 {
53 // Note! We assume that parser and checker phase nave been already passed correctly, thus the class has
54 // required accessible index method[s] and all the types are properly resolved.
55 static std::string const CALL_EXPRESSION =
56 std::string {"@@E1."} + std::string {compiler::Signatures::GET_INDEX_METHOD} + "(@@E2)";
57
58 // Parse ArkTS code string and create and process corresponding AST node(s)
59 auto *const loweringResult =
60 parser->CreateFormattedExpression(CALL_EXPRESSION, memberExpression->Object(), memberExpression->Property());
61 loweringResult->SetParent(memberExpression->Parent());
62 loweringResult->SetRange(memberExpression->Range());
63
64 CheckLoweredNode(checker->VarBinder()->AsETSBinder(), checker, loweringResult);
65 loweringResult->SetBoxingUnboxingFlags(memberExpression->GetBoxingUnboxingFlags());
66 return loweringResult;
67 }
68
Perform(public_lib::Context * ctx,parser::Program * program)69 bool ObjectIndexLowering::Perform(public_lib::Context *ctx, parser::Program *program)
70 {
71 if (ctx->config->options->CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB) {
72 for (auto &[_, extPrograms] : program->ExternalSources()) {
73 (void)_;
74 for (auto *extProg : extPrograms) {
75 Perform(ctx, extProg);
76 }
77 }
78 }
79
80 auto *const parser = ctx->parser->AsETSParser();
81 ASSERT(parser != nullptr);
82 auto *const checker = ctx->checker->AsETSChecker();
83 ASSERT(checker != nullptr);
84
85 program->Ast()->TransformChildrenRecursively(
86 // CC-OFFNXT(G.FMT.14-CPP) project code style
87 [this, parser, checker](ir::AstNode *const ast) -> ir::AstNode * {
88 if (ast->IsAssignmentExpression() && ast->AsAssignmentExpression()->Left()->IsMemberExpression() &&
89 ast->AsAssignmentExpression()->Left()->AsMemberExpression()->Kind() ==
90 ir::MemberExpressionKind::ELEMENT_ACCESS) {
91 if (auto const *const objectType =
92 ast->AsAssignmentExpression()->Left()->AsMemberExpression()->ObjType();
93 objectType != nullptr && !objectType->IsETSDynamicType()) {
94 return ProcessIndexSetAccess(parser, checker, ast->AsAssignmentExpression());
95 }
96 }
97 return ast;
98 },
99 Name());
100
101 program->Ast()->TransformChildrenRecursively(
102 // CC-OFFNXT(G.FMT.14-CPP) project code style
103 [this, parser, checker](ir::AstNode *const ast) -> ir::AstNode * {
104 if (ast->IsMemberExpression() &&
105 ast->AsMemberExpression()->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
106 if (auto const *const objectType = ast->AsMemberExpression()->ObjType();
107 objectType != nullptr && !objectType->IsETSDynamicType()) {
108 return ProcessIndexGetAccess(parser, checker, ast->AsMemberExpression());
109 }
110 }
111 return ast;
112 },
113 Name());
114
115 return true;
116 }
117
Postcondition(public_lib::Context * ctx,const parser::Program * program)118 bool ObjectIndexLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program)
119 {
120 auto checkExternalPrograms = [this, ctx](const ArenaVector<parser::Program *> &programs) {
121 for (auto *p : programs) {
122 if (!Postcondition(ctx, p)) {
123 return false;
124 }
125 }
126 return true;
127 };
128
129 if (ctx->config->options->CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB) {
130 for (auto &[_, extPrograms] : program->ExternalSources()) {
131 (void)_;
132 if (!checkExternalPrograms(extPrograms)) {
133 return false;
134 };
135 }
136 }
137
138 return !program->Ast()->IsAnyChild([](const ir::AstNode *ast) {
139 if (ast->IsMemberExpression() &&
140 ast->AsMemberExpression()->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
141 if (auto const *const objectType = ast->AsMemberExpression()->ObjType(); objectType != nullptr) {
142 return !objectType->IsETSDynamicType();
143 }
144 }
145 return false;
146 });
147 }
148
149 } // namespace ark::es2panda::compiler
150