mech_core/program/
mod.rs

1use crate::*;
2use std::io::Cursor;
3#[cfg(not(feature = "no_std"))]
4use std::collections::HashSet;
5#[cfg(feature = "no_std")]
6use hashbrown::HashSet;
7
8#[cfg(any(feature = "compiler", feature = "program"))]
9pub mod compiler;
10#[cfg(feature = "symbol_table")]
11pub mod symbol_table;
12#[cfg(feature = "program")]
13pub mod program;
14
15#[cfg(any(feature = "compiler", feature = "program"))]
16pub use self::compiler::*;
17#[cfg(feature = "symbol_table")]
18pub use self::symbol_table::*;
19#[cfg(feature = "program")]
20pub use self::program::*;
21
22// Program State
23// ----------------------------------------------------------------------------
24
25pub type Dictionary = HashMap<u64,String>;
26pub type KindTable = HashMap<u64, ValueKind>;
27#[cfg(feature = "enum")]
28pub type EnumTable = HashMap<u64, MechEnum>;
29
30pub struct ProgramState {
31  #[cfg(feature = "symbol_table")]
32  pub symbol_table: SymbolTableRef,
33  #[cfg(feature = "symbol_table")]
34  pub environment: Option<SymbolTableRef>,
35  #[cfg(feature = "functions")]
36  pub functions: FunctionsRef,
37  #[cfg(feature = "functions")]
38  pub plan: Plan,
39  pub kinds: KindTable,
40  #[cfg(feature = "enum")]
41  pub enums: EnumTable,
42  pub dictionary: Ref<Dictionary>,
43}
44
45impl Clone for ProgramState {
46  fn clone(&self) -> Self {
47    ProgramState {
48      #[cfg(feature = "symbol_table")]
49      symbol_table: self.symbol_table.clone(),
50      #[cfg(feature = "symbol_table")]
51      environment: self.environment.clone(),
52      #[cfg(feature = "functions")]
53      functions: self.functions.clone(),
54      #[cfg(feature = "functions")]
55      plan: self.plan.clone(),
56      kinds: self.kinds.clone(),
57      #[cfg(feature = "enum")]
58      enums: self.enums.clone(),
59      dictionary: self.dictionary.clone(),
60    }
61  }
62}
63
64impl ProgramState {
65  pub fn new() -> ProgramState {
66    ProgramState {
67      #[cfg(feature = "symbol_table")]
68      symbol_table: Ref::new(SymbolTable::new()),
69      #[cfg(feature = "symbol_table")]
70      environment: None,
71      #[cfg(feature = "functions")]
72      functions: Ref::new(Functions::new()),
73      #[cfg(feature = "functions")]
74      plan: Plan::new(),
75      kinds: KindTable::new(),
76      #[cfg(feature = "enum")]
77      enums: EnumTable::new(),
78      dictionary: Ref::new(Dictionary::new()),
79    }
80  }
81
82  #[cfg(feature = "pretty_print")]
83  pub fn pretty_print(&self) -> String {
84    let mut output = String::new();
85    output.push_str("Program State:\n");
86    #[cfg(feature = "symbol_table")]
87    {
88      output.push_str("Symbol Table:\n");
89      output.push_str(&self.symbol_table.borrow().pretty_print());
90    }
91    #[cfg(feature = "functions")]
92    {
93      output.push_str(&self.functions.borrow().pretty_print());
94    }
95    #[cfg(feature = "functions")]
96    {
97      output.push_str("Execution Plan:\n");
98      for (i, step) in self.plan.borrow().iter().enumerate() {
99        output.push_str(&format!("  Step {}: {}\n", i, step.to_string()));
100      }
101    }
102    output
103  }
104
105  #[cfg(feature = "symbol_table")]
106  pub fn get_symbol(&self, id: u64) -> Option<Ref<Value>> {
107    let syms = self.symbol_table.borrow();
108    syms.get(id)
109  }
110
111  #[cfg(feature = "symbol_table")]
112  pub fn get_mutable_symbol(&self, id: u64) -> Option<ValRef> {
113    let syms = self.symbol_table.borrow();
114    syms.get_mutable(id)
115  }
116
117  #[cfg(feature = "symbol_table")]
118  pub fn contains_symbol(&self, id: u64) -> bool {
119    if let Some(env) = &self.environment {
120      let env_brrw = env.borrow();
121      if env_brrw.contains(id) {
122        true
123      } else {
124        let syms = self.symbol_table.borrow();
125        syms.contains(id)
126      }
127    } else {
128      let syms = self.symbol_table.borrow();
129      syms.contains(id)
130    }
131  }
132
133  #[cfg(feature = "symbol_table")]
134  pub fn get_environment(&self) -> Option<SymbolTableRef> {
135    self.environment.clone()
136  }
137
138  /// Look up symbol in environment first, then in global symbol table
139  #[cfg(feature = "symbol_table")]
140  pub fn get_env_symbol(&self, id: u64) -> Option<Ref<Value>> {
141    if let Some(env) = &self.environment {
142      let env_brrw = env.borrow();
143      match env_brrw.get(id) {
144        Some(val) => Some(val),
145        None => {
146          let sym_brrw = self.symbol_table.borrow();
147          sym_brrw.get(id)
148        }
149      }
150    } else {
151      None
152    }
153  }
154      
155  #[cfg(feature = "functions")]
156  pub fn add_plan_step(&self, step: Box<dyn MechFunction>) {
157    let mut plan_brrw = self.plan.borrow_mut();
158    plan_brrw.push(step);
159  }
160
161  #[cfg(feature = "functions")]
162  pub fn insert_function(&self, fxn: FunctionDescriptor) {
163    let mut fxns_brrw = self.functions.borrow_mut();
164    let id = hash_str(&fxn.name);
165    fxns_brrw.functions.insert(id.clone(), fxn.ptr);
166    self.dictionary.borrow_mut().insert(id, fxn.name.to_string());
167  }
168
169  #[cfg(feature = "symbol_table")]
170  pub fn save_symbol(&self, id: u64, name: String, value: Value, mutable: bool) -> ValRef {
171    let mut symbols_brrw = self.symbol_table.borrow_mut();
172    let val_ref = symbols_brrw.insert(id,value,mutable);
173    let mut dict_brrw = symbols_brrw.dictionary.borrow_mut();
174    dict_brrw.insert(id,name);
175    val_ref
176  }
177
178  #[cfg(feature = "symbol_table")]
179  pub fn save_env_symbol(&self, id: u64, name: String, value: Value, mutable: bool) -> ValRef {
180    if let Some(env) = &self.environment {
181      let mut env_brrw = env.borrow_mut();
182      let val_ref = env_brrw.insert(id,value,mutable);
183      let mut dict_brrw = env_brrw.dictionary.borrow_mut();
184      dict_brrw.insert(id,name);
185      val_ref
186    } else {
187      panic!("No environment to save variable into");
188    }
189  }
190
191}
192
193pub fn parse_version_to_u16(s: &str) -> Option<u16> {
194  let parts: Vec<&str> = s.split('.').collect();
195  if parts.len() != 3 { return None; }
196
197  let major = parts[0].parse::<u16>().ok()?;
198  let minor = parts[1].parse::<u16>().ok()?;
199  let patch = parts[2].parse::<u16>().ok()?; // parse to u16 to check bounds easily
200
201  if major > 0b111 { return None; }    // 3 bits => 0..7
202  if minor > 0b1_1111 { return None; } // 5 bits => 0..31
203  if patch > 0xFF { return None; }     // 8 bits => 0..255
204
205  // Pack: major in bits 15..13, minor in bits 12..8, patch in bits 7..0
206  let encoded = (major << 13) | (minor << 8) | patch;
207  Some(encoded as u16)
208}
209
210#[derive(Debug, Clone)]
211pub struct InvalidMagicNumberError;
212
213impl MechErrorKind2 for InvalidMagicNumberError {
214  fn name(&self) -> &str { "InvalidMagicNumber" }
215  fn message(&self) -> String { "Invalid magic number".to_string() }
216}