Files
carbon-lang/toolchain/check/handle_loop_statement.cpp
T
Jon Ross-Perkins 99696b9812 Rename check handlers to HandleParseNode overloads. (#4121)
This is for consistency with #4120. Similar to that, we can use
overloads on the typed NodeId rather than individually named handlers.
There isn't the same caller benefit here though, since the calls from
check.cpp are already boilerplate.
2024-07-12 22:38:06 +00:00

143 lines
4.4 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/check/handle.h"
namespace Carbon::Check {
// `while`
// -------
auto HandleParseNode(Context& context, Parse::WhileConditionStartId node_id)
-> bool {
// Branch to the loop header block. Note that we create a new block here even
// if the current block is empty; this ensures that the loop always has a
// preheader block.
auto loop_header_id = context.AddDominatedBlockAndBranch(node_id);
context.inst_block_stack().Pop();
// Start emitting the loop header block.
context.inst_block_stack().Push(loop_header_id);
context.AddCurrentCodeBlockToFunction();
context.node_stack().Push(node_id, loop_header_id);
return true;
}
auto HandleParseNode(Context& context, Parse::WhileConditionId node_id)
-> bool {
auto cond_value_id = context.node_stack().PopExpr();
auto loop_header_id =
context.node_stack().Peek<Parse::NodeKind::WhileConditionStart>();
cond_value_id = ConvertToBoolValue(context, node_id, cond_value_id);
// Branch to either the loop body or the loop exit block.
auto loop_body_id =
context.AddDominatedBlockAndBranchIf(node_id, cond_value_id);
auto loop_exit_id = context.AddDominatedBlockAndBranch(node_id);
context.inst_block_stack().Pop();
// Start emitting the loop body.
context.inst_block_stack().Push(loop_body_id);
context.AddCurrentCodeBlockToFunction();
context.break_continue_stack().push_back(
{.break_target = loop_exit_id, .continue_target = loop_header_id});
context.node_stack().Push(node_id, loop_exit_id);
return true;
}
auto HandleParseNode(Context& context, Parse::WhileStatementId node_id)
-> bool {
auto loop_exit_id =
context.node_stack().Pop<Parse::NodeKind::WhileCondition>();
auto loop_header_id =
context.node_stack().Pop<Parse::NodeKind::WhileConditionStart>();
context.break_continue_stack().pop_back();
// Add the loop backedge.
context.AddInst<SemIR::Branch>(node_id, {.target_id = loop_header_id});
context.inst_block_stack().Pop();
// Start emitting the loop exit block.
context.inst_block_stack().Push(loop_exit_id);
context.AddCurrentCodeBlockToFunction();
return true;
}
// `for`
// -----
auto HandleParseNode(Context& context, Parse::ForHeaderStartId node_id)
-> bool {
return context.TODO(node_id, "HandleForHeaderStart");
}
auto HandleParseNode(Context& context, Parse::ForInId node_id) -> bool {
context.decl_introducer_state_stack().Pop<Lex::TokenKind::Var>();
return context.TODO(node_id, "HandleForIn");
}
auto HandleParseNode(Context& context, Parse::ForHeaderId node_id) -> bool {
return context.TODO(node_id, "HandleForHeader");
}
auto HandleParseNode(Context& context, Parse::ForStatementId node_id) -> bool {
return context.TODO(node_id, "HandleForStatement");
}
// `break`
// -------
auto HandleParseNode(Context& context, Parse::BreakStatementStartId node_id)
-> bool {
auto& stack = context.break_continue_stack();
if (stack.empty()) {
CARBON_DIAGNOSTIC(BreakOutsideLoop, Error,
"`break` can only be used in a loop.");
context.emitter().Emit(node_id, BreakOutsideLoop);
} else {
context.AddInst<SemIR::Branch>(node_id,
{.target_id = stack.back().break_target});
}
context.inst_block_stack().Pop();
context.inst_block_stack().PushUnreachable();
return true;
}
auto HandleParseNode(Context& /*context*/, Parse::BreakStatementId /*node_id*/)
-> bool {
return true;
}
// `continue`
// ----------
auto HandleParseNode(Context& context, Parse::ContinueStatementStartId node_id)
-> bool {
auto& stack = context.break_continue_stack();
if (stack.empty()) {
CARBON_DIAGNOSTIC(ContinueOutsideLoop, Error,
"`continue` can only be used in a loop.");
context.emitter().Emit(node_id, ContinueOutsideLoop);
} else {
context.AddInst<SemIR::Branch>(node_id,
{.target_id = stack.back().continue_target});
}
context.inst_block_stack().Pop();
context.inst_block_stack().PushUnreachable();
return true;
}
auto HandleParseNode(Context& /*context*/,
Parse::ContinueStatementId /*node_id*/) -> bool {
return true;
}
} // namespace Carbon::Check