mech_core/
functions.rs

1use crate::types::*;
2use crate::value::*;
3use crate::nodes::*;
4use crate::*;
5
6use std::collections::HashMap;
7#[cfg(feature = "functions")]
8use indexmap::map::IndexMap;
9use std::rc::Rc;
10use std::cell::RefCell;
11#[cfg(feature = "pretty_print")]
12use tabled::{
13  builder::Builder,
14  settings::{object::Rows,Panel, Span, Alignment, Modify, Style},
15  Tabled,
16};
17use std::fmt;
18
19// Functions ------------------------------------------------------------------
20
21pub type FunctionsRef = Ref<Functions>;
22pub type FunctionTable = HashMap<u64, fn(FunctionArgs) -> MResult<Box<dyn MechFunction>>>;
23pub type FunctionCompilerTable = HashMap<u64, &'static dyn NativeFunctionCompiler>;
24
25#[derive(Clone,Debug)]
26pub enum FunctionArgs {
27  Nullary(Value),
28  Unary(Value, Value),
29  Binary(Value, Value, Value),
30  Ternary(Value, Value, Value, Value),
31  Quaternary(Value, Value, Value, Value, Value),
32  Variadic(Value, Vec<Value>),
33}
34
35#[repr(C)]
36#[derive(Clone)]
37pub struct FunctionDescriptor {
38  pub name: &'static str,
39  pub ptr: fn(FunctionArgs) -> MResult<Box<dyn MechFunction>>,
40}
41
42impl Debug for FunctionDescriptor {
43  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44    write!(f, "{{ name: {:?}, ptr: {:?} }}", self.name, self.ptr)
45  }
46}
47
48unsafe impl Sync for FunctionDescriptor {}
49
50#[repr(C)]
51pub struct FunctionCompilerDescriptor {
52  pub name: &'static str,
53  pub ptr: &'static dyn NativeFunctionCompiler,
54}
55
56impl Debug for FunctionCompilerDescriptor {
57  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58    write!(f, "{:?}", self.name)
59  }
60}
61
62unsafe impl Sync for FunctionCompilerDescriptor {}
63
64pub trait MechFunctionFactory {
65  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>>;
66}
67
68pub trait MechFunctionImpl {
69  fn solve(&self);
70  fn out(&self) -> Value;
71  fn to_string(&self) -> String;
72}
73
74#[cfg(feature = "compiler")]
75pub trait MechFunctionCompiler {
76  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register>;
77}
78
79#[cfg(feature = "compiler")]
80pub trait MechFunction: MechFunctionImpl + MechFunctionCompiler {}
81#[cfg(feature = "compiler")]
82impl<T> MechFunction for T where T: MechFunctionImpl + MechFunctionCompiler {}
83
84#[cfg(not(feature = "compiler"))]
85pub trait MechFunction: MechFunctionImpl {}
86#[cfg(not(feature = "compiler"))]
87impl<T> MechFunction for T where T: MechFunctionImpl {}
88
89pub trait NativeFunctionCompiler {
90  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>>;
91}
92
93#[derive(Clone)]
94pub struct Functions {
95  pub functions: FunctionTable,
96  pub function_compilers: FunctionCompilerTable,
97  pub dictionary: Ref<Dictionary>,
98}
99
100impl Functions {
101  pub fn new() -> Self {
102    Self {
103      functions: HashMap::new(), 
104      function_compilers: HashMap::new(), 
105      dictionary: Ref::new(Dictionary::new()),
106    }
107  }
108
109  pub fn insert_function(&mut self, fxn: FunctionDescriptor) {
110    let id = hash_str(&fxn.name);
111    self.functions.insert(id.clone(), fxn.ptr);
112    self.dictionary.borrow_mut().insert(id, fxn.name.to_string());
113  }
114
115
116}
117
118#[derive(Clone)]
119pub struct FunctionDefinition {
120  pub code: FunctionDefine,
121  pub id: u64,
122  pub name: String,
123  pub input: IndexMap<u64, KindAnnotation>,
124  pub output: IndexMap<u64, KindAnnotation>,
125  pub symbols: SymbolTableRef,
126  pub out: Ref<Value>,
127  pub plan: Plan,
128}
129
130impl fmt::Debug for FunctionDefinition {
131  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132    if cfg!(feature = "pretty_print") {
133      #[cfg(feature = "pretty_print")]
134      return fmt::Display::fmt(&self.pretty_print(), f);
135      fmt::Display::fmt(&"".to_string(), f)
136    } else {
137      write!(f, "FunctionDefinition {{ id: {}, name: {}, input: {:?}, output: {:?}, symbols: {:?} }}", 
138      self.id, self.name, self.input, self.output, self.symbols.borrow())
139    }
140  }
141}
142
143#[cfg(feature = "pretty_print")]
144impl PrettyPrint for FunctionDefinition {
145  fn pretty_print(&self) -> String {
146    let input_str = format!("{:#?}", self.input);
147    let output_str = format!("{:#?}", self.output);
148    let symbols_str = format!("{:#?}", self.symbols);
149    let mut plan_str = "".to_string();
150    for step in self.plan.borrow().iter() {
151      plan_str = format!("{}  - {}\n",plan_str,step.to_string());
152    }
153    let data = vec!["📥 Input", &input_str, 
154                    "📤 Output", &output_str, 
155                    "🔣 Symbols",   &symbols_str,
156                    "📋 Plan", &plan_str];
157    let mut table = tabled::Table::new(data);
158    table.with(Style::modern_rounded())
159         .with(Panel::header(format!("📈 UserFxn::{}\n({})", self.name, humanize(&self.id))))
160         .with(Alignment::left());
161    format!("{table}")
162  }
163}
164
165impl FunctionDefinition {
166
167  pub fn new(id: u64, name: String, code: FunctionDefine) -> Self {
168    Self {
169      id,
170      name,
171      code,
172      input: IndexMap::new(),
173      output: IndexMap::new(),
174      out: Ref::new(Value::Empty),
175      symbols: Ref::new(SymbolTable::new()),
176      plan: Plan::new(),
177    }
178  }
179
180  pub fn solve(&self) -> ValRef {
181    let plan_brrw = self.plan.borrow();
182    for step in plan_brrw.iter() {
183      let result = step.solve();
184    }
185    self.out.clone()
186  }
187
188  pub fn out(&self) -> ValRef {
189    self.out.clone()
190  }
191}
192
193// User Function --------------------------------------------------------------
194
195pub struct UserFunction {
196  pub fxn: FunctionDefinition,
197}
198
199impl MechFunctionImpl for UserFunction {
200  fn solve(&self) {
201    self.fxn.solve();
202  }
203  fn out(&self) -> Value {
204    Value::MutableReference(self.fxn.out.clone())
205  }
206  fn to_string(&self) -> String { format!("UserFxn::{:?}", self.fxn.name) }
207}
208#[cfg(feature = "compiler")]
209impl MechFunctionCompiler for UserFunction {
210  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
211    todo!();
212  }
213}
214
215// Plan
216// ----------------------------------------------------------------------------
217
218pub struct Plan(pub Ref<Vec<Box<dyn MechFunction>>>);
219
220impl Clone for Plan {
221  fn clone(&self) -> Self { Plan(self.0.clone()) }
222}
223
224impl fmt::Debug for Plan {
225  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226    for p in &(*self.0.borrow()) {
227      writeln!(f, "{}", p.to_string())?;
228    }
229    Ok(())
230  }
231}
232
233impl Plan {
234  pub fn new() -> Self { Plan(Ref::new(vec![])) }
235  pub fn borrow(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
236  pub fn borrow_mut(&self) -> std::cell::RefMut<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow_mut() }
237  pub fn add_function(&self, func: Box<dyn MechFunction>) { self.0.borrow_mut().push(func); }
238  pub fn get_functions(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
239  pub fn len(&self) -> usize { self.0.borrow().len() }
240  pub fn is_empty(&self) -> bool { self.0.borrow().is_empty() }
241}
242
243#[cfg(feature = "pretty_print")]
244impl PrettyPrint for Plan {
245  fn pretty_print(&self) -> String {
246    let mut builder = Builder::default();
247
248    let mut row = vec![];
249    let plan_brrw = self.0.borrow();
250    if self.is_empty() {
251      builder.push_record(vec!["".to_string()]);
252    } else {
253      for (ix, fxn) in plan_brrw.iter().enumerate() {
254        let plan_str = format!("{}. {}\n", ix + 1, fxn.to_string());
255        row.push(plan_str.clone());
256        if row.len() == 4 {
257          builder.push_record(row.clone());
258          row.clear();
259        }
260      }
261    }
262    if row.is_empty() == false {
263      builder.push_record(row.clone());
264    }
265    let mut table = builder.build();
266    table.with(Style::modern_rounded())
267        .with(Panel::header("📋 Plan"));
268    format!("{table}")
269  }
270}
271
272// Function Registry
273// ----------------------------------------------------------------------------
274
275// Function registry is a mapping from function IDs to the actual fucntion implementaionts
276
277/*lazy_static! {
278  pub static ref FUNCTION_REGISTRY: RefCell<HashMap<u64, Box<dyn NativeFunctionCompiler>>> = RefCell::new(HashMap::new());
279}*/
280
281pub struct FunctionRegistry {
282  pub registry: RefCell<HashMap<u64, Box<dyn MechFunctionImpl>>>,
283}