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