1use std::collections::HashMap;
4
5use astro_float::BigFloat;
6use lazy_static::lazy_static;
7use serde::{Deserialize, Serialize};
8
9use crate::ast::{BuiltinFunc, CalcFuncRef, UserFunc};
10use crate::builtins;
11use crate::{CalcError, CalcResult, Number, PREC, RM};
12
13lazy_static! {
14 pub static ref BUILTINS: HashMap<String, BuiltinFunc> = {
16 let mut m = HashMap::new();
17
18 m.insert(
20 "sqrt".to_string(),
21 BuiltinFunc::new(1, builtins::sqrt)
22 );
23
24 m.insert(
26 "ln".to_string(),
27 BuiltinFunc::new(1, builtins::ln)
28 );
29
30 m.insert(
32 "log".to_string(),
33 BuiltinFunc::new(1, builtins::log)
34 );
35
36 m.insert(
38 "sin".to_string(),
39 BuiltinFunc::new(1, builtins::sin)
40 );
41
42 m.insert(
43 "cos".to_string(),
44 BuiltinFunc::new(1, builtins::cos)
45 );
46
47 m.insert(
48 "tan".to_string(),
49 BuiltinFunc::new(1, builtins::tan)
50 );
51
52 m
53 };
54
55 pub static ref BUILTIN_VALUES: HashMap<String, BigFloat> = {
57 let mut m = HashMap::new();
58 let mut consts = astro_float::Consts::new().unwrap();
59 m.insert("pi".to_string(), consts.pi(PREC, RM));
60 m.insert("e".to_string(), consts.e(PREC, RM));
61 m
62 };
63}
64
65#[derive(Clone, Serialize, Deserialize)]
69pub struct Context {
70 functions: Vec<HashMap<String, UserFunc>>,
71 values: Vec<HashMap<String, Number>>,
72}
73
74impl Context {
75 pub fn new() -> Context {
77 Context {
78 functions: vec![HashMap::new()],
79 values: vec![HashMap::new()],
80 }
81 }
82
83 pub fn add_scope(&mut self, values: HashMap<String, Number>) {
85 self.values.push(values);
86 }
87
88 pub fn lookup_value(&self, name: &str) -> CalcResult {
92 if let Some(value) = self
93 .values
94 .iter()
95 .rev()
96 .find(|s| s.contains_key(name))
97 .and_then(|s| s.get(name).cloned())
98 {
99 Ok(value)
100 } else if let Some(value) = BUILTIN_VALUES.get(name) {
101 Ok(value.clone())
102 } else {
103 Err(CalcError::NameNotFound(name.to_owned()))
104 }
105 }
106
107 pub fn lookup_fn(&self, name: &str) -> Result<CalcFuncRef, CalcError> {
111 if let Some(func) = self
112 .functions
113 .iter()
114 .rev()
115 .find(|s| s.contains_key(name))
116 .and_then(|s| s.get(name))
117 {
118 Ok(CalcFuncRef::UserDef(func))
119 } else if let Some(func) = BUILTINS.get(name) {
120 Ok(CalcFuncRef::Builtin(func))
121 } else {
122 Err(CalcError::NameNotFound(name.to_owned()))
123 }
124 }
125
126 pub fn bind_value(&mut self, name: String, value: Number) -> CalcResult {
129 if BUILTIN_VALUES.contains_key(&name) {
131 Err(CalcError::NameAlreadyBound(name))
132 } else {
133 self.values.last_mut().unwrap().insert(name, value.clone());
134 Ok(value)
135 }
136 }
137
138 pub fn bind_fn(&mut self, name: String, func: UserFunc) -> Result<(), CalcError> {
141 if BUILTINS.contains_key(&name) {
143 Err(CalcError::NameAlreadyBound(name))
144 } else {
145 self.functions.last_mut().unwrap().insert(name, func);
146 Ok(())
147 }
148 }
149}