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
129}
130
131#[derive(Clone)]
132pub struct FunctionDefinition {
133  pub code: FunctionDefine,
134  pub id: u64,
135  pub name: String,
136  pub input: IndexMap<u64, KindAnnotation>,
137  pub output: IndexMap<u64, KindAnnotation>,
138  pub symbols: SymbolTableRef,
139  pub out: Ref<Value>,
140  pub plan: Plan,
141}
142
143impl fmt::Debug for FunctionDefinition {
144  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145    if cfg!(feature = "pretty_print") {
146      #[cfg(feature = "pretty_print")]
147      return fmt::Display::fmt(&self.pretty_print(), f);
148      fmt::Display::fmt(&"".to_string(), f)
149    } else {
150      write!(f, "FunctionDefinition {{ id: {}, name: {}, input: {:?}, output: {:?}, symbols: {:?} }}", 
151      self.id, self.name, self.input, self.output, self.symbols.borrow())
152    }
153  }
154}
155
156#[cfg(feature = "pretty_print")]
157impl PrettyPrint for FunctionDefinition {
158  fn pretty_print(&self) -> String {
159    let input_str = format!("{:#?}", self.input);
160    let output_str = format!("{:#?}", self.output);
161    let symbols_str = format!("{:#?}", self.symbols);
162    let mut plan_str = "".to_string();
163    for step in self.plan.borrow().iter() {
164      plan_str = format!("{}  - {}\n",plan_str,step.to_string());
165    }
166    let data = vec!["📥 Input", &input_str, 
167                    "📤 Output", &output_str, 
168                    "🔣 Symbols",   &symbols_str,
169                    "📋 Plan", &plan_str];
170    let mut table = tabled::Table::new(data);
171    table.with(Style::modern_rounded())
172         .with(Panel::header(format!("📈 UserFxn::{}\n({})", self.name, humanize(&self.id))))
173         .with(Alignment::left());
174    format!("{table}")
175  }
176}
177
178impl FunctionDefinition {
179
180  pub fn new(id: u64, name: String, code: FunctionDefine) -> Self {
181    Self {
182      id,
183      name,
184      code,
185      input: IndexMap::new(),
186      output: IndexMap::new(),
187      out: Ref::new(Value::Empty),
188      symbols: Ref::new(SymbolTable::new()),
189      plan: Plan::new(),
190    }
191  }
192
193  pub fn solve(&self) -> ValRef {
194    let plan_brrw = self.plan.borrow();
195    for step in plan_brrw.iter() {
196      let result = step.solve();
197    }
198    self.out.clone()
199  }
200
201  pub fn out(&self) -> ValRef {
202    self.out.clone()
203  }
204}
205
206// User Function --------------------------------------------------------------
207
208pub struct UserFunction {
209  pub fxn: FunctionDefinition,
210}
211
212impl MechFunctionImpl for UserFunction {
213  fn solve(&self) {
214    self.fxn.solve();
215  }
216  fn out(&self) -> Value {
217    Value::MutableReference(self.fxn.out.clone())
218  }
219  fn to_string(&self) -> String { format!("UserFxn::{:?}", self.fxn.name) }
220}
221#[cfg(feature = "compiler")]
222impl MechFunctionCompiler for UserFunction {
223  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
224    todo!();
225  }
226}
227
228// Plan
229// ----------------------------------------------------------------------------
230
231pub struct Plan(pub Ref<Vec<Box<dyn MechFunction>>>);
232
233impl Clone for Plan {
234  fn clone(&self) -> Self { Plan(self.0.clone()) }
235}
236
237impl fmt::Debug for Plan {
238  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239    for p in &(*self.0.borrow()) {
240      writeln!(f, "{}", p.to_string())?;
241    }
242    Ok(())
243  }
244}
245
246impl Plan {
247  pub fn new() -> Self { Plan(Ref::new(vec![])) }
248  pub fn borrow(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
249  pub fn borrow_mut(&self) -> std::cell::RefMut<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow_mut() }
250  pub fn add_function(&self, func: Box<dyn MechFunction>) { self.0.borrow_mut().push(func); }
251  pub fn get_functions(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
252  pub fn len(&self) -> usize { self.0.borrow().len() }
253  pub fn is_empty(&self) -> bool { self.0.borrow().is_empty() }
254}
255
256#[cfg(feature = "pretty_print")]
257impl PrettyPrint for Plan {
258  fn pretty_print(&self) -> String {
259    let mut builder = Builder::default();
260    let plan_brrw = self.0.borrow();
261
262    if self.is_empty() {
263      builder.push_record(vec!["".to_string()]);
264    } else {
265      let total = plan_brrw.len();
266      let mut display_fxns: Vec<String> = Vec::new();
267
268      // Determine which functions to display
269      let indices: Vec<usize> = if total > 30 {
270          (0..10).chain((total - 10)..total).collect()
271      } else {
272          (0..total).collect()
273      };
274
275      for &ix in &indices {
276        let fxn_str = plan_brrw[ix].to_string();
277        let lines: Vec<&str> = fxn_str.lines().collect();
278
279        let truncated = if lines.len() > 20 {
280          let mut t = Vec::new();
281          t.extend_from_slice(&lines[..10]);           // first 10
282          t.push("…");                                 // ellipsis
283          t.extend_from_slice(&lines[lines.len()-10..]); // last 10
284          t.join("\n")
285        } else {
286          lines.join("\n")
287        };
288
289        display_fxns.push(format!("{}. {}", ix + 1, truncated));
290      }
291
292      // Insert ellipsis for skipped functions
293      if total > 30 {
294        display_fxns.insert(10, "…".to_string());
295      }
296
297      // Push rows in chunks of 4 (like before)
298      let mut row: Vec<String> = Vec::new();
299      for plan_str in display_fxns {
300        row.push(plan_str);
301        if row.len() == 4 {
302          builder.push_record(row.clone());
303          row.clear();
304        }
305      }
306      if !row.is_empty() {
307        builder.push_record(row);
308      }
309    }
310
311    let mut table = builder.build();
312    table.with(Style::modern_rounded())
313          .with(Panel::header("📋 Plan"));
314
315    format!("{table}")
316  }
317}
318
319
320
321// Function Registry
322// ----------------------------------------------------------------------------
323
324// Function registry is a mapping from function IDs to the actual fucntion implementaionts
325
326/*lazy_static! {
327  pub static ref FUNCTION_REGISTRY: RefCell<HashMap<u64, Box<dyn NativeFunctionCompiler>>> = RefCell::new(HashMap::new());
328}*/
329
330pub struct FunctionRegistry {
331  pub registry: RefCell<HashMap<u64, Box<dyn MechFunctionImpl>>>,
332}
333
334#[derive(Debug, Clone)]
335pub struct UnhandledFunctionArgumentKind1 {
336  pub arg: ValueKind,
337  pub fxn_name: String,
338}
339impl MechErrorKind2 for UnhandledFunctionArgumentKind1 {
340  fn name(&self) -> &str { "UnhandledFunctionArgumentKind1" }
341  fn message(&self) -> String {
342    format!("Unhandled function argument kind for function '{}': arg = {:?}", self.fxn_name, self.arg)
343  }
344}
345
346#[derive(Debug, Clone)]
347pub struct UnhandledFunctionArgumentKind2 {
348  pub arg: (ValueKind, ValueKind),
349  pub fxn_name: String,
350}
351impl MechErrorKind2 for UnhandledFunctionArgumentKind2 {
352  fn name(&self) -> &str { "UnhandledFunctionArgumentKind2" }
353  fn message(&self) -> String {
354    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
355  }
356}
357
358#[derive(Debug, Clone)]
359pub struct UnhandledFunctionArgumentKind3 {
360  pub arg: (ValueKind, ValueKind, ValueKind),
361  pub fxn_name: String,
362}
363impl MechErrorKind2 for UnhandledFunctionArgumentKind3 {
364  fn name(&self) -> &str { "UnhandledFunctionArgumentKind3" }
365  fn message(&self) -> String {
366    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
367  }
368}
369
370#[derive(Debug, Clone)]
371pub struct UnhandledFunctionArgumentKind4 {
372  pub arg: (ValueKind, ValueKind, ValueKind, ValueKind),
373  pub fxn_name: String,
374}
375impl MechErrorKind2 for UnhandledFunctionArgumentKind4 {
376  fn name(&self) -> &str { "UnhandledFunctionArgumentKind4" }
377  fn message(&self) -> String {
378    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
379  }
380}
381
382#[derive(Debug, Clone)]
383pub struct UnhandledFunctionArgumentKindVarg {
384  pub arg: Vec<ValueKind>,
385  pub fxn_name: String,
386}
387impl MechErrorKind2 for UnhandledFunctionArgumentKindVarg {
388  fn name(&self) -> &str { "UnhandledFunctionArgumentKindVarg" }
389  fn message(&self) -> String {
390    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
391  }
392}
393
394#[derive(Debug, Clone)]
395pub struct UnhandledFunctionArgumentIxes {
396  pub arg: (ValueKind, Vec<ValueKind>, ValueKind),
397  pub fxn_name: String,
398}
399impl MechErrorKind2 for UnhandledFunctionArgumentIxes {
400  fn name(&self) -> &str { "UnhandledFunctionArgumentIxes" }
401  fn message(&self) -> String {
402    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
403  }
404}
405
406#[derive(Debug, Clone)]
407pub struct UnhandledFunctionArgumentIxesMono {
408  pub arg: (ValueKind, Vec<ValueKind>),
409  pub fxn_name: String,
410}
411impl MechErrorKind2 for UnhandledFunctionArgumentIxesMono {
412  fn name(&self) -> &str { "UnhandledFunctionArgumentIxesMono" }
413  fn message(&self) -> String {
414    format!("Unhandled function argument kinds for function '{}': arg = {:?}", self.fxn_name, self.arg)
415  }
416}
417
418#[derive(Debug, Clone)]
419pub struct IncorrectNumberOfArguments {
420  pub expected: usize,
421  pub found: usize,
422}
423impl MechErrorKind2 for IncorrectNumberOfArguments {
424  fn name(&self) -> &str {
425    "IncorrectNumberOfArguments"
426  }
427
428  fn message(&self) -> String {
429    format!("Expected {} arguments, but found {}", self.expected, self.found)
430  }
431}