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, FunctionDefinition>;
23pub type FunctionCompilerTable = HashMap<u64, Box<dyn NativeFunctionCompiler>>;
24
25pub trait MechFunctionImpl {
26  fn solve(&self);
27  fn out(&self) -> Value;
28  fn to_string(&self) -> String;
29}
30
31#[cfg(feature = "compiler")]
32pub trait MechFunctionCompiler {
33  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register>;
34}
35
36#[cfg(feature = "compiler")]
37pub trait MechFunction: MechFunctionImpl + MechFunctionCompiler {}
38#[cfg(feature = "compiler")]
39impl<T> MechFunction for T where T: MechFunctionImpl + MechFunctionCompiler {}
40
41#[cfg(not(feature = "compiler"))]
42pub trait MechFunction: MechFunctionImpl {}
43#[cfg(not(feature = "compiler"))]
44impl<T> MechFunction for T where T: MechFunctionImpl {}
45
46pub trait NativeFunctionCompiler {
47  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>>;
48}
49
50pub struct Functions {
51  pub functions: FunctionTable,
52  pub function_compilers: FunctionCompilerTable,
53}
54
55impl Functions {
56  pub fn new() -> Self {
57    Self {
58      functions: HashMap::new(), 
59      function_compilers: HashMap::new(), 
60    }
61  }
62}
63
64#[derive(Clone)]
65pub struct FunctionDefinition {
66  pub code: FunctionDefine,
67  pub id: u64,
68  pub name: String,
69  pub input: IndexMap<u64, KindAnnotation>,
70  pub output: IndexMap<u64, KindAnnotation>,
71  pub symbols: SymbolTableRef,
72  pub out: Ref<Value>,
73  pub plan: Plan,
74}
75
76impl fmt::Debug for FunctionDefinition {
77  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78    if cfg!(feature = "pretty_print") {
79      #[cfg(feature = "pretty_print")]
80      return fmt::Display::fmt(&self.pretty_print(), f);
81      fmt::Display::fmt(&"".to_string(), f)
82    } else {
83      write!(f, "FunctionDefinition {{ id: {}, name: {}, input: {:?}, output: {:?}, symbols: {:?} }}", 
84      self.id, self.name, self.input, self.output, self.symbols.borrow())
85    }
86  }
87}
88
89#[cfg(feature = "pretty_print")]
90impl PrettyPrint for FunctionDefinition {
91  fn pretty_print(&self) -> String {
92    let input_str = format!("{:#?}", self.input);
93    let output_str = format!("{:#?}", self.output);
94    let symbols_str = format!("{:#?}", self.symbols);
95    let mut plan_str = "".to_string();
96    for step in self.plan.borrow().iter() {
97      plan_str = format!("{}  - {}\n",plan_str,step.to_string());
98    }
99    let data = vec!["📥 Input", &input_str, 
100                    "📤 Output", &output_str, 
101                    "🔣 Symbols",   &symbols_str,
102                    "📋 Plan", &plan_str];
103    let mut table = tabled::Table::new(data);
104    table.with(Style::modern_rounded())
105         .with(Panel::header(format!("📈 UserFxn::{}\n({})", self.name, humanize(&self.id))))
106         .with(Alignment::left());
107    format!("{table}")
108  }
109}
110
111impl FunctionDefinition {
112
113  pub fn new(id: u64, name: String, code: FunctionDefine) -> Self {
114    Self {
115      id,
116      name,
117      code,
118      input: IndexMap::new(),
119      output: IndexMap::new(),
120      out: Ref::new(Value::Empty),
121      symbols: Ref::new(SymbolTable::new()),
122      plan: Plan::new(),
123    }
124  }
125
126  pub fn solve(&self) -> ValRef {
127    let plan_brrw = self.plan.borrow();
128    for step in plan_brrw.iter() {
129      let result = step.solve();
130    }
131    self.out.clone()
132  }
133
134  pub fn out(&self) -> ValRef {
135    self.out.clone()
136  }
137}
138
139// User Function --------------------------------------------------------------
140
141pub struct UserFunction {
142  pub fxn: FunctionDefinition,
143}
144
145impl MechFunctionImpl for UserFunction {
146  fn solve(&self) {
147    self.fxn.solve();
148  }
149  fn out(&self) -> Value {
150    Value::MutableReference(self.fxn.out.clone())
151  }
152  fn to_string(&self) -> String { format!("UserFxn::{:?}", self.fxn.name) }
153}
154#[cfg(feature = "compiler")]
155impl MechFunctionCompiler for UserFunction {
156  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
157    todo!();
158  }
159}
160
161// Plan
162// ----------------------------------------------------------------------------
163
164pub struct Plan(pub Ref<Vec<Box<dyn MechFunction>>>);
165
166impl Clone for Plan {
167  fn clone(&self) -> Self { Plan(self.0.clone()) }
168}
169
170impl fmt::Debug for Plan {
171  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172    for p in &(*self.0.borrow()) {
173      writeln!(f, "{}", p.to_string())?;
174    }
175    Ok(())
176  }
177}
178
179impl Plan {
180  pub fn new() -> Self { Plan(Ref::new(vec![])) }
181  pub fn borrow(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
182  pub fn borrow_mut(&self) -> std::cell::RefMut<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow_mut() }
183  pub fn add_function(&self, func: Box<dyn MechFunction>) { self.0.borrow_mut().push(func); }
184  pub fn get_functions(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
185  pub fn len(&self) -> usize { self.0.borrow().len() }
186  pub fn is_empty(&self) -> bool { self.0.borrow().is_empty() }
187}
188
189#[cfg(feature = "pretty_print")]
190impl PrettyPrint for Plan {
191  fn pretty_print(&self) -> String {
192    let mut builder = Builder::default();
193
194    let mut row = vec![];
195    let plan_brrw = self.0.borrow();
196    if self.is_empty() {
197      builder.push_record(vec!["".to_string()]);
198    } else {
199      for (ix, fxn) in plan_brrw.iter().enumerate() {
200        let plan_str = format!("{}. {}\n", ix + 1, fxn.to_string());
201        row.push(plan_str.clone());
202        if row.len() == 4 {
203          builder.push_record(row.clone());
204          row.clear();
205        }
206      }
207    }
208    if row.is_empty() == false {
209      builder.push_record(row.clone());
210    }
211    let mut table = builder.build();
212    table.with(Style::modern_rounded())
213        .with(Panel::header("📋 Plan"));
214    format!("{table}")
215  }
216}