cl-ds / data /repos /cl-annot /src /lib /class.lisp
j14i's picture
977 CL macro transformation examples: CL-native pipeline with SBCL verification
d69fc90 verified
(in-package :cl-user)
(defpackage cl-annot.class
(:nicknames :annot.class)
(:use :cl
:annot.util
:annot.helper)
(:export :metaclass
:export-slots
:export-accessors
:export-constructors
:export-structure
:export-class)
(:import-from :alexandria
:ensure-list
:curry
:compose
:if-let
:symbolicate))
(in-package :annot.class)
(defannotation metaclass (metaclass class-definition-form)
(:arity 2)
(progn-form-replace-last
(lambda (class-definition-form)
(if (get-class-option :metaclass class-definition-form)
(error ":metaclass is not empty")
(append class-definition-form
`((:metaclass ,metaclass)))))
class-definition-form))
(defmacro export-slots (class-definition-form)
(progn-form-replace-last
(lambda (class-definition-form)
(loop for slot-specifier in (slot-specifiers class-definition-form)
for slot = (if (consp slot-specifier)
(car slot-specifier)
slot-specifier)
collect slot into slots
finally
(return
(if slots
`(progn
(export ',slots)
,class-definition-form)
class-definition-form))))
class-definition-form))
(defmacro export-accessors (class-definition-form)
(progn-form-replace-last
(lambda (class-definition-form)
(case (first class-definition-form)
(defclass (get-accessors-in-defclass class-definition-form))
(defstruct (get-accessors-in-defstruct class-definition-form))))
class-definition-form))
(defun get-accessors-in-defclass (class-definition-form)
(loop for slot-specifier in (slot-specifiers class-definition-form)
for slot-options = (when (consp slot-specifier) (cdr slot-specifier))
if slot-options
append (plist-get-all slot-options :reader) into accessors
and append (plist-get-all slot-options :writer) into accessors
and append (plist-get-all slot-options :accessor) into accessors
finally
(return
(if accessors
`(progn
(export ',accessors)
,class-definition-form)
class-definition-form))))
(defun get-conc-name (class-definition-form)
(let ((options (ensure-list (second class-definition-form))))
(if-let ((conc-name
(find-if (lambda (option)
(and (consp option) (eq (first option) :conc-name)))
options)))
(second conc-name)
(if (find :conc-name options)
nil
(symbolicate (first options) '-)))))
(defun get-accessors-in-defstruct (class-definition-form)
`(progn
(export ',(mapcar (compose
(let ((conc-name (get-conc-name class-definition-form)))
(if conc-name
(curry #'symbolicate conc-name)
#'identity))
#'first
#'ensure-list)
(slot-specifiers class-definition-form)))
,class-definition-form))
(defmacro export-constructors (class-definition-form)
(progn-form-replace-last
(lambda (class-definition-form)
(case (first class-definition-form)
(defstruct
(if (consp (second class-definition-form))
(let ((constructor-clauses
(remove-if-not
(lambda (lst) (eq (first lst) :constructor))
(mapcar #'ensure-list
(cdr (second class-definition-form))))))
(if (and (= 1 (length constructor-clauses))
(= 2 (length (car constructor-clauses)))
(null (cadar constructor-clauses)))
class-definition-form
`(progn
(export
',(or (remove nil (mapcar #'second constructor-clauses))
(list (symbolicate
'make- (first (second class-definition-form))))))
,class-definition-form)))
`(progn
(export
'(,(symbolicate
'make- (second class-definition-form))))
,class-definition-form)))
(t class-definition-form)))
class-definition-form))
(defmacro export-class (class-definition-form)
`(annot.std:export*
(export-slots
(export-accessors
,class-definition-form))))
(defmacro export-structure (class-definition-form)
`(annot.std:export*
(export-slots
(export-accessors
(export-constructors
,class-definition-form)))))