brundonsmith / rust_lisp

A Rust-embeddable Lisp, with support for interop with native Rust functions
239 stars 19 forks source link

:bug: Fix closures being ignored #12

Closed adri326 closed 2 years ago

adri326 commented 2 years ago

Prior to this pull request, closures in lambdas were ignored. This can be seen when running grep -Rn "closure" src/:

src/interpreter.rs:146:                        closure: env.clone(),
src/interpreter.rs:162:                        closure: env,
src/model.rs:471:    pub closure: Rc<RefCell<Env>>,
src/model.rs:478:        self.closure.as_ptr() == other.closure.as_ptr()
src/model.rs:513:/// closures, for `let` statements, for function arguments, etc.

The closure field is never read, except when testing for equality. When a lambda is called, the environment of the caller's site is injected into the lambda's environment instead; this means that captured variables are discarded. The following piece of code is affected by this issue:

(map (let ((x 3)) (lambda (y) (+ x y))) (list 0 1 2 3 4))

Expected: (3 4 5 6 7) Actual: Runtime error: Function "+" requires an argument 2

This pull request fixes that by injecting the lambda's stored closure instead of the caller's environment, and introduces the above piece of code as a test.

adri326 commented 2 years ago

Poke @alexmozaidze as their fork is also affected

brundonsmith commented 2 years ago

Wow that was a pretty big oversight, thanks for the fix