Skip to main content

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>;
24pub type UserFunctionTable = HashMap<u64, FunctionDefinition>;
25
26#[derive(Clone,Debug)]
27pub enum FunctionArgs {
28  Nullary(Value),
29  Unary(Value, Value),
30  Binary(Value, Value, Value),
31  Ternary(Value, Value, Value, Value),
32  Quaternary(Value, Value, Value, Value, Value),
33  Variadic(Value, Vec<Value>),
34}
35
36impl FunctionArgs {
37  pub fn len(&self) -> usize {
38    match self {
39      FunctionArgs::Nullary(_) => 0,
40      FunctionArgs::Unary(_, _) => 1,
41      FunctionArgs::Binary(_, _, _) => 2,
42      FunctionArgs::Ternary(_, _, _, _) => 3,
43      FunctionArgs::Quaternary(_, _, _, _, _) => 4,
44      FunctionArgs::Variadic(_, args) => args.len(),
45    }
46  }
47}
48
49#[repr(C)]
50#[derive(Clone)]
51pub struct FunctionDescriptor {
52  pub name: &'static str,
53  pub ptr: fn(FunctionArgs) -> MResult<Box<dyn MechFunction>>,
54}
55
56impl Debug for FunctionDescriptor {
57  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58    write!(f, "{{ name: {:?}, ptr: {:?} }}", self.name, self.ptr)
59  }
60}
61
62unsafe impl Sync for FunctionDescriptor {}
63
64#[repr(C)]
65pub struct FunctionCompilerDescriptor {
66  pub name: &'static str,
67  pub ptr: &'static dyn NativeFunctionCompiler,
68}
69
70impl Debug for FunctionCompilerDescriptor {
71  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72    write!(f, "{:?}", self.name)
73  }
74}
75
76unsafe impl Sync for FunctionCompilerDescriptor {}
77
78pub trait MechFunctionFactory {
79  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>>;
80}
81
82pub trait MechFunctionImpl {
83  fn solve(&self);
84  fn out(&self) -> Value;
85  fn to_string(&self) -> String;
86}
87
88#[cfg(feature = "compiler")]
89pub trait MechFunctionCompiler {
90  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register>;
91}
92
93#[cfg(feature = "compiler")]
94pub trait MechFunction: MechFunctionImpl + MechFunctionCompiler {}
95#[cfg(feature = "compiler")]
96impl<T> MechFunction for T where T: MechFunctionImpl + MechFunctionCompiler {}
97
98#[cfg(not(feature = "compiler"))]
99pub trait MechFunction: MechFunctionImpl {}
100#[cfg(not(feature = "compiler"))]
101impl<T> MechFunction for T where T: MechFunctionImpl {}
102
103pub trait NativeFunctionCompiler {
104  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>>;
105}
106
107#[derive(Clone)]
108pub struct Functions {
109  pub functions: FunctionTable,
110  pub function_compilers: FunctionCompilerTable,
111  pub user_functions: UserFunctionTable,
112  pub dictionary: Ref<Dictionary>,
113}
114
115impl Functions {
116  pub fn new() -> Self {
117    Self {
118      functions: HashMap::new(),
119      function_compilers: HashMap::new(),
120      user_functions: HashMap::new(),
121      dictionary: Ref::new(Dictionary::new()),
122    }
123  }
124
125  pub fn insert_function(&mut self, fxn: FunctionDescriptor) {
126    let id = hash_str(&fxn.name);
127    self.functions.insert(id.clone(), fxn.ptr);
128    self.dictionary.borrow_mut().insert(id, fxn.name.to_string());
129  }
130
131  #[cfg(feature = "pretty_print")]
132  pub fn pretty_print(&self) -> String {
133    let mut output = String::new();
134    output.push_str("\nFunctions:\n");
135    // print number of functions loaded:
136    output.push_str(&format!("Total Functions: {}\n", self.functions.len()));
137    output.push_str(&format!("User Functions: {}\n", self.user_functions.len()));
138    //for (id, fxn_ptr) in &self.functions {
139    //  let dict_brrw = self.dictionary.borrow();
140    //  let name = dict_brrw.get(id).unwrap();
141    //  output.push_str(&format!("  {}: {:?}\n", name, fxn_ptr));
142    //}
143    output
144  }
145
146}
147
148#[derive(Clone)]
149pub struct FunctionDefinition {
150  pub code: FunctionDefine,
151  pub id: u64,
152  pub name: String,
153  pub input: IndexMap<u64, KindAnnotation>,
154  pub output: IndexMap<u64, KindAnnotation>,
155  pub symbols: SymbolTableRef,
156  pub out: Ref<Value>,
157  pub plan: Plan,
158}
159
160impl fmt::Debug for FunctionDefinition {
161  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162    if cfg!(feature = "pretty_print") {
163      #[cfg(feature = "pretty_print")]
164      return fmt::Display::fmt(&self.pretty_print(), f);
165      fmt::Display::fmt(&"".to_string(), f)
166    } else {
167      write!(f, "FunctionDefinition {{ id: {}, name: {}, input: {:?}, output: {:?}, symbols: {:?} }}",
168      self.id, self.name, self.input, self.output, self.symbols.borrow())
169    }
170  }
171}
172
173#[cfg(feature = "pretty_print")]
174impl PrettyPrint for FunctionDefinition {
175  fn pretty_print(&self) -> String {
176    let input_str = format!("{:#?}", self.input);
177    let output_str = format!("{:#?}", self.output);
178    let symbols_str = format!("{:#?}", self.symbols);
179    let mut plan_str = "".to_string();
180    for step in self.plan.borrow().iter() {
181      plan_str = format!("{}  - {}\n",plan_str,step.to_string());
182    }
183    let data = vec!["📥 Input", &input_str,
184                    "📤 Output", &output_str,
185                    "🔣 Symbols",   &symbols_str,
186                    "📋 Plan", &plan_str];
187    let mut table = tabled::Table::new(data);
188    table.with(Style::modern_rounded())
189         .with(Panel::header(format!("📈 UserFxn::{}\n({})", self.name, humanize(&self.id))))
190         .with(Alignment::left());
191    format!("{table}")
192  }
193}
194
195impl FunctionDefinition {
196
197  pub fn new(id: u64, name: String, code: FunctionDefine) -> Self {
198    Self {
199      id,
200      name,
201      code,
202      input: IndexMap::new(),
203      output: IndexMap::new(),
204      out: Ref::new(Value::Empty),
205      symbols: Ref::new(SymbolTable::new()),
206      plan: Plan::new(),
207    }
208  }
209
210  pub fn solve(&self) -> ValRef {
211    let plan_brrw = self.plan.borrow();
212    for step in plan_brrw.iter() {
213      let result = step.solve();
214    }
215    self.out.clone()
216  }
217
218  pub fn out(&self) -> ValRef {
219    self.out.clone()
220  }
221}
222
223// User Function --------------------------------------------------------------
224
225pub struct UserFunction {
226  pub fxn: FunctionDefinition,
227}
228
229impl MechFunctionImpl for UserFunction {
230  fn solve(&self) {
231    self.fxn.solve();
232  }
233  fn out(&self) -> Value {
234    self.fxn.out.borrow().clone()
235  }
236  fn to_string(&self) -> String { format!("UserFxn::{:?}", self.fxn.name) }
237}
238#[cfg(feature = "compiler")]
239impl MechFunctionCompiler for UserFunction {
240  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
241    todo!();
242  }
243}
244
245// Plan
246// ----------------------------------------------------------------------------
247
248pub struct Plan(pub Ref<Vec<Box<dyn MechFunction>>>);
249
250impl Clone for Plan {
251  fn clone(&self) -> Self { Plan(self.0.clone()) }
252}
253
254impl fmt::Debug for Plan {
255  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256    for p in &(*self.0.borrow()) {
257      writeln!(f, "{}", p.to_string())?;
258    }
259    Ok(())
260  }
261}
262
263impl Plan {
264  pub fn new() -> Self { Plan(Ref::new(vec![])) }
265  pub fn borrow(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
266  pub fn borrow_mut(&self) -> std::cell::RefMut<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow_mut() }
267  pub fn add_function(&self, func: Box<dyn MechFunction>) { self.0.borrow_mut().push(func); }
268  pub fn get_functions(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
269  pub fn len(&self) -> usize { self.0.borrow().len() }
270  pub fn is_empty(&self) -> bool { self.0.borrow().is_empty() }
271}
272
273#[cfg(feature = "pretty_print")]
274impl PrettyPrint for Plan {
275  fn pretty_print(&self) -> String {
276    let mut builder = Builder::default();
277    let plan_brrw = self.0.borrow();
278
279    if self.is_empty() {
280      builder.push_record(vec!["".to_string()]);
281    } else {
282      let total = plan_brrw.len();
283      let mut display_fxns: Vec<String> = Vec::new();
284
285      // Determine which functions to display
286      let indices: Vec<usize> = if total > 30 {
287          (0..10).chain((total - 10)..total).collect()
288      } else {
289          (0..total).collect()
290      };
291
292      for &ix in &indices {
293        let fxn_str = plan_brrw[ix].to_string();
294        let lines: Vec<&str> = fxn_str.lines().collect();
295
296        let truncated = if lines.len() > 20 {
297          let mut t = Vec::new();
298          t.extend_from_slice(&lines[..10]);           // first 10
299          t.push("…");                                 // ellipsis
300          t.extend_from_slice(&lines[lines.len()-10..]); // last 10
301          t.join("\n")
302        } else {
303          lines.join("\n")
304        };
305
306        display_fxns.push(format!("{}. {}", ix + 1, truncated));
307      }
308
309      // Insert ellipsis for skipped functions
310      if total > 30 {
311        display_fxns.insert(10, "…".to_string());
312      }
313
314      // Push rows in chunks of 4 (like before)
315      let mut row: Vec<String> = Vec::new();
316      for plan_str in display_fxns {
317        row.push(plan_str);
318        if row.len() == 4 {
319          builder.push_record(row.clone());
320          row.clear();
321        }
322      }
323      if !row.is_empty() {
324        builder.push_record(row);
325      }
326    }
327
328    let mut table = builder.build();
329    table.with(Style::modern_rounded())
330          .with(Panel::header("📋 Plan"));
331
332    format!("{table}")
333  }
334}
335
336
337
338// Function Registry
339// ----------------------------------------------------------------------------
340
341// Function registry is a mapping from function IDs to the actual fucntion implementaionts
342
343/*lazy_static! {
344  pub static ref FUNCTION_REGISTRY: RefCell<HashMap<u64, Box<dyn NativeFunctionCompiler>>> = RefCell::new(HashMap::new());
345}*/
346
347pub struct FunctionRegistry {
348  pub registry: RefCell<HashMap<u64, Box<dyn MechFunctionImpl>>>,
349}
350
351#[derive(Debug, Clone)]
352pub struct UnhandledFunctionArgumentKind1 {
353  pub arg: ValueKind,
354  pub fxn_name: String,
355}
356impl MechErrorKind for UnhandledFunctionArgumentKind1 {
357  fn name(&self) -> &str { "UnhandledFunctionArgumentKind1" }
358  fn message(&self) -> String {
359    format!("Unhandled function argument kind for function '{}': arg = {:?}", self.fxn_name, self.arg)
360  }
361}
362
363#[derive(Debug, Clone)]
364pub struct UnhandledFunctionArgumentKind2 {
365  pub arg: (ValueKind, ValueKind),
366  pub fxn_name: String,
367}
368impl MechErrorKind for UnhandledFunctionArgumentKind2 {
369  fn name(&self) -> &str { "UnhandledFunctionArgumentKind2" }
370  fn message(&self) -> String {
371    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
372  }
373}
374
375#[derive(Debug, Clone)]
376pub struct UnhandledFunctionArgumentKind3 {
377  pub arg: (ValueKind, ValueKind, ValueKind),
378  pub fxn_name: String,
379}
380impl MechErrorKind for UnhandledFunctionArgumentKind3 {
381  fn name(&self) -> &str { "UnhandledFunctionArgumentKind3" }
382  fn message(&self) -> String {
383    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
384  }
385}
386
387#[derive(Debug, Clone)]
388pub struct UnhandledFunctionArgumentKind4 {
389  pub arg: (ValueKind, ValueKind, ValueKind, ValueKind),
390  pub fxn_name: String,
391}
392impl MechErrorKind for UnhandledFunctionArgumentKind4 {
393  fn name(&self) -> &str { "UnhandledFunctionArgumentKind4" }
394  fn message(&self) -> String {
395    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
396  }
397}
398
399#[derive(Debug, Clone)]
400pub struct UnhandledFunctionArgumentKindVarg {
401  pub arg: Vec<ValueKind>,
402  pub fxn_name: String,
403}
404impl MechErrorKind for UnhandledFunctionArgumentKindVarg {
405  fn name(&self) -> &str { "UnhandledFunctionArgumentKindVarg" }
406  fn message(&self) -> String {
407    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
408  }
409}
410
411#[derive(Debug, Clone)]
412pub struct UnhandledFunctionArgumentIxes {
413  pub arg: (ValueKind, Vec<ValueKind>, ValueKind),
414  pub fxn_name: String,
415}
416impl MechErrorKind for UnhandledFunctionArgumentIxes {
417  fn name(&self) -> &str { "UnhandledFunctionArgumentIxes" }
418  fn message(&self) -> String {
419    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
420  }
421}
422
423#[derive(Debug, Clone)]
424pub struct UnhandledFunctionArgumentIxesMono {
425  pub arg: (ValueKind, Vec<ValueKind>),
426  pub fxn_name: String,
427}
428impl MechErrorKind for UnhandledFunctionArgumentIxesMono {
429  fn name(&self) -> &str { "UnhandledFunctionArgumentIxesMono" }
430  fn message(&self) -> String {
431    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
432  }
433}
434
435#[derive(Debug, Clone)]
436pub struct IncorrectNumberOfArguments {
437  pub expected: usize,
438  pub found: usize,
439}
440impl MechErrorKind for IncorrectNumberOfArguments {
441  fn name(&self) -> &str {
442    "IncorrectNumberOfArguments"
443  }
444
445  fn message(&self) -> String {
446    format!("Expected {} arguments, but found {}", self.expected, self.found)
447  }
448}