mech_core/
functions.rs

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
17// Functions ------------------------------------------------------------------
18
19pub 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// User Function --------------------------------------------------------------
111
112#[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
127// Symbol Table ---------------------------------------------------------------
128
129pub 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_symbol_name_by_id(&self, id: u64) -> Option<String> {
151    self.dictionary.borrow().get(&id).cloned()
152  }
153
154  pub fn get_mutable(&self, key: u64) -> Option<ValRef> {
155    self.mutable_variables.get(&key).cloned()
156  }
157
158  pub fn get(&self, key: u64) -> Option<ValRef> {
159    self.symbols.get(&key).cloned()
160  }
161
162  pub fn contains(&self, key: u64) -> bool {
163    self.symbols.contains_key(&key)
164  }
165
166  pub fn insert(&mut self, key: u64, value: Value, mutable: bool) -> ValRef {
167    let cell = new_ref(value);
168    self.reverse_lookup.insert(Rc::as_ptr(&cell), key);
169    let old = self.symbols.insert(key,cell.clone());
170    if mutable {
171      self.mutable_variables.insert(key,cell.clone());
172    }
173    cell.clone()
174  }
175
176  pub fn pretty_print(&self) -> String {
177    let mut builder = Builder::default();
178    let dict_brrw = self.dictionary.borrow();
179    for (k,v) in &self.symbols {
180      let name = dict_brrw.get(k).unwrap_or(&"??".to_string()).clone();
181      let v_brrw = v.borrow();
182      builder.push_record(vec![format!("\n{} : {}\n{}\n",name, v_brrw.kind(), v_brrw.pretty_print())])
183    }
184    if self.symbols.is_empty() {
185      builder.push_record(vec!["".to_string()]);
186    }
187    let mut table = builder.build();
188    let table_style = Style::empty()
189    .top(' ')
190    .left(' ')
191    .right(' ')
192    .bottom(' ')
193    .vertical(' ')
194    .horizontal('ยท')
195    .intersection_bottom(' ')
196    .corner_top_left(' ')
197    .corner_top_right(' ')
198    .corner_bottom_left(' ')
199    .corner_bottom_right(' ');
200    table.with(table_style);
201    format!("{table}")
202  }
203}