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