1 /*
2 * Copyright (c) 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 "defaultParametersLowering.h"
17 #include "compiler/lowering/util.h"
18
19 #include <checker/ETSchecker.h>
20
21 namespace ark::es2panda::compiler {
22
TransformInitializer(ArenaAllocator * allocator,parser::ETSParser * parser,ir::ETSParameterExpression * param)23 static ir::Statement *TransformInitializer(ArenaAllocator *allocator, parser::ETSParser *parser,
24 ir::ETSParameterExpression *param)
25 {
26 auto const ident = param->Ident();
27 auto const init = param->Initializer();
28 auto const typeAnnotation = param->TypeAnnotation();
29
30 param->SetIdent(Gensym(allocator));
31
32 param->Ident()->SetTsTypeAnnotation(typeAnnotation);
33 typeAnnotation->SetParent(param->Ident());
34
35 param->SetInitializer(nullptr);
36 ES2PANDA_ASSERT(param->IsOptional());
37
38 return parser->CreateFormattedStatement("let @@I1: @@T2 = (@@I3 !== undefined) ? @@I4 : (@@E5 as @@T6)", ident,
39 typeAnnotation->Clone(allocator, nullptr), param->Ident()->Name(),
40 param->Ident()->Name(), init, typeAnnotation->Clone(allocator, nullptr));
41 }
42
ValidateDefaultParamInDeclare(public_lib::Context * ctx,ir::ScriptFunction * function,std::vector<ir::ETSParameterExpression * > & params)43 static void ValidateDefaultParamInDeclare(public_lib::Context *ctx, ir::ScriptFunction *function,
44 std::vector<ir::ETSParameterExpression *> ¶ms)
45 {
46 for (auto param : params) {
47 if (param->Initializer() == nullptr) {
48 continue;
49 }
50 param->SetInitializer(nullptr);
51 if ((function->Flags() & ir::ScriptFunctionFlags::EXTERNAL) != 0U) {
52 ctx->checker->AsETSChecker()->LogError(diagnostic::DEFAULT_PARAM_IN_DECLARE, param->Start());
53 }
54 }
55 }
56
TransformFunction(public_lib::Context * ctx,ir::ScriptFunction * function)57 static void TransformFunction(public_lib::Context *ctx, ir::ScriptFunction *function)
58 {
59 auto const ¶ms = function->Params();
60 std::vector<ir::ETSParameterExpression *> defaultParams;
61
62 for (auto *param : params) {
63 if (!param->IsETSParameterExpression()) { // #23134
64 ES2PANDA_ASSERT(ctx->diagnosticEngine->IsAnyError());
65 continue;
66 }
67 if (param->AsETSParameterExpression()->Initializer() == nullptr) {
68 continue;
69 }
70 if (param->AsETSParameterExpression()->TypeAnnotation() == nullptr) { // #23134
71 ES2PANDA_ASSERT(ctx->diagnosticEngine->IsAnyError());
72 continue;
73 }
74 defaultParams.push_back(param->AsETSParameterExpression());
75 }
76
77 if (defaultParams.empty()) {
78 return;
79 }
80 if (!function->HasBody()) { // #23134
81 ValidateDefaultParamInDeclare(ctx, function, defaultParams);
82 return;
83 }
84 auto const body = function->Body()->AsBlockStatement();
85 auto const allocator = ctx->allocator;
86 auto const parser = ctx->parser->AsETSParser();
87
88 body->Statements().insert(body->Statements().begin(), defaultParams.size(), nullptr);
89
90 for (size_t dfltIdx = 0; dfltIdx < defaultParams.size(); ++dfltIdx) {
91 auto const param = defaultParams.at(dfltIdx);
92 auto stmt = TransformInitializer(allocator, parser, param);
93 body->Statements()[dfltIdx] = stmt;
94 // From a developer's perspective, this locational information is more intuitive.
95 stmt->SetParent(param);
96 RefineSourceRanges(stmt);
97 stmt->SetParent(body);
98 }
99 }
100
PerformForModule(public_lib::Context * ctx,parser::Program * program)101 bool DefaultParametersLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program)
102 {
103 program->Ast()->TransformChildrenRecursivelyPreorder(
104 // CC-OFFNXT(G.FMT.14-CPP) project code style
105 [ctx](ir::AstNode *const node) -> ir::AstNode * {
106 if (node->IsScriptFunction()) {
107 TransformFunction(ctx, node->AsScriptFunction());
108 }
109 return node;
110 },
111 Name());
112
113 return true;
114 }
115
PostconditionForModule(public_lib::Context * ctx,parser::Program const * program)116 bool DefaultParametersLowering::PostconditionForModule([[maybe_unused]] public_lib::Context *ctx,
117 parser::Program const *program)
118 {
119 return !program->Ast()->IsAnyChild([ctx](ir::AstNode const *node) {
120 if (!node->IsScriptFunction()) {
121 return false;
122 }
123 for (auto p : node->AsScriptFunction()->Params()) {
124 if (!p->IsETSParameterExpression()) { // #23134
125 ES2PANDA_ASSERT(ctx->diagnosticEngine->IsAnyError());
126 (void)ctx;
127 continue;
128 }
129 if (p->AsETSParameterExpression()->Initializer() != nullptr) {
130 return true;
131 }
132 }
133 return false;
134 });
135 }
136
137 } // namespace ark::es2panda::compiler
138