1use crate::types::*;
2use crate::value::*;
3use crate::nodes::*;
4use crate::*;
5
6use hashbrown::{HashMap, HashSet};
7use indexmap::map::IndexMap;
8use std::rc::Rc;
9use std::cell::RefCell;
10use tabled::{
11  builder::Builder,
12  settings::{object::Rows,Panel, Span, Alignment, Modify, Style},
13  Tabled,
14};
15use std::fmt;
16
17pub trait MechFunction {
20  fn solve(&self);
21  fn out(&self) -> Value;
22  fn to_string(&self) -> String;
23}
24
25pub trait NativeFunctionCompiler {
26  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>>;
27}
28
29pub struct Functions {
30  pub functions: HashMap<u64,FunctionDefinition>,
31  pub function_compilers: HashMap<u64, Box<dyn NativeFunctionCompiler>>,
32  pub kinds: HashMap<u64,ValueKind>,
33  pub enums: HashMap<u64,MechEnum>,
34}
35  
36impl Functions {
37  pub fn new() -> Self {
38    Self {
39      functions: HashMap::new(), 
40      function_compilers: HashMap::new(), 
41      kinds: HashMap::new(),
42      enums: HashMap::new(),
43    }
44  }
45}
46
47#[derive(Clone)]
48pub struct FunctionDefinition {
49  pub code: FunctionDefine,
50  pub id: u64,
51  pub name: String,
52  pub input: IndexMap<u64, KindAnnotation>,
53  pub output: IndexMap<u64, KindAnnotation>,
54  pub symbols: SymbolTableRef,
55  pub out: Ref<Value>,
56  pub plan: Plan,
57}
58
59impl fmt::Debug for FunctionDefinition {
60  #[inline]
61  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62    let input_str = format!("{:#?}", self.input);
63    let output_str = format!("{:#?}", self.output);
64    let symbols_str = format!("{:#?}", self.symbols);
65    let mut plan_str = "".to_string();
66    for step in self.plan.borrow().iter() {
67      plan_str = format!("{}  - {}\n",plan_str,step.to_string());
68    }
69    let data = vec!["๐ฅ Input", &input_str, 
70                    "๐ค Output", &output_str, 
71                    "๐ฃ Symbols",   &symbols_str,
72                    "๐ Plan", &plan_str];
73    let mut table = tabled::Table::new(data);
74    table.with(Style::modern_rounded())
75         .with(Panel::header(format!("๐ UserFxn::{}\n({})", self.name, humanize(&self.id))))
76         .with(Alignment::left());
77    println!("{table}");
78    Ok(())
79  }
80}
81
82impl FunctionDefinition {
83
84  pub fn new(id: u64, name: String, code: FunctionDefine) -> Self {
85    Self {
86      id,
87      name,
88      code,
89      input: IndexMap::new(),
90      output: IndexMap::new(),
91      out: new_ref(Value::Empty),
92      symbols: new_ref(SymbolTable::new()),
93      plan: new_ref(Vec::new()),
94    }
95  }
96
97  pub fn solve(&self) -> ValRef {
98    let plan_brrw = self.plan.borrow();
99    for step in plan_brrw.iter() {
100      let result = step.solve();
101    }
102    self.out.clone()
103  }
104
105  pub fn out(&self) -> ValRef {
106    self.out.clone()
107  }
108}
109
110#[derive(Debug)]
113pub struct UserFunction {
114  pub fxn: FunctionDefinition,
115}
116
117impl MechFunction for UserFunction {
118  fn solve(&self) {
119    self.fxn.solve();
120  }
121  fn out(&self) -> Value {
122    Value::MutableReference(self.fxn.out.clone())
123  }
124  fn to_string(&self) -> String { format!("UserFxn::{:?}", self.fxn.name)}
125}
126
127pub type Dictionary = IndexMap<u64,String>;
130
131#[derive(Clone, Debug)]
132pub struct SymbolTable {
133  pub symbols: HashMap<u64,ValRef>,
134  pub mutable_variables: HashMap<u64,ValRef>,
135  pub dictionary: Ref<Dictionary>,
136  pub reverse_lookup: HashMap<*const RefCell<Value>, u64>,
137}
138
139impl SymbolTable {
140
141  pub fn new() -> SymbolTable {
142    Self {
143      symbols: HashMap::new(),
144      mutable_variables: HashMap::new(),
145      dictionary: new_ref(IndexMap::new()),
146      reverse_lookup: HashMap::new(),
147    }
148  }
149
150  pub fn get_mutable(&self, key: u64) -> Option<ValRef> {
151    self.mutable_variables.get(&key).cloned()
152  }
153
154  pub fn get(&self, key: u64) -> Option<ValRef> {
155    self.symbols.get(&key).cloned()
156  }
157
158  pub fn contains(&self, key: u64) -> bool {
159    self.symbols.contains_key(&key)
160  }
161
162  pub fn insert(&mut self, key: u64, value: Value, mutable: bool) -> ValRef {
163    let cell = new_ref(value);
164    self.reverse_lookup.insert(Rc::as_ptr(&cell), key);
165    let old = self.symbols.insert(key,cell.clone());
166    if mutable {
167      self.mutable_variables.insert(key,cell.clone());
168    }
169    cell.clone()
170  }
171
172  pub fn pretty_print(&self) -> String {
173    let mut builder = Builder::default();
174    let dict_brrw = self.dictionary.borrow();
175    for (k,v) in &self.symbols {
176      let name = dict_brrw.get(k).unwrap_or(&"??".to_string()).clone();
177      let v_brrw = v.borrow();
178      builder.push_record(vec![format!("\n{} : {:?}\n{}\n",name, v_brrw.kind(), v_brrw.pretty_print())])
179    }
180    if self.symbols.is_empty() {
181      builder.push_record(vec!["".to_string()]);
182    }
183    let mut table = builder.build();
184    let table_style = Style::empty()
185    .top(' ')
186    .left(' ')
187    .right(' ')
188    .bottom(' ')
189    .vertical(' ')
190    .horizontal('ยท')
191    .intersection_bottom(' ')
192    .corner_top_left(' ')
193    .corner_top_right(' ')
194    .corner_bottom_left(' ')
195    .corner_bottom_right(' ');
196    table.with(table_style);
197    format!("{table}")
198  }
199}