48 lines
1.9 KiB
Clojure
48 lines
1.9 KiB
Clojure
(ns emptyhead.thought.eval
|
|
"Implements evaluation of thoughts."
|
|
(:require [emptyhead.idea.protocol :as prtc]
|
|
[emptyhead.thought.extend :as extend]
|
|
[emptyhead.thought.crud :as thought]
|
|
[emptyhead.util.logging :as logging]
|
|
[emptyhead.thought.return :as return]
|
|
[emptyhead.idea.property :as prop]
|
|
[emptyhead.idea.crud :as idea]
|
|
[emptyhead.util.magic :as magic]))
|
|
|
|
(defn- impl! [thought & [parent]]
|
|
(let [impl-idea
|
|
(-> thought prtc/value thought/operator magic/thought-impl-prop prop/just-property)]
|
|
(if-not impl-idea
|
|
(logging/error (str "No implementation for thought `" (thought/operator thought) "`.")
|
|
{:thought thought :parent parent :type :unimplemented-thought})
|
|
((prtc/copy-fn :implementation impl-idea) thought parent))))
|
|
|
|
(def root-thought (thought/make-thought :root))
|
|
|
|
;; at what point do returns get cleared?
|
|
(defn execute!
|
|
"Execute `thought` with `parent`, applying aspects to `thought` according to its :extension-stages.
|
|
Returns (potentially modified) `parent`."
|
|
[thought & [parent]]
|
|
(loop [th (prtc/copy thought)
|
|
parent (or parent root-thought)]
|
|
(let [cur (first (thought/stages thought))
|
|
[extensions th] (extend/pop-stage th)
|
|
|
|
;; Execute extensions, potentially modifying th
|
|
th (reduce #(execute! %2 %1) th extensions)
|
|
;; If it's time for `thought`'s implementation to run, do so,
|
|
;; potentially modifying `parent`.
|
|
[parent return]
|
|
(if (= cur [:thought (thought/operator th)])
|
|
(impl! th parent)
|
|
parent)
|
|
|
|
;; Fold return value into `parent`.
|
|
parent (return/with-return parent (thought/operator th) return)]
|
|
|
|
;; Recur if there's remaining aspects, otherwise return `parent`.
|
|
(if (not-empty (thought/stages th))
|
|
(recur th parent)
|
|
parent))))
|