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, 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
139pub 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
161pub 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}