File size: 4,880 Bytes
d69fc90 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | (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)))))
|