• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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 #include "expandBrackets.h"
17 
18 #include "checker/ETSchecker.h"
19 #include "compiler/lowering/util.h"
20 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
21 
22 namespace ark::es2panda::compiler {
23 
24 // NOLINTBEGIN(modernize-avoid-c-arrays)
25 static constexpr char const FORMAT_NEW_MULTI_DIM_ARRAY_EXPRESSION[] =
26     "let @@I1: @@T2 = (@@E3);"
27     "if (!isSafeInteger(@@I4)) {"
28     "  throw new TypeError(\"Fractional part of index expression should be zero.\");"
29     "};";
30 static constexpr char const FORMAT_NEW_ARRAY_EXPRESSION[] =
31     "let @@I1: @@T2 = (@@E3);"
32     "if (!isSafeInteger(@@I4)) {"
33     "  throw new TypeError(\"Fractional part of index expression should be zero.\");"
34     "};"
35     "(@@E5);";
36 static constexpr char const CAST_NEW_DIMENSION_EXPRESSION[] = "@@I1 as int";
37 static constexpr char const CAST_OLD_DIMENSION_EXPRESSION[] = "(@@E1) as int";
38 // NOLINTEND(modernize-avoid-c-arrays)
39 
ProcessNewArrayInstanceExpression(public_lib::Context * ctx,ir::ETSNewArrayInstanceExpression * newInstanceExpression) const40 ir::Expression *ExpandBracketsPhase::ProcessNewArrayInstanceExpression(
41     public_lib::Context *ctx, ir::ETSNewArrayInstanceExpression *newInstanceExpression) const
42 {
43     auto *const parser = ctx->parser->AsETSParser();
44     ES2PANDA_ASSERT(parser != nullptr);
45     auto *const checker = ctx->checker->AsETSChecker();
46     ES2PANDA_ASSERT(checker != nullptr);
47     auto *dimension = newInstanceExpression->Dimension();
48     auto *dimType = dimension->TsType();
49     if (auto *unboxed = checker->MaybeUnboxInRelation(dimType); unboxed != nullptr) {
50         dimType = unboxed;
51     }
52     if (dimType == nullptr || !dimType->HasTypeFlag(checker::TypeFlag::ETS_FLOATING_POINT)) {
53         return newInstanceExpression;
54     }
55 
56     auto *scope = NearestScope(newInstanceExpression);
57     if (scope == nullptr) {
58         scope = checker->VarBinder()->VarScope() != nullptr ? checker->VarBinder()->VarScope()
59                                                             : checker->VarBinder()->TopScope();
60     }
61     auto expressionCtx = varbinder::LexicalScope<varbinder::Scope>::Enter(checker->VarBinder(), scope);
62 
63     auto const identName = GenName(ctx->Allocator());
64     auto *exprType = ctx->AllocNode<ir::OpaqueTypeNode>(dimType, ctx->Allocator());
65     auto *const newInstanceParent = newInstanceExpression->Parent();
66 
67     auto *blockExpression = parser->CreateFormattedExpression(FORMAT_NEW_ARRAY_EXPRESSION, identName, exprType,
68                                                               dimension, identName, newInstanceExpression);
69     blockExpression->SetParent(newInstanceParent);
70 
71     auto *castedDimension = parser->CreateFormattedExpression(CAST_NEW_DIMENSION_EXPRESSION, identName);
72     newInstanceExpression->SetDimension(castedDimension);
73 
74     newInstanceExpression->SetTsType(nullptr);
75     InitScopesPhaseETS::RunExternalNode(blockExpression, checker->VarBinder());
76     checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(blockExpression, NearestScope(blockExpression));
77     blockExpression->Check(checker);
78 
79     return blockExpression;
80 }
81 
ProcessNewMultiDimArrayInstanceExpression(public_lib::Context * ctx,ir::ETSNewMultiDimArrayInstanceExpression * newInstanceExpression) const82 ir::Expression *ExpandBracketsPhase::ProcessNewMultiDimArrayInstanceExpression(
83     public_lib::Context *ctx, ir::ETSNewMultiDimArrayInstanceExpression *newInstanceExpression) const
84 {
85     auto *const parser = ctx->parser->AsETSParser();
86     ES2PANDA_ASSERT(parser != nullptr);
87     auto *const checker = ctx->checker->AsETSChecker();
88     ES2PANDA_ASSERT(checker != nullptr);
89     ir::BlockExpression *returnExpression = nullptr;
90 
91     auto *scope = NearestScope(newInstanceExpression);
92     if (scope == nullptr) {
93         scope = checker->VarBinder()->VarScope() != nullptr ? checker->VarBinder()->VarScope()
94                                                             : checker->VarBinder()->TopScope();
95     }
96     auto expressionCtx = varbinder::LexicalScope<varbinder::Scope>::Enter(checker->VarBinder(), scope);
97 
98     for (std::size_t i = 0U; i < newInstanceExpression->Dimensions().size(); ++i) {
99         auto *dimension = newInstanceExpression->Dimensions()[i];
100         auto *dimType = dimension->TsType();
101         if (auto *unboxed = checker->MaybeUnboxInRelation(dimType); unboxed != nullptr) {
102             dimType = unboxed;
103         }
104         if (dimType == nullptr || !dimType->HasTypeFlag(checker::TypeFlag::ETS_FLOATING_POINT)) {
105             continue;
106         }
107 
108         if (dimension->IsNumberLiteral()) {
109             auto *castedDimension = parser->CreateFormattedExpression(CAST_OLD_DIMENSION_EXPRESSION, dimension);
110             castedDimension->SetParent(newInstanceExpression);
111             newInstanceExpression->Dimensions()[i] = castedDimension;
112         } else {
113             auto const identName = GenName(ctx->Allocator());
114             auto *exprType = ctx->AllocNode<ir::OpaqueTypeNode>(dimType, ctx->Allocator());
115 
116             auto *blockExpression = parser
117                                         ->CreateFormattedExpression(FORMAT_NEW_MULTI_DIM_ARRAY_EXPRESSION, identName,
118                                                                     exprType, dimension, identName)
119                                         ->AsBlockExpression();
120 
121             if (returnExpression == nullptr) {
122                 returnExpression = blockExpression;
123             } else {
124                 returnExpression->AddStatements(blockExpression->Statements());
125             }
126 
127             auto *castedDimension = parser->CreateFormattedExpression(CAST_NEW_DIMENSION_EXPRESSION, identName);
128             castedDimension->SetParent(newInstanceExpression);
129             newInstanceExpression->Dimensions()[i] = castedDimension;
130         }
131     }
132 
133     if (returnExpression != nullptr) {
134         return CreateNewMultiDimArrayInstanceExpression(ctx, newInstanceExpression, returnExpression);
135     }
136 
137     return newInstanceExpression;
138 }
139 
140 //  NOTE: Just to reduce the size of 'ProcessNewMultiDimArrayInstanceExpression' method
CreateNewMultiDimArrayInstanceExpression(public_lib::Context * ctx,ir::ETSNewMultiDimArrayInstanceExpression * newInstanceExpression,ir::BlockExpression * blockExpression) const141 ir::Expression *ExpandBracketsPhase::CreateNewMultiDimArrayInstanceExpression(
142     public_lib::Context *ctx, ir::ETSNewMultiDimArrayInstanceExpression *newInstanceExpression,
143     ir::BlockExpression *blockExpression) const
144 {
145     blockExpression->SetParent(newInstanceExpression->Parent());
146     newInstanceExpression->SetTsType(nullptr);
147     blockExpression->AddStatement(ctx->AllocNode<ir::ExpressionStatement>(newInstanceExpression));
148 
149     auto *checker = ctx->checker->AsETSChecker();
150     InitScopesPhaseETS::RunExternalNode(blockExpression, checker->VarBinder());
151     checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(blockExpression, NearestScope(blockExpression));
152     blockExpression->Check(checker);
153 
154     return blockExpression;
155 }
156 
PerformForModule(public_lib::Context * ctx,parser::Program * program)157 bool ExpandBracketsPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program)
158 {
159     program->Ast()->TransformChildrenRecursively(
160         [this, ctx](checker::AstNodePtr const ast) -> checker::AstNodePtr {
161             if (ast->IsETSNewArrayInstanceExpression()) {
162                 return ProcessNewArrayInstanceExpression(ctx, ast->AsETSNewArrayInstanceExpression());
163             }
164 
165             if (ast->IsETSNewMultiDimArrayInstanceExpression()) {
166                 return ProcessNewMultiDimArrayInstanceExpression(ctx, ast->AsETSNewMultiDimArrayInstanceExpression());
167             }
168 
169             return ast;
170         },
171         Name());
172 
173     return true;
174 }
175 
176 }  // namespace ark::es2panda::compiler
177