Dspec classes are the namespaces for dspecs. Class names are often the same as the name of the defining form, though documentation types as defined for documentation are also used. See Details of built-in dspec classes and aliases for a list of the classes.
Dspec classes provide a set of handlers, to allow uniform handling of different types of definitions by other parts of the system, such as the editor and various browsers.
The most important handlers are dspec-defined-p and dspec-undefiner for testing if a dspec is currently defined and for undefining a dspec.
New dspec classes are defined using define-dspec-class.
Dspec classes can be subclassed. The top-level classes correspond to distinct global namespaces (such as variable
for variables and constants and function
for functions and macros), and at each level, all the subclasses are distinct from each other (but they do not have to form a complete partition of the superclass). See Details of built-in dspec classes and aliases for the full hierarchy of system-provided classes.
You are allowed to define new top-level classes and subclass them, but you cannot add new subclasses to a system-provided class. However, see Dspec aliases for how to add new ways of making existing definitions.
Define a saved-value
object which has a name and a value:
(defstruct saved-value
name
value)
The objects are defined using def-saved-value
and stored on the plist of their name:
(defmacro def-saved-value (name value)
`(dspec:def (def-saved-value ,name)
(when (record-definition `(def-saved-value ,',name)
(dspec:location))
(setf (get ',name 'saved-value)
(make-saved-value :name ',name
:value ,value))
',name)))
Define a function to retrieve the saved-value
object:
(defun find-saved-value (name)
(get name 'saved-value))
Define a macro to access a saved-value
object:
(defmacro saved-value (name)
`(saved-value-value (find-saved-value ',name)))
Define a dspec class for def-saved-value
dspecs:
(dspec:define-dspec-class def-saved-value nil
"Defined saved values"
:definedp
#'(lambda (name)
;; Find any object that def-saved-value recorded
(not (null (find-saved-value name))))
:undefiner
#'(lambda (dspec)
;; Remove what def-saved-value recorded
`(remprop ,(dspec:dspec-name dspec) 'saved-value))
:object-dspec
#'(lambda (obj)
;; Given a saved-value object, we can reconstruct its dspec
(and (saved-value-p obj)
`(def-saved-value ,(saved-value-name obj)))))
For completeness, define a form parser that generates dspecs from forms:
(dspec:define-form-parser
(def-saved-value
(:parser dspec:single-form-form-parser)))
Note:
this form parser for def-saved-value
is not strictly necessary, because the system provides an implicit form parser which recognizes definitions beginning with "def".
This example is based on that in Complete example of a top-level dspec class.
Define a computed-saved-value
object has a function to compute the value the first time:
(defstruct (computed-saved-value (:include saved-value))
function)
saved-value
objects are defined using def-computed-saved-value and stored on the plist of their name:
(defmacro def-computed-saved-value (name function)
`(dspec:def (def-computed-saved-value ,name)
(when (record-definition `(def-computed-saved-value ,',name)
(dspec:location))
(setf (get ',name 'saved-value)
(make-computed-saved-value :name ',name
:function ,function))
',name)))
Define a function to compute a computed-saved-value
:
(defun ensure-saved-value-computed (name)
(let ((saved-value (find-saved-value name)))
(or (saved-value-value saved-value)
(setf (saved-value-value saved-value)
(funcall
(computed-saved-value-function saved-value))))))
Define a macro to access a computed-saved-value
:
(defmacro computed-saved-value (name)
`(ensure-saved-value-computed ',name))
Define a dspec class for def-computed-saved-value
dspecs:
(dspec:define-dspec-class def-computed-saved-value def-saved-value
"Defined computed saved values"
:definedp
#'(lambda (name)
;; Find any object that def-computed-saved-value recorded
(computed-saved-value-p (find-saved-value name)))
;; The :undefiner is inherited from the superspace.
:object-dspec
#'(lambda (obj)
;; Given a computed-saved-value object, we can reconstruct its dspec
(and (computed-saved-value-p obj)
`(def-computed-saved-value ,(saved-value-name obj)))))
For completeness, define a form parser that generates dspecs from forms:
(dspec:define-form-parser
(def-computed-saved-value
(:parser dspec:single-form-form-parser)))
Note:
this form parser for def-computed-saved-value
is not strictly necessary, because the implicit form parser will recognize definitions beginning with "def".
You can add new ways of making existing definitions and use the dspec system to track these definitions. This is what happens when your defining form expands into a system-provided form. The macro define-dspec-alias is used to inform the dspec system of this.
For example if your definer is:
(defmacro my-defun ((name &rest args) &body body)
`(defun ,name ,args ,@body))
then you would define the form of dspecs for my-defun
definitions like this:
(dspec:define-dspec-alias my-defun (name)
`(defun ,name))
Note: in general you should not include the lambda list in the dspec, because it is not needed to locate the definition later.
Note: to make source location work you will also need a define-form-parser definition for my-defun. This is illustrated in Using pre-defined form parsers.
LispWorks User Guide and Reference Manual - 20 Sep 2017