1use petr_core::SelectorWord;
2
3use crate::{DispatchError, DispatchResult};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct OpFrame {
8 pub text: String,
10 pub acc: i64,
12}
13
14impl OpFrame {
15 pub fn text(text: impl Into<String>) -> Self { Self { text: text.into(), acc: 0 } }
17
18 pub fn acc(acc: i64) -> Self { Self { text: String::new(), acc } }
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Default)]
24pub struct OpArg {
25 pub n: i64,
27 pub text: String,
29}
30
31impl OpArg {
32 pub fn n(n: i64) -> Self { Self { n, text: String::new() } }
34
35 pub fn text(text: impl Into<String>) -> Self { Self { n: 0, text: text.into() } }
37}
38
39pub type OpFn = fn(OpFrame, &OpArg) -> DispatchResult<OpFrame>;
41
42#[derive(Clone)]
44pub struct OpEntry {
45 pub func: OpFn,
47 pub arg: OpArg,
49 pub name: String,
51}
52
53impl core::fmt::Debug for OpEntry {
54 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 f.debug_struct("OpEntry").field("name", &self.name).field("arg", &self.arg).finish()
56 }
57}
58
59#[derive(Debug, Clone)]
61pub struct OperationTable {
62 entries: Vec<Option<OpEntry>>,
63}
64
65impl Default for OperationTable {
66 fn default() -> Self { Self::new() }
67}
68
69impl OperationTable {
70 pub fn new() -> Self { Self { entries: vec![None; 256] } }
72
73 pub fn register(&mut self, selector: u8, name: impl Into<String>, func: OpFn, arg: OpArg) {
75 self.entries[selector as usize] = Some(OpEntry { func, arg, name: name.into() });
76 }
77
78 pub fn register_word(&mut self, selector: SelectorWord, name: impl Into<String>, func: OpFn, arg: OpArg) {
80 self.register(selector.function_id(), name, func, arg);
81 }
82
83 pub fn execute(&self, selector: u8, frame: OpFrame) -> DispatchResult<OpFrame> {
85 match &self.entries[selector as usize] {
86 Some(entry) => (entry.func)(frame, &entry.arg),
87 None => Err(DispatchError::OperationNotFound(selector)),
88 }
89 }
90
91 pub fn execute_word(&self, selector: SelectorWord, frame: OpFrame) -> DispatchResult<OpFrame> {
93 self.execute(selector.function_id(), frame)
94 }
95
96 pub fn execute_or_nop(&self, selector: u8, frame: OpFrame) -> OpFrame {
101 if let Some(entry) = &self.entries[selector as usize] {
102 (entry.func)(frame, &entry.arg).unwrap_or_else(|_| OpFrame::text("<op-error>"))
103 } else {
104 frame
105 }
106 }
107
108 pub fn contains(&self, selector: u8) -> bool { self.entries[selector as usize].is_some() }
110}