• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "spreadLowering.h"
17 #include "checker/ETSchecker.h"
18 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
19 #include "compiler/lowering/util.h"
20 #include "ir/expressions/literals/numberLiteral.h"
21 
22 namespace ark::es2panda::compiler {
23 
24 using AstNodePtr = ir::AstNode *;
25 
CreateLengthString(ir::ArrayExpression * array)26 std::string SpreadConstructionPhase::CreateLengthString(ir::ArrayExpression *array)
27 {
28     int spreadElementCount = 0;
29     std::stringstream lengthCalculationString;
30 
31     for (const auto *element : array->Elements()) {
32         if (element->Type() == ir::AstNodeType::SPREAD_ELEMENT) {
33             spreadElementCount++;
34             lengthCalculationString << element->AsSpreadElement()->Argument()->AsIdentifier()->Name() << ".length + ";
35         }
36     }
37 
38     lengthCalculationString << "0";
39     int newArrayLength = array->Elements().size() - spreadElementCount;
40     std::stringstream lengthString;
41     lengthString << "let length : int = " << newArrayLength << " + " << lengthCalculationString.str();
42 
43     return lengthString.str();
44 }
45 
CreateETSCode(ir::ArrayExpression * array,std::vector<ir::AstNode * > & node,public_lib::Context * ctx)46 std::string SpreadConstructionPhase::CreateETSCode(ir::ArrayExpression *array, std::vector<ir::AstNode *> &node,
47                                                    public_lib::Context *ctx)
48 {
49     std::stringstream src;
50     std::string lengthString = CreateLengthString(array);
51     std::string arrayType = array->TsType()->AsETSArrayType()->ElementType()->ToString();
52 
53     src.clear();
54     std::string newArrayName = "tempArrayVar";
55     src << lengthString << std::endl;
56     src << "type typeOfTempArray = " << arrayType << std::endl;
57     src << "let " << newArrayName << ": typeOfTempArray[] = new typeOfTempArray[length]" << std::endl;
58     src << "let newArrayIndex = 0" << std::endl;
59     size_t argumentCount = 1;
60 
61     for (std::uint32_t i = 0; i < array->Elements().size(); ++i) {
62         if (array->Elements()[i]->Type() == ir::AstNodeType::SPREAD_ELEMENT) {
63             std::string spreadArrayName =
64                 array->Elements()[i]->AsSpreadElement()->Argument()->AsIdentifier()->Name().Mutf8();
65             src << "let elementOfSpread" << i << ": " << array->Elements()[i]->TsType()->ToString() << std::endl;
66             src << "for (elementOfSpread" << i << " of " << spreadArrayName << ") {" << std::endl;
67             src << newArrayName << "[newArrayIndex] = "
68                 << "elementOfSpread" << i << std::endl;
69             src << "newArrayIndex++" << std::endl;
70             src << "}" << std::endl;
71         } else {
72             src << newArrayName << "[newArrayIndex] = "
73                 << "(@@E" << argumentCount << ")" << std::endl;
74             src << "newArrayIndex++" << std::endl;
75             argumentCount++;
76             node.emplace_back(array->Elements()[i]->Clone(ctx->allocator, nullptr));
77         }
78     }
79     src << newArrayName << ";" << std::endl;
80     std::cout << src.str() << std::endl;
81 
82     return src.str();
83 }
84 
Perform(public_lib::Context * ctx,parser::Program * program)85 bool SpreadConstructionPhase::Perform(public_lib::Context *ctx, parser::Program *program)
86 {
87     for (auto &[_, ext_programs] : program->ExternalSources()) {
88         (void)_;
89         for (auto *extProg : ext_programs) {
90             Perform(ctx, extProg);
91         }
92     }
93 
94     auto *const parser = ctx->parser->AsETSParser();
95     checker::ETSChecker *const checker = ctx->checker->AsETSChecker();
96 
97     program->Ast()->TransformChildrenRecursively(
98         [&parser, &checker, &ctx, this](ir::AstNode *const node) -> AstNodePtr {
99             if (node->IsArrayExpression() &&
100                 std::any_of(node->AsArrayExpression()->Elements().begin(), node->AsArrayExpression()->Elements().end(),
101                             [](const auto *param) { return param->Type() == ir::AstNodeType::SPREAD_ELEMENT; })) {
102                 auto scopeCtx =
103                     varbinder::LexicalScope<varbinder::Scope>::Enter(checker->VarBinder(), NearestScope(node));
104                 std::vector<ir::AstNode *> normalElements {};
105                 std::string src = CreateETSCode(node->AsArrayExpression(), normalElements, ctx);
106 
107                 ir::BlockExpression *blockExpression =
108                     parser->CreateFormattedExpression(src, normalElements)->AsBlockExpression();
109                 blockExpression->SetParent(node->Parent());
110                 InitScopesPhaseETS::RunExternalNode(blockExpression, checker->VarBinder());
111                 checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(blockExpression,
112                                                                                NearestScope(blockExpression));
113                 blockExpression->Check(checker);
114 
115                 return blockExpression;
116             }
117 
118             return node;
119         },
120         Name());
121     return true;
122 }
123 
Postcondition(public_lib::Context * ctx,const parser::Program * program)124 bool SpreadConstructionPhase::Postcondition(public_lib::Context *ctx, const parser::Program *program)
125 {
126     for (auto &[_, ext_programs] : program->ExternalSources()) {
127         (void)_;
128         for (auto *extProg : ext_programs) {
129             if (!Postcondition(ctx, extProg)) {
130                 return false;
131             }
132         }
133     }
134     return true;
135 }
136 
137 }  // namespace ark::es2panda::compiler
138