;;; -*- Mode:LISP; Package:(GF USE CL); Readtable:CL; Base:10 -*- ;;;; Fake Generic Functions for the Lambda -- uses CLOS method-arg syntax (EVAL-WHEN (EVAL LOAD COMPILE) (defun decode-lambda-list (lambda-list) (declare (values instance-arg positional-args keyword-args keyword-names rest-arg allow-other-keys)) (let* ((aux-vars (member '&AUX lambda-list)) (most-args (ldiff lambda-list aux-vars)) (instance-arg (first most-args))) (if (or (null instance-arg) (member instance-arg lambda-list-keywords)) (error "No instance argument was given in the lambda list.") (setq most-args (rest most-args))) (let* ((rest-arg (member '&REST most-args)) (keyword-args (member '&KEY most-args)) (positional-args (ldiff most-args (or keyword-args rest-arg))) (allow-other-keys (member '&ALLOW-OTHER-KEYS lambda-list)) keyword-names) (setq positional-args (remove '&OPTIONAL (mapcar #'(lambda (arg) (if (consp arg) (car arg) arg)) positional-args))) (setq keyword-args (loop for k in (cdr keyword-args) until (member k lambda-list-keywords) when (consp k) do (setq k (car k)) appending (list (intern (symbol-name k) si:pkg-keyword-package) k))) (setq keyword-names (mapcar #'cdr keyword-args)) (setq rest-arg (cadr rest-arg)) (values instance-arg positional-args keyword-args keyword-names rest-arg allow-other-keys)))) (defun check-method-arglist (generic-function-name method-lambda-list) (unless (get generic-function-name 'generic-function) (error "There is no generic ~S function" generic-function-name)) (multiple-value-bind (nil m-pos nil m-key m-rst m-aok) (decode-lambda-list method-lambda-list) (multiple-value-bind (nil g-pos nil g-key g-rst g-aok) (decode-lambda-list (si:arglist generic-function-name)) (unless (and (equal m-pos g-pos) (equal m-key g-key) (equal m-rst g-rst) (equal m-aok g-aok)) (error "The arglist supplied, ~S, does not match the generic arglist for ~S" method-lambda-list generic-function-name))))) );EVAL-WHEN (defmacro defgeneric (function-name lambda-list &body declarations) (multiple-value-bind (instance-arg positional-args keyword-args nil rest-arg) (decode-lambda-list lambda-list) (assert (atom instance-arg) (lambda-list)) (let ((message-sender (if rest-arg 'apply 'funcall)) (message-arglist (append positional-args keyword-args (if rest-arg (list rest-arg))))) `(progn (eval-when (compile load eval) (setf (get ',function-name 'generic-function) t)) (defun ,function-name ,lambda-list ,@declarations (,message-sender ,instance-arg ',function-name ,@message-arglist)))))) (defmacro defmethod (function-name lambda-list &body body) (let ((specialized-arg (first lambda-list)) (ordinary-args (rest lambda-list))) (assert (consp specialized-arg) (lambda-list) "First argument must be of the form (ARGUMENT INSTANCE-TYPE)") (check-method-arglist function-name lambda-list) (let ((flavor (cadr specialized-arg)) (self-var (car specialized-arg))) `(zl:defmethod (,flavor ,function-name) (,@ordinary-args) (let ((,self-var self)) ,@body)))))