src/clos.lisp @ 95393d6a5226

Add `with-result` iterate clause
author Steve Losh <steve@stevelosh.com>
date Tue, 14 Dec 2021 19:12:23 -0500
parents e9553a14c887
children b51a18850dc5
(in-package :losh.clos)

(defun build-slot-definition (conc-name slot-spec)
  (destructuring-bind (name &rest slot-options) (ensure-list slot-spec)
    `(,name
      ,@(unless (getf slot-options :initarg)
          `(:initarg ,(alexandria:make-keyword name)))
      ,@(unless (or (getf slot-options :reader)
                    (getf slot-options :writer)
                    (getf slot-options :accessor))
          `(:accessor ,(if conc-name
                         (symb conc-name name)
                         name)))
      ,@slot-options)))

(defmacro defclass* (name-and-options direct-superclasses slots &rest options)
  "`defclass` without the tedium.

  This is like `defclass`, but the `:initarg` and `:accessor` slot options will
  automatically be filled in with sane values if they aren't given.

  `name-and-options` can be a symbol or a list, which will be destructured
  against `(name &key conc-name)`.

  "
  (destructuring-bind (name &key conc-name)
      (ensure-list name-and-options)
    `(defclass ,name ,direct-superclasses
       ,(mapcar (curry #'build-slot-definition conc-name) slots)
       ,@options)))

(defmacro define-condition* (name-and-options direct-superclasses slots &rest options)
  "`define-condition` without the tedium.

  This is like `define-condition`, but the `:initarg` and `:accessor` slot
  options will automatically be filled in with sane values if they aren't given.

  `name-and-options` can be a symbol or a list, which will be destructured
  against `(name &key conc-name)`.

  "
  (destructuring-bind (name &key conc-name)
      (ensure-list name-and-options)
    `(define-condition ,name ,direct-superclasses
       ,(mapcar (curry #'build-slot-definition conc-name) slots)
       ,@options)))