• 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 "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