/* * Copyright (c) 2023, Dan Klishch * * SPDX-License-Identifier: BSD-2-Clause */ #include #include "AST/AST.h" #include "Compiler/IfBranchMergingPass.h" namespace JSSpecCompiler { RecursionDecision IfBranchMergingPass::on_entry(Tree tree) { if (auto list = as(tree); list) { Vector result; Vector unmerged_branches; auto merge_if_needed = [&] { if (!unmerged_branches.is_empty()) { result.append(merge_branches(unmerged_branches)); unmerged_branches.clear(); } }; for (auto const& node : list->m_expressions) { if (is(node.ptr())) { merge_if_needed(); unmerged_branches.append(node); } else if (is(node.ptr())) { unmerged_branches.append(node); } else { merge_if_needed(); result.append(node); } } merge_if_needed(); list->m_expressions = move(result); } return RecursionDecision::Recurse; } Tree IfBranchMergingPass::merge_branches(Vector const& unmerged_branches) { static const Tree error = make_ref_counted("Cannot make sense of if-elseif-else chain"sv); VERIFY(unmerged_branches.size() >= 1); Vector conditions; Vector branches; NullableTree else_branch; if (auto if_branch = as(unmerged_branches[0]); if_branch) { conditions.append(if_branch->m_condition); branches.append(if_branch->m_branch); } else { return error; } for (size_t i = 1; i < unmerged_branches.size(); ++i) { auto branch = as(unmerged_branches[i]); if (!branch) return error; if (!branch->m_condition) { // There might be situation like: // 1. If , then // ... // 2. Else, // a. If , then // ... // 3. Else, // ... auto substep_list = as(branch->m_branch); if (substep_list && substep_list->m_expressions.size() == 1) { if (auto nested_if = as(substep_list->m_expressions[0]); nested_if) branch = make_ref_counted(nested_if->m_condition, nested_if->m_branch); } } if (branch->m_condition) { conditions.append(branch->m_condition.release_nonnull()); branches.append(branch->m_branch); } else { if (i + 1 != unmerged_branches.size()) return error; else_branch = branch->m_branch; } } return make_ref_counted(move(conditions), move(branches), else_branch); } }