runmat_vm/runtime/
globals.rs1use crate::bytecode::instr::Instr;
2use crate::bytecode::program::Bytecode;
3use crate::runtime::workspace::refresh_workspace_state;
4use runmat_builtins::Value;
5use runmat_thread_local::runmat_thread_local;
6use std::cell::RefCell;
7use std::collections::HashMap;
8
9runmat_thread_local! {
10 static GLOBALS: RefCell<HashMap<String, Value>> = RefCell::new(HashMap::new());
11}
12
13runmat_thread_local! {
14 static PERSISTENTS: RefCell<HashMap<(String, usize), Value>> = RefCell::new(HashMap::new());
15}
16
17runmat_thread_local! {
18 static PERSISTENTS_BY_NAME: RefCell<HashMap<(String, String), Value>> = RefCell::new(HashMap::new());
19}
20
21pub fn workspace_global_names() -> Vec<String> {
22 let mut names = Vec::new();
23 GLOBALS.with(|globals| {
24 let map = globals.borrow();
25 for key in map.keys() {
26 if !key.starts_with("var_") {
27 names.push(key.clone());
28 }
29 }
30 });
31 names.sort();
32 names
33}
34
35pub fn collect_thread_roots() -> Vec<Value> {
36 let mut thread_roots = Vec::new();
37 GLOBALS.with(|g| {
38 for v in g.borrow().values() {
39 thread_roots.push(v.clone());
40 }
41 });
42 PERSISTENTS.with(|p| {
43 for v in p.borrow().values() {
44 thread_roots.push(v.clone());
45 }
46 });
47 PERSISTENTS_BY_NAME.with(|p| {
48 for v in p.borrow().values() {
49 thread_roots.push(v.clone());
50 }
51 });
52 thread_roots
53}
54
55pub fn update_global_store(
56 stored_index: usize,
57 stored_value: &Value,
58 global_aliases: &HashMap<usize, String>,
59) {
60 let key = format!("var_{stored_index}");
61 GLOBALS.with(|g| {
62 let mut m = g.borrow_mut();
63 if m.contains_key(&key) {
64 m.insert(key, stored_value.clone());
65 }
66 });
67 if let Some(name) = global_aliases.get(&stored_index) {
68 GLOBALS.with(|g| {
69 g.borrow_mut().insert(name.clone(), stored_value.clone());
70 });
71 }
72}
73
74pub fn update_persistent_local_store(func_name: &str, stored_offset: usize, stored_value: &Value) {
75 let key = (func_name.to_string(), stored_offset);
76 PERSISTENTS.with(|p| {
77 let mut m = p.borrow_mut();
78 if m.contains_key(&key) {
79 m.insert(key, stored_value.clone());
80 }
81 });
82}
83
84pub fn declare_global(indices: Vec<usize>, vars: &mut Vec<Value>) {
85 for i in indices {
86 let key = format!("var_{i}");
87 let val_opt = GLOBALS.with(|g| g.borrow().get(&key).cloned());
88 if let Some(v) = val_opt {
89 if i >= vars.len() {
90 vars.resize(i + 1, Value::Num(0.0));
91 refresh_workspace_state(vars);
92 }
93 vars[i] = v;
94 }
95 }
96}
97
98pub fn declare_global_named(
99 indices: Vec<usize>,
100 names: Vec<String>,
101 vars: &mut Vec<Value>,
102 global_aliases: &mut HashMap<usize, String>,
103) {
104 for (pos, i) in indices.into_iter().enumerate() {
105 let name = names
106 .get(pos)
107 .cloned()
108 .unwrap_or_else(|| format!("var_{i}"));
109 let val_opt = GLOBALS.with(|g| g.borrow().get(&name).cloned());
110 if let Some(v) = val_opt {
111 if i >= vars.len() {
112 vars.resize(i + 1, Value::Num(0.0));
113 refresh_workspace_state(vars);
114 }
115 vars[i] = v;
116 }
117 GLOBALS.with(|g| {
118 let mut m = g.borrow_mut();
119 if let Some(v) = m.get(&name).cloned() {
120 m.insert(format!("var_{i}"), v);
121 }
122 });
123 global_aliases.insert(i, name);
124 }
125}
126
127pub fn declare_persistent(func_name: &str, indices: Vec<usize>, vars: &mut Vec<Value>) {
128 for i in indices {
129 let key = (func_name.to_string(), i);
130 let val_opt = PERSISTENTS.with(|p| p.borrow().get(&key).cloned());
131 if let Some(v) = val_opt {
132 if i >= vars.len() {
133 vars.resize(i + 1, Value::Num(0.0));
134 refresh_workspace_state(vars);
135 }
136 vars[i] = v;
137 }
138 }
139}
140
141pub fn declare_persistent_named(
142 func_name: &str,
143 indices: Vec<usize>,
144 names: Vec<String>,
145 vars: &mut Vec<Value>,
146 persistent_aliases: &mut HashMap<usize, String>,
147) {
148 for (pos, i) in indices.into_iter().enumerate() {
149 let name = names
150 .get(pos)
151 .cloned()
152 .unwrap_or_else(|| format!("var_{i}"));
153 let key = (func_name.to_string(), i);
154 let val_opt = PERSISTENTS_BY_NAME
155 .with(|p| {
156 p.borrow()
157 .get(&(func_name.to_string(), name.clone()))
158 .cloned()
159 })
160 .or_else(|| PERSISTENTS.with(|p| p.borrow().get(&key).cloned()));
161 if let Some(v) = val_opt {
162 if i >= vars.len() {
163 vars.resize(i + 1, Value::Num(0.0));
164 refresh_workspace_state(vars);
165 }
166 vars[i] = v;
167 }
168 persistent_aliases.insert(i, name);
169 }
170}
171
172pub fn persist_declared_for_bytecode(bytecode: &Bytecode, func_name: &str, vars: &[Value]) {
173 for instr in &bytecode.instructions {
174 match instr {
175 Instr::DeclarePersistent(indices) => {
176 for &i in indices {
177 if i < vars.len() {
178 let key = (func_name.to_string(), i);
179 PERSISTENTS.with(|p| {
180 p.borrow_mut().insert(key, vars[i].clone());
181 });
182 }
183 }
184 }
185 Instr::DeclarePersistentNamed(indices, names) => {
186 for (pos, &i) in indices.iter().enumerate() {
187 if i < vars.len() {
188 let key = (func_name.to_string(), i);
189 let name_key = (
190 func_name.to_string(),
191 names
192 .get(pos)
193 .cloned()
194 .unwrap_or_else(|| format!("var_{i}")),
195 );
196 let val = vars[i].clone();
197 PERSISTENTS.with(|p| {
198 p.borrow_mut().insert(key, val.clone());
199 });
200 PERSISTENTS_BY_NAME.with(|p| {
201 p.borrow_mut().insert(name_key, val);
202 });
203 }
204 }
205 }
206 _ => {}
207 }
208 }
209}
210
211pub fn clear_all_runtime_globals() {
212 GLOBALS.with(|g| g.borrow_mut().clear());
213 PERSISTENTS.with(|p| p.borrow_mut().clear());
214 PERSISTENTS_BY_NAME.with(|p| p.borrow_mut().clear());
215}