2021-01-27 21:00:31 +03:00
|
|
|
|
; Implementors’ note: this code could be made more elegant by using quasiquotes
|
|
|
|
|
; but quasiquoting is actually loaded after this module, so we can’t rely on
|
|
|
|
|
; that functionality.
|
|
|
|
|
|
|
|
|
|
|
2021-01-15 12:48:34 +03:00
|
|
|
|
(doc Derive "is a mechanism for deriving interfaces automatically.
|
|
|
|
|
|
|
|
|
|
Please reference [the documentation](https://github.com/carp-lang/Carp/blob/master/docs/Derive.md)
|
|
|
|
|
for more information.")
|
|
|
|
|
(defmodule Derive
|
|
|
|
|
(hidden derivers)
|
|
|
|
|
(defdynamic derivers '())
|
|
|
|
|
|
|
|
|
|
(doc make-deriver "is a mechanism for providing your own deriver by providing
|
|
|
|
|
the interface name `f`, the arguments it takes `args`, and a function that can
|
|
|
|
|
generate a body when given a type `body`.
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
```
|
|
|
|
|
(make-deriver 'zero []
|
|
|
|
|
(fn [t]
|
|
|
|
|
(cons 'init
|
2021-01-27 21:00:31 +03:00
|
|
|
|
(map (fn [_] '(zero)) (eval `(members %t)))))
|
2021-01-15 12:48:34 +03:00
|
|
|
|
```")
|
|
|
|
|
(defndynamic make-deriver [f args body]
|
|
|
|
|
(set! Derive.derivers
|
|
|
|
|
(cons
|
|
|
|
|
(list f
|
|
|
|
|
(fn [t name]
|
|
|
|
|
(list 'defmodule t
|
|
|
|
|
(list 'defn name args
|
|
|
|
|
(body t))
|
|
|
|
|
(list 'implements f (Symbol.prefix t name)))))
|
|
|
|
|
Derive.derivers)))
|
|
|
|
|
|
|
|
|
|
(doc make-update-deriver "is a convenience function for creating a deriver
|
|
|
|
|
for functions that you could pass into `update-<member>` style functions.")
|
|
|
|
|
(defndynamic make-update-deriver [interface]
|
|
|
|
|
(make-deriver interface ['o]
|
|
|
|
|
(fn [t]
|
|
|
|
|
(reduce
|
|
|
|
|
(fn [acc m]
|
|
|
|
|
(list (Symbol.concat ['update- (car m)]) acc (list 'ref interface)))
|
|
|
|
|
'o
|
|
|
|
|
(eval (list 'members t))))))
|
|
|
|
|
|
|
|
|
|
(hidden get-deriver)
|
|
|
|
|
(defndynamic get-deriver [f derivers]
|
|
|
|
|
(if (empty? derivers)
|
|
|
|
|
'()
|
|
|
|
|
(if (= (caar derivers) f)
|
|
|
|
|
(car derivers)
|
|
|
|
|
(get-deriver f (cdr derivers)))))
|
|
|
|
|
|
|
|
|
|
(doc derivable? "checks whether a quoted interface name `f` is currently
|
|
|
|
|
derivable.")
|
|
|
|
|
(defndynamic derivable? [f]
|
|
|
|
|
(let [deriver (get-deriver f Derive.derivers)]
|
|
|
|
|
(not (empty? deriver))))
|
|
|
|
|
|
|
|
|
|
(doc derivables "returns the list of currently derivable interfaces.")
|
|
|
|
|
(defndynamic derivables []
|
|
|
|
|
(map car Derive.derivers))
|
|
|
|
|
|
|
|
|
|
(doc derive "derives an interface function `f` for a type `t`.
|
|
|
|
|
|
|
|
|
|
Optionally, it also takes an argument `overrride` that overrides the name of
|
|
|
|
|
the generated function to avoid collisions.")
|
|
|
|
|
(defmacro derive [t f :rest override]
|
|
|
|
|
(let [name (if (empty? override) f (car override))
|
|
|
|
|
deriver (get-deriver f Derive.derivers)]
|
|
|
|
|
(if (empty? deriver)
|
|
|
|
|
(macro-error (String.concat ["no deriver found for interface " (str f) "!"]))
|
|
|
|
|
(eval ((cadr deriver) t name))))))
|
|
|
|
|
|
|
|
|
|
(use Derive)
|
|
|
|
|
|
|
|
|
|
(make-deriver '= ['o1 'o2]
|
|
|
|
|
(fn [t]
|
|
|
|
|
(reduce
|
|
|
|
|
(fn [acc m]
|
|
|
|
|
(list 'and (list '= (list (car m) 'o1) (list (car m) 'o2)) acc))
|
|
|
|
|
true
|
|
|
|
|
(eval (list 'members t)))))
|
|
|
|
|
|
|
|
|
|
(make-deriver 'zero []
|
|
|
|
|
(fn [t]
|
|
|
|
|
(cons 'init
|
|
|
|
|
(map (fn [_] '(zero)) (eval (list 'members t))))))
|
|
|
|
|
|
|
|
|
|
(make-deriver 'str ['o]
|
|
|
|
|
(fn [t]
|
|
|
|
|
(let [mems (eval (list 'members t))]
|
|
|
|
|
(cons 'fmt
|
|
|
|
|
(cons
|
|
|
|
|
(String.concat
|
|
|
|
|
(append
|
|
|
|
|
(append ["(" (str t)]
|
|
|
|
|
(collect-into (map (fn [_] " %s") mems) array))
|
|
|
|
|
[")"]))
|
|
|
|
|
(map (fn [m] (list 'ref (list 'str (list (car m) 'o)))) mems))))))
|