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 "parser/ETSparser.h"
28
29 namespace ark::es2panda::compiler {
ProcessIndexSetAccess(parser::ETSParser * parser,checker::ETSChecker * checker,ir::AssignmentExpression * assignmentExpression) const30 ir::Expression *ObjectIndexLowering::ProcessIndexSetAccess(parser::ETSParser *parser, checker::ETSChecker *checker,
31 ir::AssignmentExpression *assignmentExpression) const
32 {
33 // Note! We assume that parser and checker phase nave been already passed correctly, thus the class has
34 // required accessible index method[s] and all the types are properly resolved.
35 static std::string const CALL_EXPRESSION =
36 std::string {"@@E1."} + std::string {compiler::Signatures::SET_INDEX_METHOD} + "(@@E2, @@E3)";
37
38 // Parse ArkTS code string and create and process corresponding AST node(s)
39 auto *const memberExpression = assignmentExpression->Left()->AsMemberExpression();
40 auto *const loweringResult = parser->CreateFormattedExpression(
41 CALL_EXPRESSION, memberExpression->Object(), memberExpression->Property(), assignmentExpression->Right());
42 loweringResult->SetParent(assignmentExpression->Parent());
43
44 loweringResult->Check(checker);
45 return loweringResult;
46 }
47
ProcessIndexGetAccess(parser::ETSParser * parser,checker::ETSChecker * checker,ir::MemberExpression * memberExpression) const48 ir::Expression *ObjectIndexLowering::ProcessIndexGetAccess(parser::ETSParser *parser, checker::ETSChecker *checker,
49 ir::MemberExpression *memberExpression) const
50 {
51 // Note! We assume that parser and checker phase nave been already passed correctly, thus the class has
52 // required accessible index method[s] and all the types are properly resolved.
53 static std::string const CALL_EXPRESSION =
54 std::string {"@@E1."} + std::string {compiler::Signatures::GET_INDEX_METHOD} + "(@@E2)";
55
56 // Parse ArkTS code string and create and process corresponding AST node(s)
57 auto *const loweringResult =
58 parser->CreateFormattedExpression(CALL_EXPRESSION, memberExpression->Object(), memberExpression->Property());
59 loweringResult->SetParent(memberExpression->Parent());
60
61 loweringResult->Check(checker);
62 loweringResult->SetBoxingUnboxingFlags(memberExpression->GetBoxingUnboxingFlags());
63 return loweringResult;
64 }
65
Perform(public_lib::Context * ctx,parser::Program * program)66 bool ObjectIndexLowering::Perform(public_lib::Context *ctx, parser::Program *program)
67 {
68 if (ctx->config->options->CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB) {
69 for (auto &[_, extPrograms] : program->ExternalSources()) {
70 (void)_;
71 for (auto *extProg : extPrograms) {
72 Perform(ctx, extProg);
73 }
74 }
75 }
76
77 auto *const parser = ctx->parser->AsETSParser();
78 ASSERT(parser != nullptr);
79 auto *const checker = ctx->checker->AsETSChecker();
80 ASSERT(checker != nullptr);
81
82 program->Ast()->TransformChildrenRecursively(
83 [this, parser, checker](ir::AstNode *const ast) -> ir::AstNode * {
84 if (ast->IsAssignmentExpression() && ast->AsAssignmentExpression()->Left()->IsMemberExpression() &&
85 ast->AsAssignmentExpression()->Left()->AsMemberExpression()->Kind() ==
86 ir::MemberExpressionKind::ELEMENT_ACCESS) {
87 if (auto const *const objectType =
88 ast->AsAssignmentExpression()->Left()->AsMemberExpression()->ObjType();
89 objectType != nullptr && !objectType->IsETSDynamicType()) {
90 return ProcessIndexSetAccess(parser, checker, ast->AsAssignmentExpression());
91 }
92 }
93 return ast;
94 },
95 Name());
96
97 program->Ast()->TransformChildrenRecursively(
98 [this, parser, checker](ir::AstNode *const ast) -> ir::AstNode * {
99 if (ast->IsMemberExpression() &&
100 ast->AsMemberExpression()->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
101 if (auto const *const objectType = ast->AsMemberExpression()->ObjType();
102 objectType != nullptr && !objectType->IsETSDynamicType()) {
103 return ProcessIndexGetAccess(parser, checker, ast->AsMemberExpression());
104 }
105 }
106 return ast;
107 },
108 Name());
109
110 return true;
111 }
112
Postcondition(public_lib::Context * ctx,const parser::Program * program)113 bool ObjectIndexLowering::Postcondition(public_lib::Context *ctx, const parser::Program *program)
114 {
115 auto checkExternalPrograms = [this, ctx](const ArenaVector<parser::Program *> &programs) {
116 for (auto *p : programs) {
117 if (!Postcondition(ctx, p)) {
118 return false;
119 }
120 }
121 return true;
122 };
123
124 if (ctx->config->options->CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB) {
125 for (auto &[_, extPrograms] : program->ExternalSources()) {
126 (void)_;
127 if (!checkExternalPrograms(extPrograms)) {
128 return false;
129 };
130 }
131 }
132
133 return !program->Ast()->IsAnyChild([](const ir::AstNode *ast) {
134 if (ast->IsMemberExpression() &&
135 ast->AsMemberExpression()->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) {
136 if (auto const *const objectType = ast->AsMemberExpression()->ObjType(); objectType != nullptr) {
137 return !objectType->IsETSDynamicType();
138 }
139 }
140 return false;
141 });
142 }
143
144 } // namespace ark::es2panda::compiler
145