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