diff options
author | Akshay <[email protected]> | 2021-05-18 06:39:46 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-05-18 06:39:46 +0100 |
commit | f3a941bb63275b0efbaa88c65e7ba762d8b05237 (patch) | |
tree | 1f577c2be937e2052e6d8f292ef4df92c052c928 | |
parent | bea80dbfe722c7bb13e19665ddbadea03b8b6293 (diff) |
fix `set!` routine
and discover a drawback of borrowck!
-rw-r--r-- | src/lisp/eval.rs | 37 | ||||
-rw-r--r-- | src/lisp/test.lisp | 14 |
2 files changed, 33 insertions, 18 deletions
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs index 784cba0..c5e4ed0 100644 --- a/src/lisp/eval.rs +++ b/src/lisp/eval.rs | |||
@@ -153,14 +153,9 @@ where | |||
153 | match args { | 153 | match args { |
154 | [LispExpr::Ident(id), expr] => { | 154 | [LispExpr::Ident(id), expr] => { |
155 | let value = self.eval(&expr)?; | 155 | let value = self.eval(&expr)?; |
156 | let local_env = self.app.lisp_env.last_mut(); | 156 | let loc = lookup_mut(&mut self.app.lisp_env, id)?; |
157 | if let Some(env) = local_env { | 157 | *loc = value; |
158 | env.insert(id.into(), value) | 158 | Ok(LispExpr::Unit) |
159 | .ok_or_else(|| EvalError::UnboundVariable(id.into()).into()) | ||
160 | } else { | ||
161 | error!("Unable to set in global env!"); | ||
162 | Err(EvalError::BadForm.into()) | ||
163 | } | ||
164 | } | 159 | } |
165 | _ => { | 160 | _ => { |
166 | error!("Invalid usage of `set!`"); | 161 | error!("Invalid usage of `set!`"); |
@@ -334,16 +329,22 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> { | |||
334 | } | 329 | } |
335 | 330 | ||
336 | pub fn lookup(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { | 331 | pub fn lookup(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> { |
337 | if env_list.is_empty() { | 332 | Ok(env_list |
338 | Err(EvalError::UnboundVariable(key.into()).into()) | 333 | .iter() |
339 | } else { | 334 | .rev() |
340 | let local_env = env_list.last().unwrap(); | 335 | .find_map(|local_env| local_env.get(key).cloned()) |
341 | if let Some(val) = local_env.get(key) { | 336 | .ok_or(EvalError::UnboundVariable(key.into()))?) |
342 | Ok(val.clone()) | 337 | } |
343 | } else { | 338 | |
344 | lookup(&env_list[..env_list.len() - 1], key) | 339 | pub fn lookup_mut<'a, 'b>( |
345 | } | 340 | env_list: &'a mut [Environment], |
346 | } | 341 | key: &'b str, |
342 | ) -> Result<&'a mut LispExpr, LispError> { | ||
343 | Ok(env_list | ||
344 | .iter_mut() | ||
345 | .rev() | ||
346 | .find_map(|local_env| local_env.get_mut(key)) | ||
347 | .ok_or(EvalError::UnboundVariable(key.into()))?) | ||
347 | } | 348 | } |
348 | 349 | ||
349 | pub fn completions<'a>(env_list: &'a [Environment], prefix: &str) -> Vec<&'a str> { | 350 | pub fn completions<'a>(env_list: &'a [Environment], prefix: &str) -> Vec<&'a str> { |
diff --git a/src/lisp/test.lisp b/src/lisp/test.lisp index a167f28..5eb1aaa 100644 --- a/src/lisp/test.lisp +++ b/src/lisp/test.lisp | |||
@@ -17,3 +17,17 @@ | |||
17 | (assert-eq | 17 | (assert-eq |
18 | ((lambda (x) x) 2) | 18 | ((lambda (x) x) 2) |
19 | 2) | 19 | 2) |
20 | |||
21 | (define x 2) | ||
22 | (define y 5) | ||
23 | (set! x 3) | ||
24 | (assert-eq x 3) | ||
25 | |||
26 | (define (square-x x) | ||
27 | (let [(y x)] | ||
28 | (begin | ||
29 | (set! y (* x x)) | ||
30 | y))) | ||
31 | |||
32 | (assert-eq (square-x 2) 4) | ||
33 | (assert-eq y 5) | ||