(use fugue)
(import /src/calc)
(def define (:new calc/Adverb
:arity 2
:type :define
:fun-ref (fn define [stack]
(let [sym (calc/pop stack)
q (calc/pop stack)]
(match sym
{:value sym-value :quoted? true} (put-in stack [:env sym-value] q))))))
(defn lookup
```
Look up a symbol in a stack 's environment. The symbol might refer
to an atomic element or to an unevaluated quotation.
```
[stack sym-value]
(match (get-in stack [:env sym-value])
# Mark the stored quotation for evaluation by creating a Thunk out
# of it, which is a Quotation that evaluates its contents when
# pushed to the stack.
(q (calc/Quotation? q)) (:new calc/Thunk (q :data))
nil (errorf "Eval error: unknown word %s" sym-value)
elem elem))
(defn eval
```
Evaluate an unquoted symbol by looking it up in the stack
environment; all other types evaluate to themselves.
```
[stack sym]
(match sym
{:value sym-value :quoted? false} (lookup stack sym-value)
_ sym))
(defn apply-quotation
```
Quotation evaluation. Given any potentially unevaluated quotation,
evaluate and push each element.
```
[stack maybe-quote]
(match maybe-quote
(q (calc/Quotation*? q)) (each elem (calc/data q)
(->> elem
(eval stack)
(calc/push stack)))
not-a-quote (calc/push stack not-a-quote)))
(extend-multi calc/push
[calc/Stack calc/Thunk]
[stack thunk]
(let [evaled (map |(eval stack $) (thunk :data))
q (:new calc/Quotation evaled)]
(apply-quotation stack q)))
(defn eval-and-push
[stack symbol]
(->> symbol
(eval stack)
(calc/push stack)))