• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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