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
19pub type FunctionsRef = Ref<Functions>;
22pub type FunctionTable = HashMap<u64, fn(FunctionArgs) -> MResult<Box<dyn MechFunction>>>;
23pub type FunctionCompilerTable = HashMap<u64, Box<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
50pub trait MechFunctionFactory {
51 fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>>;
52}
53
54pub trait MechFunctionImpl {
55 fn solve(&self);
56 fn out(&self) -> Value;
57 fn to_string(&self) -> String;
58}
59
60#[cfg(feature = "compiler")]
61pub trait MechFunctionCompiler {
62 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register>;
63}
64
65#[cfg(feature = "compiler")]
66pub trait MechFunction: MechFunctionImpl + MechFunctionCompiler {}
67#[cfg(feature = "compiler")]
68impl<T> MechFunction for T where T: MechFunctionImpl + MechFunctionCompiler {}
69
70#[cfg(not(feature = "compiler"))]
71pub trait MechFunction: MechFunctionImpl {}
72#[cfg(not(feature = "compiler"))]
73impl<T> MechFunction for T where T: MechFunctionImpl {}
74
75pub trait NativeFunctionCompiler {
76 fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>>;
77}
78
79pub struct Functions {
80 pub functions: FunctionTable,
81 pub function_compilers: FunctionCompilerTable,
82 pub dictionary: Ref<Dictionary>,
83}
84
85impl Functions {
86 pub fn new() -> Self {
87 Self {
88 functions: HashMap::new(),
89 function_compilers: HashMap::new(),
90 dictionary: Ref::new(Dictionary::new()),
91 }
92 }
93
94 pub fn insert_function(&mut self, fxn: FunctionDescriptor) {
95 let id = hash_str(&fxn.name);
96 self.functions.insert(id.clone(), fxn.ptr);
97 self.dictionary.borrow_mut().insert(id, fxn.name.to_string());
98 }
99
100
101}
102
103#[derive(Clone)]
104pub struct FunctionDefinition {
105 pub code: FunctionDefine,
106 pub id: u64,
107 pub name: String,
108 pub input: IndexMap<u64, KindAnnotation>,
109 pub output: IndexMap<u64, KindAnnotation>,
110 pub symbols: SymbolTableRef,
111 pub out: Ref<Value>,
112 pub plan: Plan,
113}
114
115impl fmt::Debug for FunctionDefinition {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 if cfg!(feature = "pretty_print") {
118 #[cfg(feature = "pretty_print")]
119 return fmt::Display::fmt(&self.pretty_print(), f);
120 fmt::Display::fmt(&"".to_string(), f)
121 } else {
122 write!(f, "FunctionDefinition {{ id: {}, name: {}, input: {:?}, output: {:?}, symbols: {:?} }}",
123 self.id, self.name, self.input, self.output, self.symbols.borrow())
124 }
125 }
126}
127
128#[cfg(feature = "pretty_print")]
129impl PrettyPrint for FunctionDefinition {
130 fn pretty_print(&self) -> String {
131 let input_str = format!("{:#?}", self.input);
132 let output_str = format!("{:#?}", self.output);
133 let symbols_str = format!("{:#?}", self.symbols);
134 let mut plan_str = "".to_string();
135 for step in self.plan.borrow().iter() {
136 plan_str = format!("{} - {}\n",plan_str,step.to_string());
137 }
138 let data = vec!["📥 Input", &input_str,
139 "📤 Output", &output_str,
140 "🔣 Symbols", &symbols_str,
141 "📋 Plan", &plan_str];
142 let mut table = tabled::Table::new(data);
143 table.with(Style::modern_rounded())
144 .with(Panel::header(format!("📈 UserFxn::{}\n({})", self.name, humanize(&self.id))))
145 .with(Alignment::left());
146 format!("{table}")
147 }
148}
149
150impl FunctionDefinition {
151
152 pub fn new(id: u64, name: String, code: FunctionDefine) -> Self {
153 Self {
154 id,
155 name,
156 code,
157 input: IndexMap::new(),
158 output: IndexMap::new(),
159 out: Ref::new(Value::Empty),
160 symbols: Ref::new(SymbolTable::new()),
161 plan: Plan::new(),
162 }
163 }
164
165 pub fn solve(&self) -> ValRef {
166 let plan_brrw = self.plan.borrow();
167 for step in plan_brrw.iter() {
168 let result = step.solve();
169 }
170 self.out.clone()
171 }
172
173 pub fn out(&self) -> ValRef {
174 self.out.clone()
175 }
176}
177
178pub struct UserFunction {
181 pub fxn: FunctionDefinition,
182}
183
184impl MechFunctionImpl for UserFunction {
185 fn solve(&self) {
186 self.fxn.solve();
187 }
188 fn out(&self) -> Value {
189 Value::MutableReference(self.fxn.out.clone())
190 }
191 fn to_string(&self) -> String { format!("UserFxn::{:?}", self.fxn.name) }
192}
193#[cfg(feature = "compiler")]
194impl MechFunctionCompiler for UserFunction {
195 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
196 todo!();
197 }
198}
199
200pub struct Plan(pub Ref<Vec<Box<dyn MechFunction>>>);
204
205impl Clone for Plan {
206 fn clone(&self) -> Self { Plan(self.0.clone()) }
207}
208
209impl fmt::Debug for Plan {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 for p in &(*self.0.borrow()) {
212 writeln!(f, "{}", p.to_string())?;
213 }
214 Ok(())
215 }
216}
217
218impl Plan {
219 pub fn new() -> Self { Plan(Ref::new(vec![])) }
220 pub fn borrow(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
221 pub fn borrow_mut(&self) -> std::cell::RefMut<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow_mut() }
222 pub fn add_function(&self, func: Box<dyn MechFunction>) { self.0.borrow_mut().push(func); }
223 pub fn get_functions(&self) -> std::cell::Ref<'_, Vec<Box<dyn MechFunction>>> { self.0.borrow() }
224 pub fn len(&self) -> usize { self.0.borrow().len() }
225 pub fn is_empty(&self) -> bool { self.0.borrow().is_empty() }
226}
227
228#[cfg(feature = "pretty_print")]
229impl PrettyPrint for Plan {
230 fn pretty_print(&self) -> String {
231 let mut builder = Builder::default();
232
233 let mut row = vec![];
234 let plan_brrw = self.0.borrow();
235 if self.is_empty() {
236 builder.push_record(vec!["".to_string()]);
237 } else {
238 for (ix, fxn) in plan_brrw.iter().enumerate() {
239 let plan_str = format!("{}. {}\n", ix + 1, fxn.to_string());
240 row.push(plan_str.clone());
241 if row.len() == 4 {
242 builder.push_record(row.clone());
243 row.clear();
244 }
245 }
246 }
247 if row.is_empty() == false {
248 builder.push_record(row.clone());
249 }
250 let mut table = builder.build();
251 table.with(Style::modern_rounded())
252 .with(Panel::header("📋 Plan"));
253 format!("{table}")
254 }
255}
256
257pub struct FunctionRegistry {
267 pub registry: RefCell<HashMap<u64, Box<dyn MechFunctionImpl>>>,
268}