• 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 "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