;;;; error-handling machinery for PARSE-DEFMACRO, separated from ;;;; PARSE-DEFMACRO code itself because the happy path can be handled ;;;; earlier in the bootstrap sequence than DEFINE-CONDITION can be ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. ;;;; ;;;; This software is derived from the CMU CL system, which was ;;;; written at Carnegie Mellon University and released into the ;;;; public domain. The software is in the public domain and is ;;;; provided with absolutely no warranty. See the COPYING and CREDITS ;;;; files for more information. (in-package "SB!KERNEL") (define-condition defmacro-lambda-list-bind-error (error) ((kind :reader defmacro-lambda-list-bind-error-kind :initarg :kind) (name :reader defmacro-lambda-list-bind-error-name :initarg :name :initform nil))) ;;; shared logic for REPORTing variants of DEFMACRO-LAMBDA-LIST-BIND-ERROR: ;;; Set up appropriate prettying and indentation on STREAM, print some ;;; boilerplate related to CONDITION (an instance of ;;; DEFMACRO-LAMBDA-LIST-BIND-ERROR), then execute BODY. (defmacro !printing-defmacro-lambda-list-bind-error ((condition stream) &body body) `(%printing-defmacro-lambda-list-bind-error ,condition ,stream (lambda (,stream) (declare (type stream ,stream)) ,@body))) (defun %printing-defmacro-lambda-list-bind-error (condition stream fun) (declare (type stream stream) (type function fun)) (pprint-logical-block (stream nil) (format stream "error while parsing arguments to ~A~@[ ~S~]:~2I~:@_" (defmacro-lambda-list-bind-error-kind condition) (defmacro-lambda-list-bind-error-name condition)) (pprint-logical-block (stream nil) (funcall fun stream)))) (define-condition defmacro-bogus-sublist-error (defmacro-lambda-list-bind-error) ((object :reader defmacro-bogus-sublist-error-object :initarg :object) (lambda-list :reader defmacro-bogus-sublist-error-lambda-list :initarg :lambda-list)) (:report (lambda (condition stream) (!printing-defmacro-lambda-list-bind-error (condition stream) (format stream "bogus sublist ~2I~_~S ~I~_to satisfy lambda-list ~2I~_~:S" (defmacro-bogus-sublist-error-object condition) (defmacro-bogus-sublist-error-lambda-list condition)))))) (define-condition arg-count-error (defmacro-lambda-list-bind-error) ((args :reader arg-count-error-args :initarg :args) (lambda-list :reader arg-count-error-lambda-list :initarg :lambda-list) (minimum :reader arg-count-error-minimum :initarg :minimum) (maximum :reader arg-count-error-maximum :initarg :maximum)) (:report (lambda (condition stream) (!printing-defmacro-lambda-list-bind-error (condition stream) (format stream "invalid number of elements in ~2I~_~:S ~ ~I~_to satisfy lambda list ~2I~_~:S: ~I~_" (arg-count-error-args condition) (arg-count-error-lambda-list condition)) (cond ((null (arg-count-error-maximum condition)) (format stream "at least ~W expected" (arg-count-error-minimum condition))) ((= (arg-count-error-minimum condition) (arg-count-error-maximum condition)) (format stream "exactly ~W expected" (arg-count-error-minimum condition))) (t (format stream "between ~W and ~W expected" (arg-count-error-minimum condition) (arg-count-error-maximum condition)))) (format stream ", but ~a found" (if (null (cdr (last (arg-count-error-args condition)))) (length (arg-count-error-args condition)) "not a proper list")))))) (define-condition defmacro-lambda-list-broken-key-list-error (defmacro-lambda-list-bind-error) ((problem :reader defmacro-lambda-list-broken-key-list-error-problem :initarg :problem) (info :reader defmacro-lambda-list-broken-key-list-error-info :initarg :info)) (:report (lambda (condition stream) (!printing-defmacro-lambda-list-bind-error (condition stream) (format stream ;; FIXME: These should probably just be three ;; subclasses of the base class, so that we don't ;; need to maintain the set of tags both here and ;; implicitly wherever this macro is used. (This ;; might get easier once CLOS is initialized in ;; cold init.) (ecase (defmacro-lambda-list-broken-key-list-error-problem condition) (:dotted-list "dotted keyword/value list: ~S") (:odd-length "odd number of elements in keyword/value list: ~S") (:unknown-keyword "~{unknown keyword: ~S; expected one of ~ ~{~S~^, ~}~}")) (defmacro-lambda-list-broken-key-list-error-info condition))))))