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