use super::loop_cmd::{LoopRuntimeState, LOOP_STACK_KEY};
#[cfg(feature = "scripts_timing")]
use crate::scripts_builtin::timing::{TimeRuntimeState, TIME_STACK_KEY};
use crate::script_engine::instruction::{InstructionData, InstructionHandler, InstructionMetadata, ScriptError};
use crate::script_engine::VMContext;
pub struct BreakHandler;
impl InstructionHandler for BreakHandler {
fn name(&self) -> &str {
"break"
}
fn parse(&self, _args: &[&str]) -> Result<InstructionData, ScriptError> {
Ok(InstructionData::None)
}
fn execute(
&self,
vm: &mut VMContext,
_data: &InstructionData,
_metadata: Option<&InstructionMetadata>,
) -> Result<(), ScriptError> {
#[cfg(feature = "scripts_timing")]
{
let time_stack = vm.get_or_create_execution_state::<Vec<TimeRuntimeState>>(TIME_STACK_KEY);
if !time_stack.is_empty() {
let time_state = time_stack.pop().unwrap();
if !vm.is_block_context_empty() {
vm.leave_block();
}
vm.ip = time_state.end_ip + 1;
return Ok(());
}
}
let loop_stack = vm.get_or_create_execution_state::<Vec<LoopRuntimeState>>(LOOP_STACK_KEY);
if let Some(loop_state) = loop_stack.pop() {
vm.ip = loop_state.end_ip + 1;
} else {
return Err(ScriptError::ExecutionError(
"'break' outside of loop or time block".into(),
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_break_no_params() {
let handler = BreakHandler;
let result = handler.parse(&[]).unwrap();
assert!(matches!(result, InstructionData::None));
}
}