surreal/
process.rs

1//! Process state and status.
2
3use std::collections::{HashMap, VecDeque};
4
5use crate::{Instruction, Message, Pid, Value};
6
7/// A frame on the call stack, enabling cross-module calls.
8#[derive(Debug, Clone)]
9pub struct CallFrame {
10    /// Module to return to (None = inline code).
11    pub module: Option<String>,
12    /// Instruction to return to.
13    pub return_pc: usize,
14}
15
16/// A frame on the exception handler stack for try/catch/after.
17#[derive(Debug, Clone)]
18pub struct TryFrame {
19    /// Where to jump on exception (catch block)
20    pub catch_target: usize,
21    /// Where to jump for cleanup (after block, always runs)
22    pub after_target: Option<usize>,
23    /// Call stack depth when try was entered (for unwinding)
24    pub call_stack_depth: usize,
25    /// Data stack depth when try was entered (for unwinding)
26    pub stack_depth: usize,
27}
28
29/// Process state
30#[derive(Debug)]
31pub struct Process {
32    pub pid: Pid,
33    pub parent: Option<Pid>,
34    /// Current module being executed (None if running inline code).
35    pub current_module: Option<String>,
36    /// Program counter - index into current module's code or inline_code.
37    pub pc: usize,
38    /// Inline code for processes spawned with raw instructions (backwards compat).
39    pub inline_code: Option<Vec<Instruction>>,
40    pub registers: [Value; 1024],
41    pub mailbox: VecDeque<Message>,
42    pub links: Vec<Pid>,
43    /// Monitors this process has set up: (ref, target_pid)
44    pub monitors: Vec<(u64, Pid)>,
45    /// Processes that are monitoring this one: (ref, monitoring_pid)
46    pub monitored_by: Vec<(u64, Pid)>,
47    pub status: ProcessStatus,
48    /// Exit reason when process terminates (default: :normal for Done, :crashed for Crashed)
49    pub exit_reason: Value,
50    /// When true, exit signals from linked processes become messages instead of killing this process
51    pub trap_exit: bool,
52    /// Remaining timeout (in reductions) when waiting for a message
53    pub timeout: Option<u32>,
54    /// Call stack for function calls (stores return context)
55    pub call_stack: Vec<CallFrame>,
56    /// Data stack for saving/restoring values (Push/Pop)
57    pub stack: Vec<Value>,
58    /// Process dictionary for per-process key-value storage
59    pub dictionary: HashMap<Value, Value>,
60    /// Exception handler stack for try/catch/after
61    pub try_stack: Vec<TryFrame>,
62    /// Current exception being handled (class, reason, stacktrace)
63    pub current_exception: Option<(Value, Value, Vec<String>)>,
64    /// Binary match state: (binary bytes, current bit position)
65    pub binary_match_state: Option<(Vec<u8>, usize)>,
66}
67
68/// Process execution status
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum ProcessStatus {
71    /// Ready to run
72    Ready,
73    /// Waiting for a message
74    Waiting,
75    /// Finished normally
76    Done,
77    /// Crashed
78    Crashed,
79}
80
81impl Process {
82    /// Create a new process with inline code (backwards compatible).
83    pub fn new(pid: Pid, parent: Option<Pid>, code: Vec<Instruction>) -> Self {
84        Self {
85            pid,
86            parent,
87            current_module: None,
88            pc: 0,
89            inline_code: Some(code),
90            registers: std::array::from_fn(|_| Value::None),
91            mailbox: VecDeque::new(),
92            links: Vec::new(),
93            monitors: Vec::new(),
94            monitored_by: Vec::new(),
95            status: ProcessStatus::Ready,
96            exit_reason: Value::Atom("normal".to_string()),
97            trap_exit: false,
98            timeout: None,
99            call_stack: Vec::new(),
100            stack: Vec::new(),
101            dictionary: HashMap::new(),
102            try_stack: Vec::new(),
103            current_exception: None,
104            binary_match_state: None,
105        }
106    }
107
108    /// Create a new process that runs a module function.
109    pub fn new_with_module(pid: Pid, parent: Option<Pid>, module: String, entry: usize) -> Self {
110        Self {
111            pid,
112            parent,
113            current_module: Some(module),
114            pc: entry,
115            inline_code: None,
116            registers: std::array::from_fn(|_| Value::None),
117            mailbox: VecDeque::new(),
118            links: Vec::new(),
119            monitors: Vec::new(),
120            monitored_by: Vec::new(),
121            status: ProcessStatus::Ready,
122            exit_reason: Value::Atom("normal".to_string()),
123            trap_exit: false,
124            timeout: None,
125            call_stack: Vec::new(),
126            stack: Vec::new(),
127            dictionary: HashMap::new(),
128            try_stack: Vec::new(),
129            current_exception: None,
130            binary_match_state: None,
131        }
132    }
133}