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