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