Skip to main content

runmat_vm/runtime/
globals.rs

1use 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}