mech_core/
lib.rs

1#![cfg_attr(feature = "no_std", no_std)]
2#![feature(get_mut_unchecked)]
3#![allow(warnings)]
4#![feature(iter_intersperse)]
5#![feature(extract_if)]
6#![allow(dead_code)]
7#![feature(step_trait)]
8#![feature(box_patterns)]
9
10//extern crate core as rust_core;
11extern crate seahash;
12
13#[cfg(feature="no_std")] #[macro_use] 
14extern crate alloc;
15#[cfg(not(feature = "no_std"))] 
16extern crate core;
17
18#[cfg(feature="no_std")]
19use hashbrown::HashMap;
20#[cfg(not(feature = "no_std"))] 
21use std::collections::HashMap;
22
23#[cfg(feature="no_std")]
24use alloc::fmt::{self, Debug, Display};
25#[cfg(not(feature = "no_std"))] 
26use std::fmt::{self, Debug, Display};
27
28#[cfg(feature="no_std")]
29use alloc::vec::Vec;
30
31#[cfg(feature="no_std")]
32use fxhash::FxHasher;
33
34#[cfg(feature = "no_std")]
35use embedded_io::{self, Read, Write};
36#[cfg(not(feature = "no_std"))] 
37use std::io::{self, Error as ioError, Cursor, Read, Write};
38
39#[cfg(feature = "no_std")]
40use alloc::string::{String, ToString};
41
42#[cfg(feature = "no_std")]
43use core::hash::{Hash, Hasher};
44#[cfg(not(feature = "no_std"))] 
45use std::hash::{Hash, Hasher};
46
47#[cfg(feature = "no_std")]
48use alloc::boxed::Box;
49
50#[cfg(feature = "matrix")]  
51extern crate nalgebra as na;
52#[cfg(feature = "pretty_print")]
53extern crate tabled;
54#[cfg(feature = "serde")] #[macro_use] 
55extern crate serde_derive;
56#[cfg(feature = "serde")]
57extern crate serde;
58#[cfg(any(feature = "math_exp", feature = "f64", feature = "f32", feature = "complex", feature = "rational"))]
59extern crate num_traits;
60
61use paste::paste;
62
63#[cfg(any(feature = "math_exp", feature = "f64"))]
64use num_traits::*;
65#[cfg(feature = "rational")]
66use num_rational::Rational64;
67#[cfg(feature = "vector3")]
68use nalgebra::Vector3;
69#[cfg(feature = "vectord")]
70use nalgebra::DVector;
71#[cfg(feature = "vector2")]
72use nalgebra::Vector2;
73#[cfg(feature = "vector4")]
74use nalgebra::Vector4;
75#[cfg(feature = "row_vectord")]
76use nalgebra::RowDVector;
77#[cfg(feature = "matrix1")]
78use nalgebra::Matrix1;
79#[cfg(feature = "matrix3")]
80use nalgebra::Matrix3;
81#[cfg(feature = "matrix4")]
82use nalgebra::Matrix4;
83#[cfg(feature = "row_vector3")]
84use nalgebra::RowVector3;
85#[cfg(feature = "row_vector4")]
86use nalgebra::RowVector4;
87#[cfg(feature = "row_vector2")]
88use nalgebra::RowVector2;
89#[cfg(feature = "matrixd")]
90use nalgebra::DMatrix;
91#[cfg(feature = "matrix2x3")]
92use nalgebra::Matrix2x3;
93#[cfg(feature = "matrix3x2")]
94use nalgebra::Matrix3x2;
95#[cfg(feature = "matrix2")]
96use nalgebra::Matrix2;
97
98#[cfg(feature = "pretty_print")]
99use tabled::{
100  builder::Builder,
101  settings::{object::Rows,Panel, Span, Alignment, Modify, Style},
102  Tabled,
103};
104
105pub mod error;
106pub mod kind;
107pub mod nodes;
108pub mod structures;
109pub mod value;
110#[cfg(feature = "functions")]
111pub mod functions;
112pub mod program;
113pub mod stdlib;
114pub mod types;
115
116pub use self::error::*;
117pub use self::kind::*;
118pub use self::nodes::*;
119pub use self::structures::*;
120pub use self::value::*;
121#[cfg(feature = "functions")]
122pub use self::functions::*;
123pub use self::program::*;
124pub use self::stdlib::*;
125pub use self::types::*;
126
127// Mech Source Code
128// ---------------------------------------------------------------------------
129
130#[cfg(feature = "functions")]
131inventory::collect!(FunctionDescriptor);
132
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134#[derive(Clone, Debug, PartialEq, Eq)]
135pub enum MechSourceCode {
136    String(String),
137    Tree(Program),
138    Html(String),
139    ByteCode(Vec<u8>),
140    Program(Vec<MechSourceCode>),
141}
142
143impl MechSourceCode {
144
145  pub fn to_string(&self) -> String {
146    match self {
147      MechSourceCode::ByteCode(bc) => {
148        #[cfg(feature = "program")]
149        match ParsedProgram::from_bytes(bc) {
150          Ok(program) => {
151            format!("{:#?}",program)
152          },
153          Err(e) => return format!("Error parsing bytecode: {:?}", e),
154        }
155        #[cfg(not(feature = "program"))]
156        format!("{:#?}", bc)
157        
158      }
159      MechSourceCode::String(s) => s.clone(),
160      MechSourceCode::Tree(p) => todo!("Print the tree!"),
161      MechSourceCode::Html(h) => h.clone(),
162      MechSourceCode::Program(v) => v.iter().map(|c| c.to_string()).collect::<Vec<String>>().join("\n"),
163    }
164  }
165}
166
167#[derive(Clone, Debug, PartialEq, Eq)]
168pub struct IndexedString {
169  pub data: Vec<char>,
170  pub index_map: Vec<Vec<usize>>,
171  pub rows: usize,
172  pub cols: usize,
173}
174
175impl IndexedString {
176  
177  fn new(input: &str) -> Self {
178      let mut data = Vec::new();
179      let mut index_map = Vec::new();
180      let mut current_row = 0;
181      let mut current_col = 0;
182      index_map.push(Vec::new());
183      for c in input.chars() {
184        data.push(c);
185        if c == '\n' {
186          index_map.push(Vec::new());
187          current_row += 1;
188          current_col = 0;
189        } else {
190          index_map[current_row].push(data.len() - 1);
191          current_col += 1;
192        }
193      }
194      let rows = index_map.len();
195      let cols = if rows > 0 { index_map[0].len() } else { 0 };
196      IndexedString {
197          data,
198          index_map,
199          rows,
200          cols,
201      }
202  }
203
204  fn to_string(&self) -> String {
205    self.data.iter().collect()
206  }
207
208  fn get(&self, row: usize, col: usize) -> Option<char> {
209    if row < self.rows {
210      let rowz = &self.index_map[row];
211      if col < rowz.len() {
212        let index = self.index_map[row][col];
213        Some(self.data[index])
214      } else {
215        None
216      }
217    } else {
218      None
219    }
220  }
221
222  fn set(&mut self, row: usize, col: usize, new_char: char) -> Result<(), String> {
223    if row < self.rows {
224      let row_indices = &mut self.index_map[row];
225      if col < row_indices.len() {
226        let index = row_indices[col];
227        self.data[index] = new_char;
228        Ok(())
229      } else {
230        Err("Column index out of bounds".to_string())
231      }
232    } else {
233      Err("Row index out of bounds".to_string())
234    }
235  }
236}
237
238// Humanize
239// ---------------------------------------------------------------------------
240
241// Turn bytes into something more readable by humans
242// Useful for visualizing register dumps, hashes, etc.
243
244pub fn hash_chars(input: &Vec<char>) -> u64 {
245  seahash::hash(input.iter().map(|s| String::from(*s)).collect::<String>().as_bytes()) & 0x00FFFFFFFFFFFFFF
246}
247
248pub fn hash_bytes(input: &Vec<u8>) -> u64 {
249  seahash::hash(input) & 0x00FFFFFFFFFFFFFF
250}
251
252pub fn hash_str(input: &str) -> u64 {
253  seahash::hash(input.as_bytes()) & 0x00FFFFFFFFFFFFFF
254}
255
256pub fn emojify_bytes(bytes: &[u8]) -> String {
257  let start = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len() - 1);
258  let mut out = String::new();
259  for &b in &bytes[start..] {
260      out.push_str(EMOJILIST[b as usize]);
261  }
262  out
263}
264
265pub fn humanize_bytes(bytes: &[u8]) -> String {
266  let parts: Vec<&str> = bytes
267    .iter()
268    .enumerate()
269    .filter_map(|(ix, &b)| if ix % 2 == 1 { Some(WORDLIST[b as usize]) } else { None })
270    .collect();
271  parts.join("-")
272}
273
274pub fn emojify<T>(num: &T) -> String
275where
276    T: Display + Copy + TryInto<u128>,
277    <T as TryInto<u128>>::Error: std::fmt::Debug,
278{
279  match (*num).try_into() {
280    Ok(v) => {
281      let bytes = v.to_be_bytes();
282      emojify_bytes(&bytes)
283    }
284    Err(_) => format!("{}", num),
285  }
286}
287
288pub fn humanize<T>(num: &T) -> String
289where
290    T: Display + Copy + TryInto<u128>,
291    <T as TryInto<u128>>::Error: Debug,
292{
293    match (*num).try_into() {
294        Ok(v) => {
295            let bytes = v.to_be_bytes();
296            let first_non_zero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len() - 1);
297            let trimmed = &bytes[first_non_zero..];
298            humanize_bytes(trimmed)
299        }
300        Err(_) => format!("{}", num),
301    }
302}
303
304pub const WORDLIST: &[&str;256] = &[
305  "nil", "ama", "ine", "ska", "pha", "gel", "art", 
306  "ona", "sas", "ist", "aus", "pen", "ust", "umn",
307  "ado", "con", "loo", "man", "eer", "lin", "ium",
308  "ack", "som", "lue", "ird", "avo", "dog", "ger",
309  "ter", "nia", "bon", "nal", "ina", "pet", "cat",
310  "ing", "lie", "ken", "fee", "ola", "old", "rad",
311  "met", "cut", "azy", "cup", "ota", "dec", "del",
312  "elt", "iet", "don", "ble", "ear", "rth", "eas", 
313  "war", "eig", "tee", "ele", "emm", "ene", "qua",
314  "tst", "fan", "fif", "fil", "fin", "fis", "fiv", 
315  "flo", "for", "foo", "fou", "fot", "fox", "fre",
316  "fri", "fru", "gee", "gia", "glu", "fol", "gre", 
317  "ham", "hap", "har", "haw", "hel", "hig", "hot", 
318  "hyd", "ida", "ill", "ind", "ini", "ink", "iwa",
319  "and", "ite", "jer", "jig", "joh", "jul", "uly", 
320  "kan", "ket", "kil", "kin", "kit", "lac", "lak", 
321  "lem", "ard", "lim", "lio", "lit", "lon", "lou",
322  "low", "mag", "nes", "mai", "gam", "arc", "mar",
323  "mao", "mas", "may", "mex", "mic", "mik", "ril",
324  "min", "mir", "mis", "mio", "mob", "moc", "ech",
325  "moe", "tan", "oon", "ain", "mup", "sic", "neb",
326  "une", "net", "nev", "nin", "een", "nit", "nor",
327  "nov", "nut", "oct", "ohi", "okl", "one", "ora",
328  "ges", "ore", "osc", "ove", "oxy", "pap", "par", 
329  "pey", "pip", "piz", "plu", "pot", "pri", "pur",
330  "que", "uqi", "qui", "red", "riv", "rob", "roi", 
331  "rug", "sad", "sal", "sat", "sep", "sev", "eve",
332  "sha", "sie", "sin", "sik", "six", "sit", "sky", 
333  "soc", "sod", "sol", "sot", "tir", "ker", "spr",
334  "sta", "ste", "mam", "mer", "swe", "tab", "tag", 
335  "see", "nis", "tex", "thi", "the", "tim", "tri",
336  "twe", "ent", "two", "unc", "ess", "uni", "ura", 
337  "veg", "ven", "ver", "vic", "vid", "vio", "vir",
338  "was", "est", "whi", "hit", "iam", "win", "his",
339  "wis", "olf", "wyo", "ray", "ank", "yel", "zeb",
340  "ulu", "fix", "gry", "hol", "jup", "lam", "pas",
341  "rom", "sne", "ten", "uta"];
342
343// Emoji list is for quicker visual scanning/recognition when comparing registers
344
345pub const EMOJILIST: &[&str; 256] = &[
346  "๐Ÿต","๐Ÿถ","๐Ÿบ","๐ŸฆŠ","๐Ÿฆ","๐Ÿฑ","๐Ÿˆ","๐Ÿˆ","๐Ÿฆ","๐Ÿท","๐Ÿฎ","๐Ÿฆฌ","๐Ÿฏ","๐Ÿด","๐ŸซŽ","๐Ÿฆ„","๐Ÿฆ“","๐Ÿฆ™","๐Ÿฆ’","๐Ÿ˜","๐Ÿฆฃ","๐Ÿฆ","๐Ÿฆ›","๐Ÿซ","๐Ÿ","๐Ÿญ","๐Ÿฐ","๐Ÿฟ๏ธ","๐Ÿฆซ","๐Ÿฆ”","๐Ÿฆ‡","๐Ÿป","๐Ÿจ","๐Ÿผ","๐Ÿฆฅ","๐Ÿฆฆ","๐Ÿฆจ","๐Ÿฆ˜","๐Ÿฆก","๐Ÿฆƒ","๐Ÿ”","๐Ÿฆ","๐Ÿง","๐Ÿ•Š๏ธ","๐Ÿฆ…","๐Ÿฆ†","๐Ÿฆโ€๐Ÿ”ฅ","๐Ÿฆ‰","๐Ÿฆค","๐Ÿฆฉ","๐Ÿฆš","๐Ÿฆœ","๐Ÿธ","๐ŸŠ","๐Ÿข","๐ŸฆŽ","๐Ÿ","๐Ÿฒ","๐Ÿฆ–","๐Ÿณ","๐Ÿฌ","๐Ÿฆญ","๐Ÿ ","๐Ÿฆˆ","๐Ÿ™","๐Ÿชผ","๐Ÿฆ€","๐Ÿฆž","๐Ÿฆ","๐Ÿฆ‘","๐ŸŒ","๐Ÿฆ‹","๐Ÿ›","๐Ÿ","๐Ÿชฒ","๐Ÿž","๐Ÿฆ—","๐Ÿ•ธ๏ธ","๐Ÿชฐ","๐Ÿชฑ","๐Ÿฆ ","๐Ÿ‘ป","๐Ÿ‘ฝ","๐Ÿถ","๐Ÿฎ","๐Ÿš","๐Ÿชธ","๐Ÿชถ","๐Ÿฆง","๐Ÿชฟ","๐Ÿฆข","๐Ÿค–",
347  "๐ŸŒน","๐ŸŒณ","๐ŸŒด","๐ŸŒต","๐Ÿ€","๐Ÿ","๐Ÿ„","๐ŸŒ›","๐ŸŒž","๐Ÿช","โญ","โ›…","๐ŸŒง๏ธ","๐ŸŒจ๏ธ","๐ŸŒˆ","โ„๏ธ","โ˜ƒ๏ธ","โ˜„๏ธ","๐Ÿ”ฅ","๐ŸŒป",
348  "๐Ÿ‡","๐Ÿ‰","๐ŸŠ","๐Ÿ‹","๐Ÿ‹โ€๐ŸŸฉ","๐ŸŒ","๐Ÿ","๐Ÿฅญ","๐ŸŽ","๐Ÿ","๐Ÿ“","๐Ÿฅ","๐Ÿ…","๐Ÿซ’","๐Ÿฅฅ","๐Ÿฅ”","๐Ÿฅ•","๐ŸŒฝ","๐ŸŒถ๏ธ","๐Ÿซ‘","๐Ÿฅ’","๐Ÿฅฆ","๐Ÿง„","๐Ÿง…","๐Ÿซ›","๐Ÿฆ","๐Ÿง","๐Ÿฉ","๐Ÿช","๐Ÿฐ","๐Ÿง","๐Ÿฅง","๐Ÿซ","๐Ÿญ","๐Ÿž","๐Ÿฅจ","๐Ÿฅฏ","๐Ÿง‡","๐ŸŸ","๐Ÿฟ","๐Ÿงƒ",
349  "๐ŸŽค","๐ŸŽง","๐Ÿ“ป","๐ŸŽท","๐Ÿช—","๐ŸŽธ","๐ŸŽน","๐ŸŽบ","๐ŸŽป","๐Ÿช‡","๐Ÿฅ","โš—๏ธ","๐Ÿ“ท","๐Ÿงณ","๐ŸŒก๏ธ","๐Ÿงธ","๐Ÿงถ","๐Ÿ”Ž","๐Ÿ•ฏ๏ธ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ”’","๐Ÿ—๏ธ","๐Ÿชš","๐Ÿ”ง","๐Ÿช›","๐Ÿ”ฉ","โš™๏ธ","โš–๏ธ","๐Ÿงฐ","๐Ÿงฒ","๐Ÿชœ","๐Ÿ”ฌ","๐Ÿ“ก","๐Ÿงท","๐Ÿงน","๐Ÿงบ","๐Ÿชฃ","๐Ÿงผ","๐Ÿงฝ","๐Ÿงฏ","๐Ÿ›’",  
350  "โฐ","๐Ÿ›Ÿ","๐Ÿ›ฉ๏ธ","๐Ÿš","๐Ÿ›ฐ๏ธ","๐Ÿš€","๐Ÿ›ธ","โš“","๐Ÿš‚","๐Ÿš‘","๐Ÿš’","๐Ÿš•","๐Ÿš—","๐Ÿšš","๐Ÿšœ","๐ŸŽ๏ธ","๐Ÿ๏ธ","๐Ÿ›ต","๐Ÿฆผ","๐Ÿšฒ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ž","๐Ÿ“ฐ","๐Ÿ“ฆ","๐Ÿ“ซ","โœ๏ธ","๐Ÿ–Š๏ธ","๐Ÿ–Œ๏ธ","๐Ÿ–๏ธ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ—‘๏ธ","๐Ÿ†","โšพ","๐Ÿ€","๐ŸŽพ","๐ŸŽณ","โ›ณ","โ›ธ๏ธ","๐Ÿคฟ","๐Ÿ›ท","๐ŸŽฏ","๐Ÿช","๐Ÿงฉ","๐Ÿช…","๐ŸŽจ","๐Ÿงญ","๐Ÿ”๏ธ","๐Ÿ๏ธ","โ›ฒ","โ›บ","๐ŸŽ ","๐Ÿ›","๐Ÿงต","๐Ÿ’ˆ","๐ŸŽช","๐Ÿ›Ž๏ธ","๐Ÿ’Ž","โ›ต"
351];