Last active
August 15, 2017 00:47
-
-
Save fiddlerwoaroof/4e34a8c62d3a7426c3711960b8e30698 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defpackage :anonymous-generic-function | |
(:use :cl :alexandria) | |
(:export :lambda-generic)) | |
(in-package :anonymous-generic-function) | |
(defmacro defun-ct (name (&rest args) &body body) | |
`(eval-when (:load-toplevel :compile-toplevel :execute) | |
(defun ,name ,args | |
,@body))) | |
(defun-ct make-anonymous-generic-function (lambda-list methods) | |
(declare (optimize (debug 3))) | |
(let* ((gf (make-instance 'standard-generic-function | |
:lambda-list lambda-list)) | |
(mc (closer-mop:generic-function-method-class gf))) | |
(prog1 gf | |
(format t "~&~s~%" methods) | |
(loop for (specializers qualifiers body) in methods | |
for (method-lambda initargs) = (multiple-value-list (closer-mop:make-method-lambda gf (closer-mop:class-prototype mc) | |
`(lambda ,lambda-list | |
,@body) | |
nil)) | |
do | |
(format t "~&~s~%" method-lambda) | |
(add-method gf | |
(apply #'make-instance mc | |
:function (compile nil method-lambda) | |
:specializers specializers | |
:qualifiers qualifiers | |
:lambda-list lambda-list | |
initargs)))))) | |
(defun-ct take-until (pred list) | |
(loop for (item . rest) on list | |
until (funcall pred item) | |
collect item into items | |
finally | |
(return (values items | |
(cons item rest))))) | |
(defun-ct get-specializers (specialized-lambda-list) | |
(flet ((get-specializer (specializer) | |
(etypecase specializer | |
(symbol (find-class specializer)) | |
(cons (ecase (car specializer) | |
('eql (closer-mop:intern-eql-specializer (cdr specializer)))))))) | |
(mapcar (lambda (specialized-arg) | |
(if (listp specialized-arg) | |
(get-specializer (cadr specialized-arg)) | |
(find-class t))) | |
specialized-lambda-list))) | |
(defun-ct get-methods (method-definition-list) | |
(loop for (keyword . rest) in method-definition-list | |
unless (eq keyword :method) do | |
(error "method definitions must begin with the :METHOD keyword") | |
collect | |
(multiple-value-bind (qualifiers rest) (take-until #'listp rest) | |
(list (get-specializers (car rest)) | |
qualifiers | |
(cdr rest))))) | |
(defmacro lambda-generic ((&rest lambda-list) &body methods) | |
(let ((methods (get-methods methods))) | |
`(load-time-value | |
(make-anonymous-generic-function ',lambda-list ',methods)))) | |
#+null | |
(lambda-generic (a b) | |
(:method ((a integer) (b integer)) (+ a b)) | |
(:method (a b) 2) | |
(:method :after (a b) (format t "~&~d ~d~%" a b))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment