use crate::rvm::program::RuleType;
use crate::value::Value;
use alloc::collections::BTreeSet;
use alloc::vec::Vec;
use super::context::{ComprehensionContext, LoopContext};
use super::errors::VmError;
#[derive(Debug, Clone)]
pub(super) struct ExecutionFrame {
pub(super) pc: usize,
pub(super) kind: FrameKind,
}
impl ExecutionFrame {
pub(super) const fn new(pc: usize, kind: FrameKind) -> Self {
Self { pc, kind }
}
pub(super) const fn main(pc: usize, return_register: u8) -> Self {
Self {
pc,
kind: FrameKind::Main {
return_value_register: return_register,
},
}
}
}
#[derive(Debug, Clone)]
pub(super) enum FrameKind {
Main { return_value_register: u8 },
Rule(RuleFrameData),
Loop {
return_pc: usize,
context: LoopContext,
},
Comprehension {
return_pc: usize,
context: ComprehensionContext,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum RuleFramePhase {
Initializing,
ExecutingDestructuring,
ExecutingBody,
Finalizing,
}
#[derive(Debug, Clone)]
pub(super) struct RuleFrameData {
pub(super) return_pc: usize,
pub(super) dest_reg: u8,
pub(super) rule_index: u16,
pub(super) current_definition_index: usize,
pub(super) current_body_index: usize,
pub(super) total_definitions: usize,
pub(super) phase: RuleFramePhase,
pub(super) accumulated_result: Option<Value>,
pub(super) any_body_succeeded: bool,
pub(super) rule_failed_due_to_inconsistency: bool,
pub(super) rule_type: RuleType,
pub(super) result_reg: u8,
pub(super) is_function_rule: bool,
pub(super) num_registers: usize,
pub(super) num_retained_registers: usize,
pub(super) saved_registers: Vec<Value>,
pub(super) saved_loop_stack: Vec<LoopContext>,
pub(super) saved_comprehension_stack: Vec<ComprehensionContext>,
}
#[derive(Debug, Clone, Default)]
pub(super) struct ExecutionStack {
frames: Vec<ExecutionFrame>,
}
impl ExecutionStack {
pub const fn new() -> Self {
Self { frames: Vec::new() }
}
pub fn push(&mut self, frame: ExecutionFrame) {
self.frames.push(frame);
}
pub fn pop(&mut self) -> Option<ExecutionFrame> {
self.frames.pop()
}
pub fn last(&self) -> Option<&ExecutionFrame> {
self.frames.last()
}
pub fn last_mut(&mut self) -> Option<&mut ExecutionFrame> {
self.frames.last_mut()
}
pub const fn is_empty(&self) -> bool {
self.frames.is_empty()
}
pub const fn len(&self) -> usize {
self.frames.len()
}
pub fn get(&self, index: usize) -> Option<&ExecutionFrame> {
self.frames.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut ExecutionFrame> {
self.frames.get_mut(index)
}
pub fn clear(&mut self) {
self.frames.clear();
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub enum ExecutionState {
#[default]
Ready,
Running,
Suspended {
reason: SuspendReason,
pc: usize,
last_result: Value,
},
Completed {
result: Value,
},
Error {
error: VmError,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum SuspendReason {
SuspendInstruction,
Breakpoint {
pc: usize,
},
Step,
InstructionLimit,
External,
HostAwait {
dest: u8,
argument: Value,
identifier: Value,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExecutionMode {
RunToCompletion,
Suspendable,
}
pub(super) type BreakpointSet = BTreeSet<usize>;