1use crate::builtin::Builtin;
4
5use super::{
6 Callable, Interpret,
7 builtin::{Builtins, Math},
8 convalue::ConValue,
9 error::{Error, IResult},
10 function::Function,
11};
12use cl_ast::{Function as FnDecl, Sym};
13use std::{
14 collections::HashMap,
15 fmt::Display,
16 ops::{Deref, DerefMut},
17 rc::Rc,
18};
19
20type StackFrame = HashMap<Sym, Option<ConValue>>;
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
23pub enum Place {
24 Global(Sym),
25 Local(usize),
26}
27
28impl Display for Place {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 Place::Global(name) => name.fmt(f),
32 Place::Local(id) => id.fmt(f),
33 }
34 }
35}
36
37#[derive(Clone, Debug, Default)]
38struct EnvFrame {
39 pub name: Option<&'static str>,
41 pub base: usize,
42 pub binds: HashMap<Sym, usize>,
43}
44
45#[derive(Clone, Debug)]
47pub struct Environment {
48 global: HashMap<Sym, Option<ConValue>>,
49 values: Vec<Option<ConValue>>,
50 frames: Vec<EnvFrame>,
51}
52
53impl Display for Environment {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 for EnvFrame { name, base: _, binds } in self.frames.iter().rev() {
56 writeln!(
57 f,
58 "--- {} ---",
59 if let Some(name) = name { name } else { "" }
60 )?;
61 for (var, val) in binds {
62 write!(f, "{var}: ")?;
63 match self.values.get(*val) {
64 Some(Some(value)) => writeln!(f, "\t{value}"),
65 Some(None) => writeln!(f, "<undefined>"),
66 None => writeln!(f, "ERROR: {var} address blows the stack!"),
67 }?
68 }
69 }
70 Ok(())
71 }
72}
73impl Default for Environment {
74 fn default() -> Self {
75 let mut this = Self::no_builtins();
76 this.add_builtins(Builtins).add_builtins(Math);
77 this
78 }
79}
80
81impl Environment {
82 pub fn new() -> Self {
83 Self::default()
84 }
85 pub fn no_builtins() -> Self {
87 Self { values: Vec::new(), global: HashMap::new(), frames: vec![] }
88 }
89
90 pub fn eval(&mut self, node: &impl Interpret) -> IResult<ConValue> {
92 node.interpret(self)
93 }
94
95 pub fn call(&mut self, name: Sym, args: &[ConValue]) -> IResult<ConValue> {
98 let function = self.get(name)?;
99 function.call(self, args)
100 }
101
102 pub fn bind(&mut self, name: &str, value: impl Into<ConValue>) {
104 self.insert(name.into(), Some(value.into()));
105 }
106
107 pub fn globals(&self) -> &HashMap<Sym, Option<ConValue>> {
109 &self.global
110 }
111
112 pub fn add_builtins(&mut self, builtins: &'static [Builtin]) -> &mut Self {
118 let Self { global, .. } = self;
119 for builtin in builtins {
120 global.insert(builtin.name(), Some(builtin.into()));
121 }
122 self
123 }
124
125 pub fn push_frame(&mut self, name: &'static str, frame: StackFrame) {
126 self.enter(name);
127 for (k, v) in frame {
128 self.insert(k, v);
129 }
130 }
131
132 pub fn pop_frame(&mut self) -> Option<(StackFrame, &'static str)> {
133 let mut out = HashMap::new();
134 let EnvFrame { name, base, binds } = self.frames.pop()?;
135 for (k, v) in binds {
136 out.insert(k, self.values.get_mut(v).and_then(std::mem::take));
137 }
138 self.values.truncate(base);
139 Some((out, name.unwrap_or("")))
140 }
141
142 pub fn frame(&mut self, name: &'static str) -> Frame {
146 Frame::new(self, name)
147 }
148
149 pub fn get_mut(&mut self, name: Sym) -> IResult<&mut Option<ConValue>> {
153 let at = self.id_of(name)?;
154 self.get_id_mut(at).ok_or(Error::NotDefined(name))
155 }
156
157 pub fn get(&self, name: Sym) -> IResult<ConValue> {
161 let id = self.id_of(name)?;
162 let res = match id {
163 Place::Global(name) => self.global.get(&name),
164 Place::Local(id) => self.values.get(id),
165 };
166 match res.ok_or(Error::NotDefined(name))? {
167 Some(value) => Ok(value.clone()),
168 None => Err(Error::NotInitialized(name)),
169 }
170 }
171
172 pub fn id_of(&self, name: Sym) -> IResult<Place> {
174 for EnvFrame { binds, .. } in self.frames.iter().rev() {
175 if let Some(id) = binds.get(&name).copied() {
176 return Ok(Place::Local(id));
177 }
178 }
179 Ok(Place::Global(name))
180 }
181
182 pub fn get_id(&self, at: Place) -> Option<&ConValue> {
183 let res = match at {
184 Place::Global(name) => self.global.get(&name),
185 Place::Local(id) => self.values.get(id),
186 }?;
187 res.as_ref()
188 }
189
190 pub fn get_id_mut(&mut self, at: Place) -> Option<&mut Option<ConValue>> {
191 match at {
192 Place::Global(name) => self.global.get_mut(&name),
193 Place::Local(id) => self.values.get_mut(id),
194 }
195 }
196
197 pub fn insert(&mut self, k: Sym, v: Option<ConValue>) {
199 if self.bind_raw(k, self.values.len()).is_some() {
200 self.values.push(v);
201 } else {
202 self.global.insert(k, v);
203 }
204 }
205
206 pub fn insert_fn(&mut self, decl: &FnDecl) {
208 let FnDecl { name, .. } = decl;
209 let (name, function) = (*name, Rc::new(Function::new(decl)));
210 self.insert(name, Some(ConValue::Function(function.clone())));
211 function.lift_upvars(self);
213 }
214
215 pub fn stack_alloc(&mut self, value: ConValue) -> IResult<usize> {
217 let adr = self.values.len();
218 self.values.push(Some(value));
219 Ok(adr)
220 }
221
222 pub fn bind_raw(&mut self, name: Sym, id: usize) -> Option<()> {
223 let EnvFrame { name: _, base: _, binds } = self.frames.last_mut()?;
224 binds.insert(name, id);
225 Some(())
226 }
227}
228
229impl Environment {
231 fn enter(&mut self, name: &'static str) -> &mut Self {
233 let new_frame =
234 EnvFrame { name: Some(name), base: self.values.len(), binds: HashMap::new() };
235 self.frames.push(new_frame);
236 self
237 }
238
239 fn exit(&mut self) -> &mut Self {
242 if let Some(frame) = self.frames.pop() {
243 self.values.truncate(frame.base);
244 }
245 self
246 }
247}
248
249#[derive(Debug)]
251pub struct Frame<'scope> {
252 scope: &'scope mut Environment,
253}
254impl<'scope> Frame<'scope> {
255 fn new(scope: &'scope mut Environment, name: &'static str) -> Self {
256 Self { scope: scope.enter(name) }
257 }
258}
259impl Deref for Frame<'_> {
260 type Target = Environment;
261 fn deref(&self) -> &Self::Target {
262 self.scope
263 }
264}
265impl DerefMut for Frame<'_> {
266 fn deref_mut(&mut self) -> &mut Self::Target {
267 self.scope
268 }
269}
270impl Drop for Frame<'_> {
271 fn drop(&mut self) {
272 self.scope.exit();
273 }
274}