instruct/interpreter/
stack.rs1use log::trace;
2use std::{cell::RefCell, collections::HashMap, rc::Rc};
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum Error {
7 #[error("a variable '{0}' that not allocated was accessed, this should not happen!")]
8 UnallocatedVariableAccessed(String),
9 #[error("tried to access undefined variable '{0}'")]
10 UndefinedVariableAccessed(String),
11}
12
13pub type StackRef = Rc<RefCell<Stack>>;
14
15pub struct Stack {
16 variables: HashMap<String, Option<String>>,
17 parent: Option<StackRef>,
18 height: u16,
19}
20
21impl Stack {
22 pub fn new() -> Self {
23 Self {
24 variables: HashMap::new(),
25 parent: None,
26 height: 0,
27 }
28 }
29
30 pub fn inherit_new(parent: &StackRef) -> Stack {
31 Self {
32 variables: HashMap::new(),
33 parent: Some(parent.clone()),
34 height: parent.borrow().height + 1,
35 }
36 }
37
38 pub fn get(&self, name: &str) -> anyhow::Result<String> {
39 trace!("Getting '{}' from stack {}@{:p}", name, self.height, self);
40 match self.variables.get(name) {
41 Some(Some(val)) => Ok(val.into()),
42 Some(None) | None => match &self.parent {
43 Some(child) => child.borrow().get(name),
44 None => Err(Error::UnallocatedVariableAccessed(name.into()).into()),
45 },
46 }
47 }
48
49 pub fn set(&mut self, name: String, value: String) -> anyhow::Result<()> {
50 if value.len() > 10 {
51 trace!(
52 "Setting '{}' to {:?}..{:?}' for stack {}@{:p}",
53 &name,
54 &value[..10],
55 &value[value.len() - 10..],
56 self.height,
57 self
58 );
59 } else {
60 trace!(
61 "Setting '{}' to {:?} for stack {}@{:p}",
62 &name,
63 &value,
64 self.height,
65 self
66 );
67 }
68 if self.variables.insert(name.clone(), Some(value)).is_none() {
69 return Err(Error::UnallocatedVariableAccessed(name).into());
70 }
71 Ok(())
72 }
73
74 pub fn allocate(&mut self, name: String) {
75 trace!(
76 "Allocating '{}' for stack {}@{:p}",
77 &name,
78 self.height,
79 self
80 );
81 self.variables.insert(name, None);
82 }
83
84 pub fn assert_allocated(&self, name: &str) -> anyhow::Result<()> {
85 trace!(
86 "Asserting allocation '{}' for stack {}@{:p}",
87 &name,
88 self.height,
89 self
90 );
91 match self.variables.contains_key(name) {
92 true => Ok(()),
93 false => match &self.parent {
94 Some(parent) => parent.borrow().assert_allocated(name),
95 None => Err(Error::UndefinedVariableAccessed(name.into()).into()),
96 },
97 }
98 }
99}
100
101impl Default for Stack {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107impl From<Vec<(&'static str, &'static str)>> for Stack {
108 fn from(values: Vec<(&str, &str)>) -> Stack {
109 let mut stack = Stack::new();
110
111 for (key, value) in values {
112 stack.allocate(key.into());
113 stack.set(key.into(), value.into()).unwrap();
114 }
115
116 stack
117 }
118}
119
120impl From<Stack> for StackRef {
121 fn from(stack: Stack) -> StackRef {
122 Rc::new(RefCell::new(stack))
123 }
124}