1use futures::future::BoxFuture;
2use std::collections::HashMap;
3
4use crate::{
5 builtin::Builtin,
6 compile::CompileError,
7 error::RuntimeError,
8 gc::{init_gc, Gc, Trace},
9 lex::{LexError, Token},
10 parse::ParseError,
11 syntax::{Identifier, Mark, ParsedSyntax},
12 value::Value,
13};
14
15#[derive(derive_more::Debug, Trace)]
16pub struct LexicalContour {
17 #[debug(skip)]
18 pub up: Env,
19 #[debug("{:?}", vars.keys().cloned().collect::<Vec<_>>())]
21 vars: HashMap<Identifier, Gc<Value>>,
22 #[debug("{:?}", macros.keys().cloned().collect::<Vec<_>>())]
23 macros: HashMap<Identifier, Gc<Value>>,
24}
25
26impl LexicalContour {
27 pub fn is_bound<'a>(&'a self, ident: &'a Identifier) -> BoxFuture<'a, bool> {
28 Box::pin(async move {
29 self.vars.contains_key(ident)
30 || self.macros.contains_key(ident)
31 || self.up.is_bound(ident).await
32 })
33 }
34
35 fn fetch_var<'a>(&'a self, ident: &'a Identifier) -> BoxFuture<'a, Option<Gc<Value>>> {
36 Box::pin(async move {
37 if let Some(var) = self.vars.get(ident) {
38 return Some(var.clone());
39 }
40 if let Some(var) = self.macros.get(ident) {
42 return Some(var.clone());
43 }
44 self.up.fetch_var(ident).await
46 })
47 }
48
49 fn fetch_macro<'a>(&'a self, ident: &'a Identifier) -> BoxFuture<'a, Option<MacroLookup>> {
50 Box::pin(async move {
51 if let Some(var) = self.macros.get(ident) {
53 return Some(MacroLookup::WithoutEnv(var.clone()));
54 }
55 self.up.fetch_macro(ident).await.map(MacroLookup::WithEnv)
56 })
57 }
58
59 pub fn def_var(&mut self, ident: &Identifier, value: Gc<Value>) {
60 if self.macros.contains_key(ident) {
62 self.macros.remove(ident);
63 }
64 self.vars.insert(ident.clone(), value);
65 }
66
67 pub fn def_macro(&mut self, ident: &Identifier, value: Gc<Value>) {
68 if self.vars.contains_key(ident) {
70 self.vars.remove(ident);
71 }
72 self.macros.insert(ident.clone(), value);
73 }
74}
75
76#[derive(derive_more::Debug, Trace)]
77pub struct ExpansionContext {
78 #[debug(skip)]
79 up: Env,
80 mark: Mark,
81 #[debug(skip)]
82 macro_env: Env,
83}
84
85impl ExpansionContext {
86 pub fn is_bound<'a>(&'a self, ident: &'a Identifier) -> BoxFuture<'a, bool> {
87 Box::pin(async move {
88 if ident.marks.contains(&self.mark) {
89 let mut stripped = ident.clone();
90 stripped.mark(self.mark);
91 self.macro_env.is_bound(&stripped).await
92 } else {
93 self.up.is_bound(ident).await
94 }
95 })
96 }
97
98 pub fn fetch_var<'a>(&'a self, ident: &'a Identifier) -> BoxFuture<'a, Option<Gc<Value>>> {
99 Box::pin(async move {
100 if ident.marks.contains(&self.mark) {
103 let mut stripped = ident.clone();
104 stripped.mark(self.mark);
105 self.macro_env.fetch_var(&stripped).await
106 } else {
107 self.up.fetch_var(ident).await
108 }
109 })
110 }
111
112 pub fn fetch_macro<'a>(
113 &'a self,
114 ident: &'a Identifier,
115 ) -> BoxFuture<'a, Option<(Env, Gc<Value>)>> {
116 Box::pin(async move {
117 if ident.marks.contains(&self.mark) {
118 let mut stripped = ident.clone();
119 stripped.mark(self.mark);
120 self.macro_env.fetch_macro(&stripped).await
121 } else {
122 self.up.fetch_macro(ident).await
123 }
124 })
125 }
126}
127
128#[derive(Clone, Trace, derive_more::Debug)]
129pub enum Env {
130 Top,
132 Expansion(#[debug(skip)] Gc<ExpansionContext>),
134 LexicalContour(#[debug(skip)] Gc<LexicalContour>),
136}
137
138impl Env {
139 pub async fn is_bound(&self, ident: &Identifier) -> bool {
140 match self {
141 Self::Top => false,
142 Self::Expansion(expansion) => expansion.read().await.is_bound(ident).await,
143 Self::LexicalContour(env) => env.read().await.is_bound(ident).await,
144 }
145 }
146
147 pub async fn fetch_var(&self, ident: &Identifier) -> Option<Gc<Value>> {
148 match self {
149 Self::Top => None,
150 Self::Expansion(expansion) => expansion.read().await.fetch_var(ident).await,
151 Self::LexicalContour(env) => env.read().await.fetch_var(ident).await,
152 }
153 }
154
155 pub async fn fetch_macro(&self, ident: &Identifier) -> Option<(Env, Gc<Value>)> {
156 match self {
157 Self::Top => None,
158 Self::Expansion(expansion) => expansion.read().await.fetch_macro(ident).await,
159 Self::LexicalContour(env) => match env.read().await.fetch_macro(ident).await {
160 Some(MacroLookup::WithEnv((env, value))) => Some((env, value)),
161 Some(MacroLookup::WithoutEnv(value)) => Some((self.clone(), value)),
162 _ => None,
163 },
164 }
165 }
166
167 pub async fn top() -> Self {
168 init_gc();
170
171 let mut top = Self::Top.new_lexical_contour();
172 for builtin in inventory::iter::<Builtin> {
174 builtin.install(&mut top);
175 }
176 let top = Self::LexicalContour(Gc::new(top));
177 let _ = top.eval(include_str!("stdlib.scm")).await.unwrap();
179 top
180 }
181
182 pub fn new_lexical_contour(&self) -> LexicalContour {
183 LexicalContour {
184 up: self.clone(),
185 vars: HashMap::default(),
187 macros: HashMap::default(),
188 }
189 }
190
191 pub fn new_expansion_context(&self, mark: Mark, macro_env: Env) -> ExpansionContext {
192 ExpansionContext {
193 up: self.clone(),
194 mark,
195 macro_env,
196 }
197 }
198
199 pub fn def_var<'a>(&'a self, ident: &'a Identifier, value: Gc<Value>) -> BoxFuture<'a, ()> {
200 Box::pin(async move {
201 match self {
202 Self::Top => unreachable!(),
203 Self::Expansion(expansion) => expansion.read().await.up.def_var(ident, value).await,
204 Self::LexicalContour(contour) => contour.write().await.def_var(ident, value),
205 }
206 })
207 }
208
209 pub fn def_macro<'a>(&'a self, ident: &'a Identifier, value: Gc<Value>) -> BoxFuture<'a, ()> {
210 Box::pin(async move {
211 match self {
212 Self::Top => unreachable!(),
213 Self::Expansion(expansion) => {
214 expansion.read().await.up.def_macro(ident, value).await
215 }
216 Self::LexicalContour(contour) => contour.write().await.def_macro(ident, value),
217 }
218 })
219 }
220
221 pub async fn eval<'e>(&self, exprs: &'e str) -> Result<Vec<Vec<Gc<Value>>>, EvalError<'e>> {
223 let tokens = Token::tokenize_str(exprs)?;
224 let sexprs = ParsedSyntax::parse(&tokens)?;
225 let mut results = Vec::new();
226 for sexpr in sexprs {
227 let result = sexpr.compile(self, &None).await?.eval(self, &None).await?;
228 results.push(result);
229 }
230 Ok(results)
231 }
232}
233
234impl From<Gc<ExpansionContext>> for Env {
235 fn from(env: Gc<ExpansionContext>) -> Self {
236 Self::Expansion(env)
237 }
238}
239
240impl From<Gc<LexicalContour>> for Env {
241 fn from(env: Gc<LexicalContour>) -> Self {
242 Self::LexicalContour(env)
243 }
244}
245
246enum MacroLookup {
247 WithEnv((Env, Gc<Value>)),
248 WithoutEnv(Gc<Value>),
249}
250
251#[derive(derive_more::From, Debug)]
252pub enum EvalError<'e> {
253 LexError(LexError<'e>),
254 ParseError(ParseError<'e>),
255 CompileError(CompileError),
256 RuntimeError(RuntimeError),
257}