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