prolog2/heap/
symbol_db.rs1use std::{
8 collections::HashMap,
9 sync::{Arc, RwLock},
10};
11
12use lazy_static::lazy_static;
13
14const KNOWN_SYMBOLS: &[&str] = &[
15 "false",
16 "true", "+",
18 "-",
19 "*",
20 "/",
21 "**", "cos",
23 "sin",
24 "tan",
25 "acos",
26 "asin",
27 "atan", "log",
29 "abs",
30 "round",
31 "sqrt",
32 "to_degrees",
33 "to_radians", ];
35
36pub const fn known_symbol_id(index: usize) -> usize {
38 isize::MAX as usize + index
39}
40
41lazy_static! {
42 static ref SYMBOLS: RwLock<SymbolDB> = RwLock::new(SymbolDB {
43 const_symbols: KNOWN_SYMBOLS
44 .iter()
45 .map(|&symbol| symbol.to_string().into())
46 .collect(),
47 var_symbol_map: HashMap::new(),
48 strings: Vec::new(),
49 });
50}
51
52pub struct SymbolDB {
58 const_symbols: Vec<Arc<str>>,
59 var_symbol_map: HashMap<(usize, usize), Arc<str>>,
60 strings: Vec<Arc<str>>,
61}
62
63impl SymbolDB {
64 pub fn set_const(symbol: String) -> usize {
65 let mut symbols = SYMBOLS.write().unwrap();
66 let symbol: Arc<str> = symbol.into();
67 match symbols.const_symbols.iter().position(|e| *e == symbol) {
68 Some(i) => i + isize::MAX as usize,
69 None => {
70 symbols.const_symbols.push(symbol);
71 symbols.const_symbols.len() - 1 + isize::MAX as usize
72 }
73 }
74 }
75
76 pub fn set_var(symbol: String, addr: usize, heap_id: usize) {
77 SYMBOLS
78 .write()
79 .unwrap()
80 .var_symbol_map
81 .insert((addr, heap_id), symbol.into());
82 }
83
84 pub fn get_const(id: usize) -> Arc<str> {
85 SYMBOLS.read().unwrap().const_symbols[id - isize::MAX as usize].clone()
86 }
87
88 pub fn get_var(addr: usize, heap_id: usize) -> Option<Arc<str>> {
89 let vars = &SYMBOLS.read().unwrap().var_symbol_map;
90 if let Some(symbol) = vars.get(&(addr, heap_id)) {
91 Some(symbol.clone())
92 } else {
93 None
94 }
95 }
96
97 pub fn get_string(index: usize) -> Arc<str> {
98 SYMBOLS.read().unwrap().strings.get(index).unwrap().clone()
100 }
101
102 pub fn set_string(value: String) -> usize {
103 let mut write_gaurd = SYMBOLS.write().unwrap();
104 write_gaurd.strings.push(value.into());
105 write_gaurd.strings.len() - 1
106 }
107
108 pub fn _see_var_map() {
109 let symbols = SYMBOLS.read().unwrap();
110 for (k, v) in &symbols.var_symbol_map {
111 println!("{k:?}:\t{v}")
112 }
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::super::{heap::_CON_PTR, symbol_db::SymbolDB};
119
120 #[test]
121 fn known_symbols() {
123 assert_eq!(&*SymbolDB::get_const(_CON_PTR), "false");
124 assert_eq!(&*SymbolDB::get_const(_CON_PTR + 1), "true");
125 }
126
127 #[test]
128 fn insert_constant_symbol() {
129 let id = SymbolDB::set_const("a".into());
130
131 assert_eq!(&*SymbolDB::get_const(id), "a");
132 assert_eq!(SymbolDB::set_const("a".into()), id);
133 }
134
135 #[test]
136 fn insert_variable_symbol() {
137 SymbolDB::set_var("X".into(), 100, 0);
138 SymbolDB::set_var("Y".into(), 200, 1);
139 SymbolDB::set_var("Z".into(), 200, 2);
140
141 assert_eq!(*SymbolDB::get_var(100, 0).unwrap(), *"X");
142 assert_eq!(*SymbolDB::get_var(200, 1).unwrap(), *"Y");
143 assert_eq!(*SymbolDB::get_var(200, 2).unwrap(), *"Z");
144 }
145
146 #[test]
147 fn insert_string() {
148 let idx = SymbolDB::set_string("some string".into());
149 assert_eq!(*SymbolDB::get_string(idx), *"some string");
150 }
151}