use core::ops::ControlFlow;
use crate::{
BaseHost, BreakReason, MapExecErr, ONE, Stopper, ZERO,
continuation_stack::Continuation,
execution::{ExecutionState, finalize_clock_cycle, finalize_clock_cycle_with_continuation},
mast::{ExecutableMastForest, LoopNode, MastNodeId},
operation::{BinaryValueErrorContext, OperationError},
option_map_break_reason,
processor::{Processor, StackInterface},
tracer::Tracer,
};
#[inline(always)]
pub(super) fn start_loop_node<P, H, S, T, F>(
state: &mut ExecutionState<'_, P, H, S, T, F>,
loop_node: &LoopNode,
current_node_id: MastNodeId,
current_forest: &F,
) -> ControlFlow<BreakReason<F>>
where
P: Processor,
H: BaseHost,
S: Stopper<Processor = P, Forest = F>,
T: Tracer<Processor = P, Forest = F>,
F: ExecutableMastForest + Clone,
{
state.tracer.start_clock_cycle(
state.processor,
Continuation::StartNode(current_node_id),
state.continuation_stack,
current_forest,
);
let body_source_node_id = match state.child_source_node_id(0) {
Ok(source_node_id) => source_node_id,
Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
};
state.continuation_stack.push_with_source_node_id(
Continuation::FinishLoop(current_node_id),
state.current_source_node_id(),
);
state
.continuation_stack
.push_with_source_node_id(Continuation::StartNode(loop_node.body()), body_source_node_id);
finalize_clock_cycle(
state.processor,
state.tracer,
state.stopper,
state.continuation_stack,
current_forest,
)
}
#[inline(always)]
pub(super) fn start_loop_node_pure<P, H, S, T, F>(
state: &mut ExecutionState<'_, P, H, S, T, F>,
loop_node: &LoopNode,
current_node_id: MastNodeId,
current_forest: &F,
) -> ControlFlow<BreakReason<F>>
where
P: Processor,
H: BaseHost,
S: Stopper<Processor = P, Forest = F>,
T: Tracer<Processor = P, Forest = F>,
F: ExecutableMastForest + Clone,
{
state.tracer.start_clock_cycle(
state.processor,
Continuation::StartNode(current_node_id),
state.continuation_stack,
current_forest,
);
state.continuation_stack.push_finish_loop(current_node_id);
state.continuation_stack.push_start_node(loop_node.body());
finalize_clock_cycle(
state.processor,
state.tracer,
state.stopper,
state.continuation_stack,
current_forest,
)
}
#[inline(always)]
pub(super) fn finish_loop_node<P, H, S, T, F>(
state: &mut ExecutionState<'_, P, H, S, T, F>,
current_node_id: MastNodeId,
current_forest: &F,
) -> ControlFlow<BreakReason<F>>
where
P: Processor,
H: BaseHost,
S: Stopper<Processor = P, Forest = F>,
T: Tracer<Processor = P, Forest = F>,
F: ExecutableMastForest + Clone,
{
let condition = state.processor.stack().get(0);
let loop_node = option_map_break_reason(
current_forest.get_node_by_id(current_node_id),
"loop node not found in current forest",
)?
.unwrap_loop();
if condition == ONE {
state.tracer.start_clock_cycle(
state.processor,
Continuation::FinishLoop(current_node_id),
state.continuation_stack,
current_forest,
);
if let Err(err) = state.processor.stack_mut().decrement_size().map_exec_err() {
return ControlFlow::Break(BreakReason::Err(err));
}
let body_source_node_id = match state.child_source_node_id(0) {
Ok(source_node_id) => source_node_id,
Err(err) => return ControlFlow::Break(BreakReason::Err(err)),
};
state.continuation_stack.push_with_source_node_id(
Continuation::FinishLoop(current_node_id),
state.current_source_node_id(),
);
state.continuation_stack.push_with_source_node_id(
Continuation::StartNode(loop_node.body()),
body_source_node_id,
);
finalize_clock_cycle(
state.processor,
state.tracer,
state.stopper,
state.continuation_stack,
current_forest,
)
} else if condition == ZERO {
state.tracer.start_clock_cycle(
state.processor,
Continuation::FinishLoop(current_node_id),
state.continuation_stack,
current_forest,
);
if let Err(err) = state.processor.stack_mut().decrement_size().map_exec_err() {
return ControlFlow::Break(BreakReason::Err(err));
}
finalize_clock_cycle_with_continuation(
state.processor,
state.tracer,
state.stopper,
state.continuation_stack,
|| None,
current_forest,
)
} else {
let err = OperationError::NotBinaryValue {
context: BinaryValueErrorContext::Loop,
value: condition,
};
ControlFlow::Break(BreakReason::Err(state.operation_error_with_current_context(err)))
}
}
#[inline(always)]
pub(super) fn finish_loop_node_pure<P, H, S, T, F>(
state: &mut ExecutionState<'_, P, H, S, T, F>,
current_node_id: MastNodeId,
current_forest: &F,
) -> ControlFlow<BreakReason<F>>
where
P: Processor,
H: BaseHost,
S: Stopper<Processor = P, Forest = F>,
T: Tracer<Processor = P, Forest = F>,
F: ExecutableMastForest + Clone,
{
let condition = state.processor.stack().get(0);
let loop_node = option_map_break_reason(
current_forest.get_node_by_id(current_node_id),
"loop node not found in current forest",
)?
.unwrap_loop();
if condition == ONE {
state.tracer.start_clock_cycle(
state.processor,
Continuation::FinishLoop(current_node_id),
state.continuation_stack,
current_forest,
);
if let Err(err) = state.processor.stack_mut().decrement_size().map_exec_err() {
return ControlFlow::Break(BreakReason::Err(err));
}
state.continuation_stack.push_finish_loop(current_node_id);
state.continuation_stack.push_start_node(loop_node.body());
finalize_clock_cycle(
state.processor,
state.tracer,
state.stopper,
state.continuation_stack,
current_forest,
)
} else if condition == ZERO {
state.tracer.start_clock_cycle(
state.processor,
Continuation::FinishLoop(current_node_id),
state.continuation_stack,
current_forest,
);
if let Err(err) = state.processor.stack_mut().decrement_size().map_exec_err() {
return ControlFlow::Break(BreakReason::Err(err));
}
finalize_clock_cycle_with_continuation(
state.processor,
state.tracer,
state.stopper,
state.continuation_stack,
|| None,
current_forest,
)
} else {
let err = OperationError::NotBinaryValue {
context: BinaryValueErrorContext::Loop,
value: condition,
};
ControlFlow::Break(BreakReason::Err(state.operation_error_with_current_context(err)))
}
}