[2026-06-26] - annotations do not work properly because macroexpansion creates an entirely new body for lambdas - we realized that we are handling macro application in two separate places: pit_expand_macros expands lambda bodies, and pit_eval expands macros encountered while evaling. we ought to unify this so that only one is used (probably pit_expand_macros, because we need to expand macros eagerly to identify free variables to capture) - we probably can make pit_expand_macros and pit_eval much nicer - we can probably make pit_expand_macros operate in place - if we want to be really smart, cool, happy, rich: let's just make stuff translate to a little VM before it evaluates, and let's store VM programs as functions instead of sexps * little vm thing let's have a "program" (representation of one function) be a cons-list of instructions during execution, we maintain a stack of programs. calling a lisp function entails pushing a new "frame" to this stack we iterate over the frame by cdring as usual and we pop the frame when we reach the end #+begin_src pit (defun! add2 (x y) (+ x y 2)) #+end_src #+begin_src pit [ (literal x) (get) (literal y) (get) (literal 2) (literal +) (fget) (apply 3) ] #+end_src #+begin_src pit (defun! foo (x) (* (add2 x x) 4)) #+end_src #+begin_src pit [ (literal x) (get) (literal x) (get) (literal add2) (fget) (apply 2) ;; evaluating this pushes a new frame with the code for add2. next "tick" of evaluator continues in that code. once it returns, result is on the stack (for free) (literal 4) (literal *) (fget) (apply 2) ] #+end_src