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