46 lines
1.9 KiB
Clojure
46 lines
1.9 KiB
Clojure
(ns emptyhead.newlib.delegate
|
|
"Delegation: treat one message as though it were another, enabling behaviour sharing and polymorphism."
|
|
(:require [emptyhead.thought.crud :as thought]
|
|
[emptyhead.idea.crud :as idea]
|
|
[emptyhead.thought.define :as def]
|
|
[emptyhead.thought.eval :as eval]
|
|
[emptyhead.thought.extend :as extend]
|
|
[emptyhead.newlib.core]))
|
|
|
|
(defn remove-delegate
|
|
"Undelegate `del` from `msg`."
|
|
[msg del]
|
|
(let [remover (thought/register-thought! [:EH :CORE :NOP] :ext-stages [[:EH :MSG :REMOVE-DELEGATE msg del]])]
|
|
(eval/execute! remover)))
|
|
|
|
|
|
;; Forget idea stored in `thought`'s data. Used to make destructors.
|
|
(def/define! [:EH :IDEA :FORGET]
|
|
(fn [thought parent]
|
|
(idea/forget-idea! (thought/data thought))
|
|
[parent nil]))
|
|
|
|
;; FIXME Delegate order is currently undefined! Give this a proper order.
|
|
;; FIXME needs to be called with a list as second arg??
|
|
(defn add-delegate
|
|
"Register `del` as a delegate for `msg`: implementations defined for `del` will now run trigger on `msg` as well.
|
|
For instance, if message =(:foo :bar)= is defined and we =(add-delegate :quux :bar)= then =(:foo :quux)= will alias to =(:foo :bar)=.
|
|
Note that this also works on the left hand side."
|
|
[msg del]
|
|
(remove-delegate msg del)
|
|
(let [delegator (thought/register-thought!
|
|
[:EH :IO :RETURN]
|
|
:data del
|
|
:transient false)
|
|
remover (thought/register-thought! [:EH :IDEA :FORGET] :data delegator)]
|
|
(extend/register-extension! delegator [:EH :MSG :DELEGATE msg])
|
|
(extend/register-extension! remover [:EH :MSG :REMOVE-DELEGATE msg del])))
|
|
|
|
(defn get-delegates
|
|
"Get possible delegates for `msg`."
|
|
[msg]
|
|
(let [stage [:EH :MSG :DELEGATE msg]
|
|
dels (-> (thought/register-thought! [:EH :CORE :CONTAINER] :ext-stages [stage])
|
|
eval/execute! thought/empty-stack second)]
|
|
(mapcat #(cons % (get-delegates %)) dels)))
|