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  Image(String,Vec<u8>),
146}
147
148impl MechSourceCode {
149
150  pub fn to_string(&self) -> String {
151    match self {
152      MechSourceCode::ByteCode(bc) => {
153        #[cfg(feature = "program")]
154        match ParsedProgram::from_bytes(bc) {
155          Ok(program) => {
156            format!("{:#?}",program)
157          },
158          Err(e) => return format!("Error parsing bytecode: {:?}", e),
159        }
160        #[cfg(not(feature = "program"))]
161        format!("{:#?}", bc)
162      }
163      MechSourceCode::Image(extension,img) => {
164        format!("Image (.{}) with {} bytes", extension, img.len())
165      }
166      MechSourceCode::String(s) => s.clone(),
167      MechSourceCode::Tree(p) => todo!("Print the tree!"),
168      MechSourceCode::Html(h) => h.clone(),
169      MechSourceCode::Program(v) => v.iter().map(|c| c.to_string()).collect::<Vec<String>>().join("\n"),
170    }
171  }
172}
173
174#[derive(Clone, Debug, PartialEq, Eq)]
175pub struct IndexedString {
176  pub data: Vec<char>,
177  pub index_map: Vec<Vec<usize>>,
178  pub rows: usize,
179  pub cols: usize,
180}
181
182impl IndexedString {
183  
184  fn new(input: &str) -> Self {
185    let mut data = Vec::new();
186    let mut index_map = Vec::new();
187    let mut current_row = 0;
188    let mut current_col = 0;
189    index_map.push(Vec::new());
190    for c in input.chars() {
191      data.push(c);
192      if c == '\n' {
193        index_map.push(Vec::new());
194        current_row += 1;
195        current_col = 0;
196      } else {
197        index_map[current_row].push(data.len() - 1);
198        current_col += 1;
199      }
200    }
201    let rows = index_map.len();
202    let cols = if rows > 0 { index_map[0].len() } else { 0 };
203    IndexedString {
204      data,
205      index_map,
206      rows,
207      cols,
208    }
209  }
210
211  fn to_string(&self) -> String {
212    self.data.iter().collect()
213  }
214
215  fn get(&self, row: usize, col: usize) -> Option<char> {
216    if row < self.rows {
217      let rowz = &self.index_map[row];
218      if col < rowz.len() {
219        let index = self.index_map[row][col];
220        Some(self.data[index])
221      } else {
222        None
223      }
224    } else {
225      None
226    }
227  }
228
229  fn set(&mut self, row: usize, col: usize, new_char: char) -> Result<(), String> {
230    if row < self.rows {
231      let row_indices = &mut self.index_map[row];
232      if col < row_indices.len() {
233        let index = row_indices[col];
234        self.data[index] = new_char;
235        Ok(())
236      } else {
237        Err("Column index out of bounds".to_string())
238      }
239    } else {
240      Err("Row index out of bounds".to_string())
241    }
242  }
243}
244
245// Humanize
246// ---------------------------------------------------------------------------
247
248// Turn bytes into something more readable by humans
249// Useful for visualizing register dumps, hashes, etc.
250
251pub fn hash_chars(input: &Vec<char>) -> u64 {
252  seahash::hash(input.iter().map(|s| String::from(*s)).collect::<String>().as_bytes()) & 0x00FFFFFFFFFFFFFF
253}
254
255pub fn hash_bytes(input: &Vec<u8>) -> u64 {
256  seahash::hash(input) & 0x00FFFFFFFFFFFFFF
257}
258
259pub fn hash_str(input: &str) -> u64 {
260  seahash::hash(input.as_bytes()) & 0x00FFFFFFFFFFFFFF
261}
262
263pub fn emojify_bytes(bytes: &[u8]) -> String {
264  let start = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len() - 1);
265  let mut out = String::new();
266  for &b in &bytes[start..] {
267    out.push_str(EMOJILIST[b as usize]);
268  }
269  out
270}
271
272pub fn humanize_bytes(bytes: &[u8]) -> String {
273  let parts: Vec<&str> = bytes
274    .iter()
275    .enumerate()
276    .filter_map(|(ix, &b)| if ix % 2 == 1 { Some(WORDLIST[b as usize]) } else { None })
277    .collect();
278  parts.join("-")
279}
280
281pub fn emojify<T>(num: &T) -> String
282where
283    T: Display + Copy + TryInto<u128>,
284    <T as TryInto<u128>>::Error: std::fmt::Debug,
285{
286  match (*num).try_into() {
287    Ok(v) => {
288      let bytes = v.to_be_bytes();
289      emojify_bytes(&bytes)
290    }
291    Err(_) => format!("{}", num),
292  }
293}
294
295pub fn humanize<T>(num: &T) -> String
296where
297  T: Display + Copy + TryInto<u128>,
298  <T as TryInto<u128>>::Error: Debug,
299{
300  match (*num).try_into() {
301    Ok(v) => {
302      let bytes = v.to_be_bytes();
303      let first_non_zero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len() - 1);
304      let trimmed = &bytes[first_non_zero..];
305      humanize_bytes(trimmed)
306    }
307    Err(_) => format!("{}", num),
308}
309}
310
311pub const WORDLIST: &[&str;256] = &[
312  "nil", "ama", "ine", "ska", "pha", "gel", "art", 
313  "ona", "sas", "ist", "aus", "pen", "ust", "umn",
314  "ado", "con", "loo", "man", "eer", "lin", "ium",
315  "ack", "som", "lue", "ird", "avo", "dog", "ger",
316  "ter", "nia", "bon", "nal", "ina", "pet", "cat",
317  "ing", "lie", "ken", "fee", "ola", "old", "rad",
318  "met", "cut", "azy", "cup", "ota", "dec", "del",
319  "elt", "iet", "don", "ble", "ear", "rth", "eas", 
320  "war", "eig", "tee", "ele", "emm", "ene", "qua",
321  "tst", "fan", "fif", "fil", "fin", "fis", "fiv", 
322  "flo", "for", "foo", "fou", "fot", "fox", "fre",
323  "fri", "fru", "gee", "gia", "glu", "fol", "gre", 
324  "ham", "hap", "har", "haw", "hel", "hig", "hot", 
325  "hyd", "ida", "ill", "ind", "ini", "ink", "iwa",
326  "and", "ite", "jer", "jig", "joh", "jul", "uly", 
327  "kan", "ket", "kil", "kin", "kit", "lac", "lak", 
328  "lem", "ard", "lim", "lio", "lit", "lon", "lou",
329  "low", "mag", "nes", "mai", "gam", "arc", "mar",
330  "mao", "mas", "may", "mex", "mic", "mik", "ril",
331  "min", "mir", "mis", "mio", "mob", "moc", "ech",
332  "moe", "tan", "oon", "ain", "mup", "sic", "neb",
333  "une", "net", "nev", "nin", "een", "nit", "nor",
334  "nov", "nut", "oct", "ohi", "okl", "one", "ora",
335  "ges", "ore", "osc", "ove", "oxy", "pap", "par", 
336  "pey", "pip", "piz", "plu", "pot", "pri", "pur",
337  "que", "uqi", "qui", "red", "riv", "rob", "roi", 
338  "rug", "sad", "sal", "sat", "sep", "sev", "eve",
339  "sha", "sie", "sin", "sik", "six", "sit", "sky", 
340  "soc", "sod", "sol", "sot", "tir", "ker", "spr",
341  "sta", "ste", "mam", "mer", "swe", "tab", "tag", 
342  "see", "nis", "tex", "thi", "the", "tim", "tri",
343  "twe", "ent", "two", "unc", "ess", "uni", "ura", 
344  "veg", "ven", "ver", "vic", "vid", "vio", "vir",
345  "was", "est", "whi", "hit", "iam", "win", "his",
346  "wis", "olf", "wyo", "ray", "ank", "yel", "zeb",
347  "ulu", "fix", "gry", "hol", "jup", "lam", "pas",
348  "rom", "sne", "ten", "uta"];
349
350// Emoji list is for quicker visual scanning/recognition when comparing registers
351
352pub const EMOJILIST: &[&str; 256] = &[
353  "๐Ÿต","๐Ÿถ","๐Ÿบ","๐ŸฆŠ","๐Ÿฆ","๐Ÿฑ","๐Ÿˆ","๐Ÿˆ","๐Ÿฆ","๐Ÿท","๐Ÿฎ","๐Ÿฆฌ","๐Ÿฏ","๐Ÿด","๐ŸซŽ","๐Ÿฆ„","๐Ÿฆ“","๐Ÿฆ™","๐Ÿฆ’","๐Ÿ˜","๐Ÿฆฃ","๐Ÿฆ","๐Ÿฆ›","๐Ÿซ","๐Ÿ","๐Ÿญ","๐Ÿฐ","๐Ÿฟ๏ธ","๐Ÿฆซ","๐Ÿฆ”","๐Ÿฆ‡","๐Ÿป","๐Ÿจ","๐Ÿผ","๐Ÿฆฅ","๐Ÿฆฆ","๐Ÿฆจ","๐Ÿฆ˜","๐Ÿฆก","๐Ÿฆƒ","๐Ÿ”","๐Ÿฆ","๐Ÿง","๐Ÿ•Š๏ธ","๐Ÿฆ…","๐Ÿฆ†","๐Ÿฆโ€๐Ÿ”ฅ","๐Ÿฆ‰","๐Ÿฆค","๐Ÿฆฉ","๐Ÿฆš","๐Ÿฆœ","๐Ÿธ","๐ŸŠ","๐Ÿข","๐ŸฆŽ","๐Ÿ","๐Ÿฒ","๐Ÿฆ–","๐Ÿณ","๐Ÿฌ","๐Ÿฆญ","๐Ÿ ","๐Ÿฆˆ","๐Ÿ™","๐Ÿชผ","๐Ÿฆ€","๐Ÿฆž","๐Ÿฆ","๐Ÿฆ‘","๐ŸŒ","๐Ÿฆ‹","๐Ÿ›","๐Ÿ","๐Ÿชฒ","๐Ÿž","๐Ÿฆ—","๐Ÿ•ธ๏ธ","๐Ÿชฐ","๐Ÿชฑ","๐Ÿฆ ","๐Ÿ‘ป","๐Ÿ‘ฝ","๐Ÿถ","๐Ÿฎ","๐Ÿš","๐Ÿชธ","๐Ÿชถ","๐Ÿฆง","๐Ÿชฟ","๐Ÿฆข","๐Ÿค–",
354  "๐ŸŒน","๐ŸŒณ","๐ŸŒด","๐ŸŒต","๐Ÿ€","๐Ÿ","๐Ÿ„","๐ŸŒ›","๐ŸŒž","๐Ÿช","โญ","โ›…","๐ŸŒง๏ธ","๐ŸŒจ๏ธ","๐ŸŒˆ","โ„๏ธ","โ˜ƒ๏ธ","โ˜„๏ธ","๐Ÿ”ฅ","๐ŸŒป",
355  "๐Ÿ‡","๐Ÿ‰","๐ŸŠ","๐Ÿ‹","๐Ÿ‹โ€๐ŸŸฉ","๐ŸŒ","๐Ÿ","๐Ÿฅญ","๐ŸŽ","๐Ÿ","๐Ÿ“","๐Ÿฅ","๐Ÿ…","๐Ÿซ’","๐Ÿฅฅ","๐Ÿฅ”","๐Ÿฅ•","๐ŸŒฝ","๐ŸŒถ๏ธ","๐Ÿซ‘","๐Ÿฅ’","๐Ÿฅฆ","๐Ÿง„","๐Ÿง…","๐Ÿซ›","๐Ÿฆ","๐Ÿง","๐Ÿฉ","๐Ÿช","๐Ÿฐ","๐Ÿง","๐Ÿฅง","๐Ÿซ","๐Ÿญ","๐Ÿž","๐Ÿฅจ","๐Ÿฅฏ","๐Ÿง‡","๐ŸŸ","๐Ÿฟ","๐Ÿงƒ",
356  "๐ŸŽค","๐ŸŽง","๐Ÿ“ป","๐ŸŽท","๐Ÿช—","๐ŸŽธ","๐ŸŽน","๐ŸŽบ","๐ŸŽป","๐Ÿช‡","๐Ÿฅ","โš—๏ธ","๐Ÿ“ท","๐Ÿงณ","๐ŸŒก๏ธ","๐Ÿงธ","๐Ÿงถ","๐Ÿ”Ž","๐Ÿ•ฏ๏ธ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ”’","๐Ÿ—๏ธ","๐Ÿชš","๐Ÿ”ง","๐Ÿช›","๐Ÿ”ฉ","โš™๏ธ","โš–๏ธ","๐Ÿงฐ","๐Ÿงฒ","๐Ÿชœ","๐Ÿ”ฌ","๐Ÿ“ก","๐Ÿงท","๐Ÿงน","๐Ÿงบ","๐Ÿชฃ","๐Ÿงผ","๐Ÿงฝ","๐Ÿงฏ","๐Ÿ›’",  
357  "โฐ","๐Ÿ›Ÿ","๐Ÿ›ฉ๏ธ","๐Ÿš","๐Ÿ›ฐ๏ธ","๐Ÿš€","๐Ÿ›ธ","โš“","๐Ÿš‚","๐Ÿš‘","๐Ÿš’","๐Ÿš•","๐Ÿš—","๐Ÿšš","๐Ÿšœ","๐ŸŽ๏ธ","๐Ÿ๏ธ","๐Ÿ›ต","๐Ÿฆผ","๐Ÿšฒ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ž","๐Ÿ“ฐ","๐Ÿ“ฆ","๐Ÿ“ซ","โœ๏ธ","๐Ÿ–Š๏ธ","๐Ÿ–Œ๏ธ","๐Ÿ–๏ธ","๐Ÿ“Œ","๐Ÿ“","โœ‚๏ธ","๐Ÿ—‘๏ธ","๐Ÿ†","โšพ","๐Ÿ€","๐ŸŽพ","๐ŸŽณ","โ›ณ","โ›ธ๏ธ","๐Ÿคฟ","๐Ÿ›ท","๐ŸŽฏ","๐Ÿช","๐Ÿงฉ","๐Ÿช…","๐ŸŽจ","๐Ÿงญ","๐Ÿ”๏ธ","๐Ÿ๏ธ","โ›ฒ","โ›บ","๐ŸŽ ","๐Ÿ›","๐Ÿงต","๐Ÿ’ˆ","๐ŸŽช","๐Ÿ›Ž๏ธ","๐Ÿ’Ž","โ›ต"
358];