-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
definer.lisp
142 lines (118 loc) · 6.03 KB
/
definer.lisp
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
136
137
138
139
140
141
142
;; Copyright (c) 2022, "the Phoeron" Colin J.E. Lupton <[email protected]>
;; Released under the MIT License. See baphomet/LICENSE for more information.
(in-package :baphomet)
#-lispworks
(defparameter *user-package* :cl-user)
(defparameter *language* :common-lisp)
;;; ABSTRACT DEFINER DECLARATIONS
(defclass definer-class (funcallable-standard-class)
((name :initarg :definer-name :accessor definer-name-of)
(options :initarg :definer-options :accessor definer-options-of)
(signature :initarg :definer-signature :accessor definer-signature-of)
(expansion-env :initarg :definer-expansion-env :accessor definer-expansion-env-of)
(call-form :initarg :definer-call-form :accessor definer-call-form-of)
(forms :initarg :definer-forms :accessor definer-forms-of))
(:documentation "Generic class holding definer meta information."))
(defmethod validate-superclass ((class definer-class) (superclass funcallable-standard-class))
t)
(defclass definer (funcallable-standard-object)
((name :initarg :name :accessor name-of)
(options :initarg :options :accessor options-of)
(signature :initarg :signature :accessor signature-of)
(expansion-env :initarg :expansion-env :accessor expansion-env-of)
(call-form :initarg :call-form :accessor call-form-of)
(forms :initarg :forms :accessor forms-of))
(:metaclass definer-class))
(defmethod validate-superclass ((class definer) (superclass funcallable-standard-object))
t)
(def:print-object-method (definer :identity nil) (self stream)
(format stream "definer ~s" (name-of self)))
(defun get-definer (name)
"Returns definer class for the supplied definer of NAME."
(or (find-class (intern (format nil "~:@(~a-definer~)" name)) :errorp nil)
(error "Unknown definer: `~a'." name)))
(defgeneric available-definer-options (definer)
(:documentation "List of available options for related definer."))
(defgeneric restricted-definer-options (definer)
(:documentation
"List of restricted option combinations for related definer."))
(defgeneric initialize-definer (definer)
(:documentation "Initializes related definer class slots."))
(defmethod initialize-definer ((self definer))
self)
(defgeneric expand-definer (definer)
(:documentation "Expands related definer class into its compilation form."))
(defmethod expand-definer ((self definer))
self)
;;; COMMON ROUTINES
(defun definer-type (definer)
(class-name (class-of definer)))
(defclass keyword-definer (definer) ()
(:metaclass definer-class))
;;; DEFINER MACRO
(in-package :def)
;; (defmacro definer (name-and-options &rest rest)
;; (destructuring-bind (name &rest definer-options) (ensure-list name-and-options)
;; (expand-definer
;; (initialize-definer (make-instance (get-definer name)
;; :definer-options definer-options
;; :forms rest)))))
;; I could increase the generality of definer forms if I delay deconstruction of
;; signatures until the definer being defined gets it
(defmacro def:definer (&whole whole &environment environment
type-name definer-options
(&optional eval-type-op instance-name typed-lambda-list return-type)
&body body
&aux (signature (signature eval-type-op instance-name typed-lambda-list return-type))
(language (ensure-symbol (package-name (symbol-package type-name)) :keyword))
(definer-name (format nil "~A-DEFINER" (symbol-name type-name))))
(declare (symbol type-name eval-type-op instance-name return-type)
(list definer-options typed-lambda-list))
`(progn
(defparameter *current-package-name* (package-name *package*))
(defparameter *current-language-name* (package-name *language*))
(in-package *user-package*)
(defpackage ,(symbol-name type-name)
(:nicknames ,(format nil "~A.TYPES.~A" (package-name language) (symbol-name type-name))
,(format nil "CL.TYPE.~A" (symbol-name type-name)))
(:use cl baphomet))
(in-package ,(symbol-name type-name))
(setf *language* language)
(defparameter *defining-form*
',whole)
(defparameter *defining-environment*
',environment)
(defclass ,(ensure-symbol definer-name) (baphomet:definer)
()
(:metaclass baphomet:definer-class)
(:definer-name 'def:definer)
(:definer-options ,definer-options)
(:definer-signature ,signature)
(:definer-expansion-env ,environment)
(:definer-call-form ,whole)
(:definer-forms ,body))
(defmethod new (&rest initargs)
(apply #'make-instance (cons ',(get-definer type-name) initargs)))
(defmethod available-definer-options ((definer ,(ensure-symbol definer-name)))
,(coerce definer-options 'list))
(defmethod expand-definer ((definer ,(ensure-symbol definer-name)))
,(assoc-val :expander body))
(defmethod initialize-definer ((definer ,(ensure-symbol definer-name)))
,(assoc-val :initializer body))
,@(when (member #\e definer-options :test #'char-equal)
`(export (make-symbol ,(symbol-name type-name)) :def))
(defmacro ,(ensure-symbol type-name :def) (&whole whole &environment environment (&rest options) signature &body body)
(expand-definer
(initialize-definer (new :definer-options options :signature signature
:expansion-env environment :call-form whole
:forms body))))
(in-package *current-package-name*)
(setf *language* (ensure-symbol *current-language-name* :keyword))))
;; (defmacro def:definition (signature (&key options) &body body)
;; `(progn
;; (defun ,(ensure-symbol (name-of signature :def)) ,(lambda-list-of signature)
;; ))
;; ,(expand-definer
;; (initialize-definer (make-instance (get-definer (name-of signature))
;; :definer-options options
;; :forms body))))