• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *> &params)
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 &params = 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