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 "setJumpTarget.h"
17 #include "checker/types/globalTypesHolder.h"
18 #include "compiler/lowering/util.h"
19
20 namespace ark::es2panda::compiler {
21
LogError(const public_lib::Context * ctx,const diagnostic::DiagnosticKind & diagnostic,const util::DiagnosticMessageParams & diagnosticParams,const lexer::SourcePosition & pos)22 void SetJumpTargetPhase::LogError(const public_lib::Context *ctx, const diagnostic::DiagnosticKind &diagnostic,
23 const util::DiagnosticMessageParams &diagnosticParams,
24 const lexer::SourcePosition &pos)
25 {
26 ctx->diagnosticEngine->LogDiagnostic(diagnostic, diagnosticParams, pos);
27 }
28
SetTarget(ir::AstNode * const node,ir::AstNode * const target)29 static void SetTarget(ir::AstNode *const node, ir::AstNode *const target)
30 {
31 if (node->IsContinueStatement()) {
32 node->AsContinueStatement()->SetTarget(target);
33 } else {
34 ES2PANDA_ASSERT(node->IsBreakStatement());
35 node->AsBreakStatement()->SetTarget(target);
36 }
37 }
38
FindJumpTarget(const public_lib::Context * ctx,ir::AstNode * const node)39 void SetJumpTargetPhase::FindJumpTarget(const public_lib::Context *ctx, ir::AstNode *const node)
40 {
41 // Look for label
42 bool isContinue = node->IsContinueStatement();
43 auto label = isContinue ? node->AsContinueStatement()->Ident() : node->AsBreakStatement()->Ident();
44 if (label != nullptr) {
45 if (auto var = label->Variable(); var == nullptr) {
46 varbinder::LetDecl *decl;
47 auto *varbinder = ctx->parserProgram->VarBinder()->AsETSBinder();
48 std::tie(decl, var) = varbinder->NewVarDecl<varbinder::LetDecl>(
49 label->Start(),
50 !label->IsErrorPlaceHolder() ? label->Name() : compiler::GenName(ctx->allocator).View());
51 var->SetScope(varbinder->GetScope());
52 label->SetVariable(var);
53 decl->BindNode(label);
54 label->SetTsType(var->SetTsType(ctx->checker->GetGlobalTypesHolder()->GlobalTypeError()));
55 } else if (var->Declaration()->IsLabelDecl()) {
56 SetTarget(node, var->Declaration()->Node());
57 return;
58 }
59
60 // Failed to resolve variable for label
61 if (!label->IsErrorPlaceHolder()) {
62 LogError(ctx, diagnostic::UNRESOLVED_REF, {label->Name()}, label->Start());
63 }
64
65 SetTarget(node, nullptr);
66 return;
67 }
68
69 // No label, find the nearest loop or switch statement
70 auto *target = node->Parent();
71 while (target != nullptr) {
72 switch (target->Type()) {
73 case ir::AstNodeType::SWITCH_STATEMENT: {
74 if (isContinue) {
75 break;
76 }
77 [[fallthrough]];
78 }
79 case ir::AstNodeType::DO_WHILE_STATEMENT:
80 case ir::AstNodeType::WHILE_STATEMENT:
81 case ir::AstNodeType::FOR_UPDATE_STATEMENT:
82 case ir::AstNodeType::FOR_OF_STATEMENT: {
83 SetTarget(node, target);
84 return;
85 }
86 default: {
87 break;
88 }
89 }
90
91 target = target->Parent();
92 }
93
94 LogError(ctx, diagnostic::FLOW_REDIRECTION_INVALID_CTX, {}, node->Start());
95 SetTarget(node, nullptr);
96 }
97
Perform(public_lib::Context * ctx,parser::Program * program)98 bool SetJumpTargetPhase::Perform(public_lib::Context *ctx, parser::Program *program)
99 {
100 for (auto &[_, ext_programs] : program->ExternalSources()) {
101 (void)_;
102 for (auto *extProg : ext_programs) {
103 Perform(ctx, extProg);
104 }
105 }
106
107 program->Ast()->IterateRecursivelyPostorder([&](ir::AstNode *const node) -> void {
108 if (node->IsBreakStatement() || node->IsContinueStatement()) {
109 FindJumpTarget(ctx, node);
110 }
111 });
112
113 return true;
114 }
115
116 } // namespace ark::es2panda::compiler
117