DRef Manual
Table of Contents
- 1 Introduction
- 2 Locatives and References
- 3 Listing Definitions
- 4 Operations
- 5 Locative Types
- 6 Glossary
- 7 Extending DRef
[in package DREF]
1 Introduction
What if definitions were first-class objects?
Some defining forms do not create first-class
objects. For example, defun
creates
function
objects, but defvar
does not create variable
objects as no such thing exists. The main purpose of this library is
to fill this gap with the introduction of xref
objects:
(xref '*my-var* 'variable)
==> #<XREF *MY-VAR* VARIABLE>
xref
s just package up a name (*my-var*
) and a
locative (variable
). They need not denote existing definitions
until we actually want to use them:
(docstring (xref '*my-var* 'variable))
.. debugger invoked on LOCATE-ERROR:
.. Could not locate *MY-VAR* VARIABLE.
(defvar *my-var* nil
"This is my var.")
(docstring (xref '*my-var* 'variable))
=> "This is my var."
Behind the scenes, the docstring
function locate
s the definition
corresponding to its xref
argument, turning it into a dref
:
(locate (xref '*my-var* 'variable))
==> #<DREF *MY-VAR* VARIABLE>
Within DRef, the dref
Subclasses form the basis of
extending docstring
, source-location
and arglist
. Outside DRef,
PAX makes pax:document
extensible through
pax:document-object*
, which has methods specialized on dref
s.
Finally, existing definitions can be queried with definitions
and
dref-apropos
:
(definitions 'dref-ext:locate*)
==> (#<DREF LOCATE* GENERIC-FUNCTION>
--> #<DREF LOCATE* (METHOD NIL (GLOSSARY-TERM))>
--> #<DREF LOCATE* (METHOD NIL (SECTION))>
--> #<DREF LOCATE* (METHOD NIL (READTABLE))>
--> #<DREF LOCATE* (METHOD NIL (PACKAGE))>
--> #<DREF LOCATE* (METHOD NIL (ASDF/SYSTEM:SYSTEM))>
--> #<DREF LOCATE* (METHOD NIL (CLASS))>
--> #<DREF LOCATE* (METHOD NIL (METHOD))>
--> #<DREF LOCATE* (METHOD NIL (GENERIC-FUNCTION))>
--> #<DREF LOCATE* (METHOD NIL (FUNCTION))>
--> #<DREF LOCATE* (METHOD (:AROUND) (T))>
--> #<DREF LOCATE* (METHOD NIL (T))> #<DREF LOCATE* (METHOD NIL (XREF))>
--> #<DREF LOCATE* (METHOD NIL (DREF))>)
(dref-apropos 'locate-error :package :dref :external-only t)
==> (#<DREF LOCATE-ERROR CONDITION> #<DREF LOCATE-ERROR FUNCTION>)
(dref-apropos "ate-err" :package :dref :external-only t)
==> (#<DREF LOCATE-ERROR CONDITION> #<DREF LOCATE-ERROR FUNCTION>)
2 Locatives and References
After the Introduction, here we get into the details. Of special interest are:
The
xref
function to construct an arbitrary reference without any checking of validity.locate
anddref
to construct a syntactically valid reference (matching thelambda-list
in the locative type's definition) that refers to an exisiting definition.resolve
to find the first-class (non-xref
) object the definition refers to, if any.
Operations (arglist
, docstring
, source-location
) know how to deal
with references (discussed in the Extending DRef).
-
An
xref
(cross-reference) may represent some kind of definition of its name in the context given by its locative. The definition may not exist and the locative may be malformed. The subclassdref
represents definitions that exist.
-
dref
s can be thought of as referring to definitions that actually exist, although changes in the system can invalidate them (for example, adref
to a function definition can be invalidated byfmakunbound
).dref
s must be created withlocate
, and their purpose is to allow easy specialization of other generic functions (see Extending DRef) and to confine locative validation tolocate
.
[function] xref name locative
A shorthand for
(make-instance 'xref :name name :locative locative)
. It does no error checking: thelocative-type
oflocative-type
need not be defined, and thelocative-args
need not be valid. Uselocate
or thedref
function to createdref
objects.
[function] xref= xref1 xref2
See if
xref1
andxref2
have the samexref-name
andxref-locative
underequal
. Comparing like this makes most sense fordref
s. However, twoxref
s different underxref=
may denote the samedref
s.
[function] locate object &optional (errorp t)
Return a
dref
representing the definition given by the arguments. In the same dynamic environment, twodref
s denote the same thing if and only if they arexref=
.object
must be a supported first-class object, adref
, or anxref
:(locate #'print) ==> #<DREF PRINT FUNCTION>
(locate (locate #'print)) ==> #<DREF PRINT FUNCTION>
(locate (xref 'print 'function)) ==> #<DREF PRINT FUNCTION>
locate-error
(0
1
) is signalled ifobject
is anxref
with malformedlocative-args
, or if no corresponding definition is found. Iferrorp
isnil
, thennil
and thelocate-error
condition are returned instead.(locate (xref 'no-such-function 'function)) .. debugger invoked on LOCATE-ERROR: .. Could not locate NO-SUCH-FUNCTION FUNCTION. .. NO-SUCH-FUNCTION is not a symbol naming a function.
(locate (xref 'print '(function xxx))) .. debugger invoked on LOCATE-ERROR: .. Could not locate PRINT #'XXX. .. Bad arguments (XXX) for locative FUNCTION with lambda list NIL.
(locate "xxx") .. debugger invoked on LOCATE-ERROR: .. Could not locate "xxx".
Use the low-level
xref
to construct anxref
without error checking.Can be extended via
locate*
.
[function] dref name locative &optional (errorp t)
Shorthand for
(locate (xref name locative) errorp)
.
[function] resolve object &optional (errorp t)
If
object
is anxref
, then return the first-class object associated with its definition if any. Returnobject
if it's not anxref
. Thus, the value returned is never anxref
.(resolve (dref 'print 'function)) ==> #<FUNCTION PRINT>
(resolve #'print) ==> #<FUNCTION PRINT>
If
object
is anxref
, and the definition for it cannot belocate
d, then signal alocate-error
condition.(resolve (xref 'undefined 'variable)) .. debugger invoked on LOCATE-ERROR: .. Could not locate UNDEFINED VARIABLE.
If there is a definition, but there is no first-class object corresponding to it, then signal a
resolve-error
condition or returnnil
depending onerrorp
:(resolve (dref '*print-length* 'variable)) .. debugger invoked on RESOLVE-ERROR: .. Could not resolve *PRINT-LENGTH* VARIABLE.
(resolve (dref '*print-length* 'variable) nil) => NIL
resolve
is a partial inverse oflocate
: if adref
isresolve
able, thenlocate
ing the object it resolves to recovers thedref
equivalent to the original (xref=
and of the same type but noteq
).Can be extended via
resolve*
.
[condition] locate-error error
Signalled by
locate
when the definition cannot be found, anderrorp
is true.
[condition] resolve-error error
Signalled by
resolve
when the object defined cannot be returned, anderrorp
is true.
3 Listing Definitions
[function] definitions name &key (locative-types (lisp-locative-types))
Return all definitions of
name
that matchlocative-types
as a list ofdref
s.The
dref-name
s may not be the same asname
, for example, whenname
is a package nickname:(definitions 'pax) ==> (#<DREF "MGL-PAX" PACKAGE>)
Can be extended via
map-definitions
.
[function] dref-apropos name &key package external-only case-sensitive (locative-types '(:lisp))
Return a list of
dref
s corresponding to existing definitions that match the various arguments. First,(dref-apropos nil :locative-types nil)
lists all definitions in the system. Arguments with non-nil
values filter the list of definitions.Roughly speaking, when
name
orpackage
is asymbol
, they must match the whole name of the definition:(dref-apropos 'method :package :dref :external-only t) ==> (#<DREF METHOD CLASS> #<DREF METHOD LOCATIVE>)
On the other hand, when
name
orpackage
is astring
(0
1
), they are matched as substrings:(dref-apropos "method" :package :dref :external-only t) ==> (#<DREF METHOD CLASS> #<DREF METHOD LOCATIVE> --> #<DREF METHOD-COMBINATION CLASS> #<DREF METHOD-COMBINATION LOCATIVE>)
The list of
locative-types
, if non-nil
, filters out definitions whose locative types are not listed:(dref-apropos "method" :package :dref :external-only t :locative-types '(class)) ==> (#<DREF METHOD CLASS> #<DREF METHOD-COMBINATION CLASS>)
In the list, the special keywords
:all
,:lisp
,:pseudo
match alllocative-types
,lisp-locative-types
andpseudo-locative-types
, respectively.When
package
is:none
, only non-symbol names are matched:(dref-apropos "dref" :package :none) ==> (#<DREF "DREF" PACKAGE> #<DREF "DREF-EXT" PACKAGE> --> #<DREF "DREF-TEST" PACKAGE> #<DREF "dref" ASDF/SYSTEM:SYSTEM> --> #<DREF "dref/full" ASDF/SYSTEM:SYSTEM> --> #<DREF "dref/test" ASDF/SYSTEM:SYSTEM> --> #<DREF "dref/test-autoload" ASDF/SYSTEM:SYSTEM>)
The exact rules of filtering are as follows. Let
c
be the name of the candidate definition from the list of all definitions that we are matching against the arguments and denote its string representation(princ-to-string c)
withp
. Note thatprinc-to-string
does not print the package of symbols. We say that two strings match ifcase-sensitive
isnil
and they areequalp
, orcase-sensitive
is true and they areequal
.case-sensitive
affects substring comparisons too.If
name
is asymbol
, then itssymbol-name
must matchp
.If
name
is astring
, then it must be a substring ofp
.If
package
is:none
, thenc
must not be asymbol
.If
package
is notnil
or:none
, thenc
must be a symbol.If
package
is apackage
, it must beeq
to thesymbol-package
ofc
.If
package
is asymbol
other than:none
, then itssymbol-name
must match thepackage-name
or one of thepackage-nicknames
ofsymbol-package
ofc
.If
package
is astring
, then it must be a substring of thepackage-name
ofsymbol-package
ofc
.If
external-only
andc
is a symbol, thenc
must be external in a matching package.If
locative-types
isnil
, then it matches everything.If
locative-type
s is non-nil
, then thelocative-type
of the candidate definition must be in it (handling:all
,:lisp
, and:pseudo
as described above).
Can be extended via
map-names
.
-
Return a list of non-alias locative types. This is the
union
oflisp-locative-types
andpseudo-locative-types
.
[function] lisp-locative-types
Return the locative types that correspond to Lisp definitions except
unknown
. These are the ones defined withdefine-locative-type
.
[function] pseudo-locative-types
Return the locative types that correspond to non-Lisp definitions plus
unknown
. These are the ones defined withdefine-pseudo-locative-type
.
-
Return the list of locatives aliases, defined with
define-locative-alias
.
4 Operations
The following functions take a single object definition as their argument.
They may try to locate
the definition of the object, which may
signal a locate-error
condition.
[function] arglist object
Return the arglist of the definition of
object
ornil
if the arglist cannot be determined.The second return value indicates whether the arglist has been found. Furthermore,
:ordinary
indicates an ordinary lambda list,:macro
a macro lambda list,:deftype
a deftype lambda list, and:destructuring
a destructuring lambda list. Other non-nil
values are also allowed.(arglist #'arglist) => (OBJECT) => :ORDINARY
(arglist (dref 'define-locative-type 'macro)) => (LOCATIVE-TYPE LAMBDA-LIST &BODY DOCSTRING) => :MACRO
(arglist (dref 'method 'locative)) => (METHOD-QUALIFIERS METHOD-SPECIALIZERS) => :DESTRUCTURING
This function supports
macro
s,compiler-macro
s,setf
functions,function
(0
1
)s,generic-function
s,method
s,type
s,locative
s. Note thatarglist
depends on the quality ofswank-backend:arglist
. With the exception of SBCL, which has perfect support, all Lisp implementations have minor omissions:deftype
lambda lists on ABCL, AllegroCL, CLISP, CCL, CMUCL, ECL;default values in
macro
lambda lists on AllegroCL; various edgecases involving traced functions.
Can be extended via
arglist*
[function] docstring object
Return the docstring from the definition of
object
. As the second value, return the*package*
that was in effect when the docstring was installed ornil
if it cannot be determined (this is used bypax:document
when Parsing the docstring). This function is similar in purpose tocl:documentation
.Note that some locative types such as
asdf:system
s anddeclaration
s have no docstrings, and some Lisp implementations do not record all docstrings. The following are known to be missing:compiler-macro
docstrings on ABCL, AllegroCL, CCL, ECL;method-combination
docstrings on ABCL, AllegroCL.
Can be extended via
docstring*
.
[function] source-location object &key errorp
Return the Swank source location for the defining form of
object
. If no source location was found, then either anerror
condition is signalled iferrorp
else theerror
is returned as the second value (with the first beingnil
). The returned Swank location object is to be accessed only through the Source Locations API or to be passed to e.g Slime'sslime-goto-source-location
.Note that the availability of source location information varies greatly across Lisp implementations.
Can be extended via
source-location*
.
5 Locative Types
The following are the locative types supported out of the
box. As all locative types, they are named by symbols. When there is
a CL type corresponding to the reference's locative type, the
references can be resolve
d to a unique object as is the case in
(resolve (dref 'print 'function))
==> #<FUNCTION PRINT>
Even if there is no such CL type, the arglist
, the docstring
, and
the source-location
of the defining form is usually recorded unless
otherwise noted.
5.1 Locatives for Variables
[locative] variable &optional initform
Refers to a global special variable.
initform
, or if not specified, the global value of the variable is to be used for presentation.(dref '*print-length* 'variable) ==> #<DREF *PRINT-LENGTH* VARIABLE>
variable
references do notresolve
.
[locative] constant &optional initform
Refers to a constant variable defined with
defconstant
.initform
, or if not specified, the value of the constant is included in the documentation. Theconstant
locative is like thevariable
locative, but it also checks that its object isconstantp
.constant
references do notresolve
.
5.2 Locatives for Macros
-
Refers to a global macro, typically defined with
defmacro
, or to a special operator.macro
references do notresolve
.
-
Refers to a global symbol macro, defined with
define-symbol-macro
. Note that sincedefine-symbol-macro
does not support docstrings,pax
defines methods on thedocumentation
generic function specialized on(doc-type (eql 'symbol-macro))
.(define-symbol-macro my-mac 42) (setf (documentation 'my-mac 'symbol-macro) "This is MY-MAC.") (documentation 'my-mac 'symbol-macro) => "This is MY-MAC."
symbol-macro
references do notresolve
.
-
Refers to a compiler macro, typically defined with
define-compiler-macro
.compiler-macro
references do notresolve
.
[locative] setf &optional method
Refers to a setf expander (see
defsetf
anddefine-setf-expander
) or a setf function (e.g.(defun (setf name) ...)
or the same withdefgeneric
). The format indefsection
is(<name> setf)
in all these cases.To refer to methods of a setf generic function, use a
method
locative insidesetf
like this:(dref 'documentation '(setf (method () (t symbol (eql function))))
References to setf functions
resolve
to the function object. Setf expander references do notresolve
.
5.3 Locatives for Functions
-
Refers to a global function, typically defined with
defun
. The name must be asymbol
(see thesetf
locative for how to reference setf functions). It is also allowed to referencegeneric-function
s asfunction
s:(dref 'docstring 'function) ==> #<DREF DOCSTRING FUNCTION>
-
Refers to a
generic-function
, typically defined withdefgeneric
. The name must be asymbol
(see thesetf
locative for how to reference setf functions).
[locative] method method-qualifiers method-specializers
Refers to
method
s named bysymbol
s (forsetf
methods, see thesetf
locative).method-qualifiers
andmethod-specializers
are similar to thecl:find-method
's arguments of the same names. For example, the method(defgeneric foo-gf (x y z) (:method :around (x (y (eql 'xxx)) (z string)) (values x y z)))
can be referred to as
(dref 'foo-gf '(method (:around) (t (eql xxx) string))) ==> #<DREF FOO-GF (METHOD (:AROUND) (T (EQL XXX) STRING))>
method
is notexportable-locative-type-p
.
-
Refers to a
method-combination
, defined withdefine-method-combination
.method-combination
references do notresolve
.
[locative] accessor class-name
Refers to an
:accessor
in adefclass
:(defclass foo () ((xxx :accessor foo-xxx))) (dref 'foo-xxx '(accessor foo)) ==> #<DREF FOO-XXX (ACCESSOR FOO)>
An
:accessor
indefclass
creates a reader and a writer method. Somewhat arbitrarily,accessor
referencesresolve
to the writer method but can belocate
d with either.
[locative] reader class-name
Like
accessor
, but refers to a:reader
method in adefclass
.
[locative] writer class-name
Like
accessor
, but refers to a:writer
method in adefclass
.
[locative] structure-accessor &optional structure-class-name
Refers to an accessor function generated by
defstruct
. Alocate-error
condition is signalled if the wrongstructure-class-name
is provided.Note that there is no portable way to detect structure accessors, and on some platforms,
(locate #'my-accessor)
,definitions
anddref-apropos
will returnfunction
(0
1
) references instead. On such platforms,structure-accessor
references do notresolve
.
5.4 Locatives for Types and Declarations
-
This locative can refer to any Lisp type and compound type specifiers such as
and
. For types defined withdeftype
, theirarglist
is available.class
es andcondition
s may be referred to astype
s:(dref 'xref 'type) ==> #<DREF XREF CLASS>
(dref 'locate-error 'type) ==> #<DREF LOCATE-ERROR CONDITION>
type
references do notresolve
.
-
Naturally,
class
is the locative type forclass
es.condition
s may be referred to asclass
es:(dref 'locate-error 'class) ==> #<DREF LOCATE-ERROR CONDITION>
-
Refers to a declaration, used in
declare
,declaim
andproclaim
.User code may also define new declarations with CLTL2 functionality, but there is currently no way to provide a docstring, and their
arglist
is alwaysnil
.(cl-environments:define-declaration my-decl (&rest things) (values :declare (cons 'foo things)))
declaration
references do notresolve
.Also,
source-location
on declarations currently only works on SBCL.
5.5 Locatives for the Condition System
-
condition
is the locative type forcondition
s.
-
A locative to refer to the definition of a restart defined by
define-restart
.
[macro] define-restart symbol lambda-list &body docstring
Associate a definition with the name of a restart, which must be a symbol.
lambda-list
should be what calls like(invoke-restart '<symbol> ...)
must conform to, but this not enforced.pax
"defines" standard CL restarts such asuse-value
(0
1
) withdefine-restart
:(first-line (source-location-snippet (source-location (dref 'use-value 'restart)))) => "(define-restart use-value (value)"
Note that while there is a
cl:restart
class, its instances have no docstring or source location.
5.6 Locatives for Packages and Readtables
-
Refers to a registered
asdf:system
. The name may be anythingasdf:find-system
supports.asdf:system
is notexportable-locative-type-p
.
-
Refers to a
package
, defined bydefpackage
ormake-package
. The name may be anythingfind-package
supports.package
is notexportable-locative-type-p
.
-
Refers to a named
readtable
defined withnamed-readtables:defreadtable
, which associates a global name and a docstring with the readtable object. The name may be anythingfind-readtable
supports. Unfortunately,source-location
information is not available.readtable
referencesresolve
tofind-readtable
on their name.
5.7 DRef Locatives
-
This is the locative for locative types defined with
define-locative-type
,define-pseudo-locative-type
anddefine-locative-alias
.(first-line (source-location-snippet (source-location (dref 'macro 'locative)))) => "(define-locative-type macro ()"
[locative] unknown dspec
This pseudo locative type is to allow
pax
to work in a limited way with locatives it doesn't know.unknown
definitions come fromdefinitions
, which usesswank/backend:find-definitions
. The following examples showpax
stuffing the Swank dspec(:define-alien-type double-float)
into anunknown
locative on SBCL.(definitions 'double-float :locative-types (locative-types)) ==> (#<DREF DOUBLE-FLOAT CLASS> #<DREF DOUBLE-FLOAT (CLHS TYPE)> --> #<DREF DOUBLE-FLOAT (UNKNOWN (:DEFINE-ALIEN-TYPE DOUBLE-FLOAT))>)
(dref 'double-float '(unknown (:define-alien-type double-float))) ==> #<DREF DOUBLE-FLOAT (UNKNOWN (:DEFINE-ALIEN-TYPE DOUBLE-FLOAT))>
arglist
anddocstring
returnnil
forunknown
s, butsource-location
works.
[locative] lambda &key arglist arglist-type docstring docstring-package file file-position snippet &allow-other-keys
A pseudo locative type that carries its
arglist
,docstring
andsource-location
in the locative itself. Seemake-source-location
for the description offile
,file-position
, andsnippet
.lambda
references do notresolve
. The name must benil
.(arglist (dref nil '(lambda :arglist ((x y) z) :arglist-type :macro))) => ((X Y) Z) => :MACRO
(docstring (dref nil '(lambda :docstring "xxx" :docstring-package :dref))) => "xxx" ==> #<PACKAGE "DREF">
(source-location-file (source-location (dref nil '(lambda :file "xxx.el")))) => "xxx.el"
See the
pax:include
locative for an example.
6 Glossary
-
Names are symbols or strings which name functions, types, packages, etc. Together with locatives, they form references.
-
Locatives specify a type of definition such as
function
orvariable
and together with names form references.A locative can be a symbol or a list whose
car
is a symbol. In either case, the symbol is called the locative type, and the rest of the elements are the locative arguments (for example, see themethod
locative).See
xref-locative
anddref-locative
.
-
The locative type is the part of a locative that identifies what kind definition is being referred to. See Locative Types for the list locative types built into DRef.
Locative types are similar to Lisp namespaces.
See
xref-locative-type
anddref-locative-type
.
-
A reference is an name plus a locative, and it identifies a possible definition. References are of class
xref
. When a reference is adref
, it may also be called a definition.
-
references may have arguments (see Adding New Locatives) that do not affect the behaviour of
locate
and the standard DRef Operations, but which may be used for other, "presentation" purposes. For example, thevariable
locative'sinitform
argument is used for presentation bypax:document
. Presentation arguments are available viadref-ext:dref-origin
.
7 Extending DRef
7.1 References
[reader] xref-locative xref (:locative)
The locative of the reference.
The locative is normalized by replacing single-element lists with their only element:
(xref 'print 'function) ==> #<XREF PRINT FUNCTION>
(xref 'print '(function)) ==> #<XREF PRINT FUNCTION>
[reader] dref-locative dref
The same as
xref-locative
, but only works ondref
s. Use it as a statement of intent.
[reader] dref-origin dref
The object from which
locate
constructed thisdref
. This is anxref
when thelocative
argument tolocate
was non-nil
and the value NAME-OR-OBJECT argument otherwise.dref-origin
may have presentation arguments, which are not included inlocative-args
as is the case withinitform
argument of thevariable
locative:(dref '*standard-output* '(variable "see-below")) ==> #<DREF *STANDARD-OUTPUT* VARIABLE>
(dref-origin (dref '*standard-output* '(variable "see-below"))) ==> #<XREF *STANDARD-OUTPUT* (VARIABLE "see-below")>
The
initform
argument overrides the global binding of*standard-output*
when it'spax:document
ed:(first-line (pax:document (dref '*standard-output* '(variable "see-below")) :stream nil)) => "- [variable] *STANDARD-OUTPUT* \"see-below\""
[function] locative-type locative
Return locative type of
locative
(which may be fromxref-locative
). This is the first element oflocative
if it's a list. If it's a symbol, it's that symbol itself.
[function] locative-args locative
Return the
rest
oflocative
(which may be fromxref-locative
) if it's a list. If it's a symbol, then returnnil
. The locative args should match thelambda-list
of thelocative-type
's definition, but this is guaranteed only for locatives ofdref
s and is not checked for plainxref
s.
The following convenience functions are compositions of
{locative-type
, locative-args
} and {xref-locative
,
dref-locative
}.
7.2 Adding New Locatives
Let's see how to tell DRef about new kinds of definitions through
the example of the implementation of the class
locative. Note that
this is a verbatim pax:include
of the sources. Please ignore any
internal machinery. The first step is to define the locative type:
(define-locative-type class ()
"Naturally, CLASS is the locative type for [CLASS][class]es.
[CONDITIONs][type] may be referred to as CLASSes:
```cl-transcript
(dref 'locate-error 'class)
==> #<DREF LOCATE-ERROR CONDITION>
```")
Next, we define a subclass of dref
associated with the
class
locative type and specialize locate*
:
(define-definition-class class class-dref)
(defmethod locate* ((class class))
(make-instance 'class-dref :name (class-name class) :locative 'class))
(defmethod dref* (symbol (locative-type (eql 'class)) locative-args)
(check-locative-args class locative-args)
(unless (and (symbolp symbol)
(find-class symbol nil))
(locate-error "~S does not name a class." symbol))
(make-instance 'class-dref :name symbol :locative 'class))
The first method makes (locate (find-class 'dref))
work, while
the second is for (dref 'dref 'class)
. Naturally, for locative
types that do not define first-class objects, the first method
cannot be defined.
Then, with add-dref-actualizer
, we install a function that that runs
whenever a new dref
is about to be returned from locate
and
turn the locative type
into the locative class
if the denoted
definition is of a class:
(defun actualize-type-to-class (dref)
(when (eq (dref-locative-type dref) 'type)
(dref (dref-name dref) 'class nil)))
(add-dref-actualizer 'actualize-type-to-class)
Finally, we define a resolve*
method to recover the
class
object from a class-dref
. We also specialize
docstring*
and source-location*
:
(defmethod resolve* ((dref class-dref))
(find-class (dref-name dref)))
(defmethod docstring* ((class class))
(documentation* class t))
(defmethod source-location* ((dref class-dref))
(swank-source-location* (resolve dref) (dref-name dref) 'class))
We took advantage of having just made the class locative type being
resolve
able, by specializing docstring*
on the class
class.
source-location*
was specialized on class-dref
to demonstrate how
this can be done for non-resolve
able locative types.
Classes have no arglist, so no arglist*
method is needed. In the
following, we describe the pieces in detail.
[macro] define-locative-type locative-type lambda-list &body docstring
Declare
locative-type
as alocative
, which is the first step in Extending DRef.lambda-list
is a destructuring lambda list. Thelocative-args
ofdref
s with locative typelocative-type
(the argument given to this macro) always conform to this lambda list. Seecheck-locative-args
.For example, if have:
(define-locative-type dummy (x &key y) "Dummy docstring.")
then
(locate 'dummy 'locative)
refers to this definition. That is,arglist
,docstring
andsource-location
all work on it.Locative types defined with
define-locative-type
can be listed withlisp-locative-types
.
[macro] define-pseudo-locative-type locative-type lambda-list &body docstring
Like
define-locative-type
, but declare thatlocative-type
does not correspond to definitions in the Lisp system. Definitions with pseduo locatives are not listed by default bydefinitions
.Locative types defined with
define-pseudo-locative-type
can be listed withpseudo-locative-types
.
[macro] define-locative-alias alias locative-type &body docstring
Define
alias
as a locative equivalent tolocative-type
(bothsymbol
s).locative-type
must exist (i.e. be amonglocative-types
). For example, let's defineobject
as an alias of theclass
locative:(define-locative-alias object class)
Then,
locate
ing withobject
will find theclass
:(dref 'xref 'object) ==> #<DREF XREF CLASS>
The
locative-args
ofobject
(none in the above) are passed on toclass
.(arglist (dref 'object 'locative)) => (&REST ARGS) => :DESTRUCTURING
Also, see Locative Aliases in
pax
.
[macro] define-definition-class locative-type class-name &optional (superclasses '(dref)) &body body
Define a subclass of
dref
(0
1
). All definitions withlocative-type
must be of this type. If non-nil
,body
isdefclass
' slot definitions and other options.
[generic-function] locate* object
Return a definition of
object
as adref
, without actualizing it. Ifobject
is adref
already, then this function simply returns it. If no definition is found forobject
, thenlocate-error
(0
1
) is signalled.This function is for extending
locate
. Do not call it directly.
[generic-function] dref* name locative-type locative-args
locate*
calls this forxref
s which are notdref
s.An
eql
(0
1
)-specialized method must be defined for all new locative types. This function is for extendinglocate
. Do not call it directly.
[macro] check-locative-args locative-type locative-args
Signal a
locate-error
condition iflocative-args
do not match thelambda-list
argument oflocative-type
(not evaluated).
[function] locate-error &rest format-and-args
Call this function to signal a
locate-error
condition from the dynamic extent of alocate*
method (which includesdref*
). It is an error to calllocate-error
elsewhere.format-and-args
, if non-nil
, is a format string and arguments suitable forformat
.
[function] add-dref-actualizer name
Add the global function denoted by the symbol
name
to the list of actualizers. Actualizers are functions of a singledref
argument. They are called withinlocate
whenlocate*
returns adref
. Their job is to make thedref
more specific.
[function] remove-dref-actualizer name
Remove the global function denoted by the symbol
name
from the list of actualizers.
[generic-function] resolve* dref
Return the object defined by the definition
dref
refers to. Signal aresolve-error
condition by calling theresolve-error
function if the lookup fails.To keep
resolve
a partial inverse oflocate
, a specializedlocate*
method or an actualizer must be defined forresolve
able definitions. This function is for extendingresolve
. Do not call it directly.It is an error for methods of this generic function to return an
xref
.
[function] resolve-error &rest format-and-args
Call this function to signal a
resolve-error
condition from the dynamic extent of aresolve*
method. It is an error to callresolve-error
elsewhere.format-and-args
, if non-nil
, is a format string and arguments suitable forformat
.
[generic-function] map-definitions fn name locative-type
Call
fn
withdref
s which have the givenname
andlocative-type
. For most locative types, there is at most one definition, but formethod
, for example, there may be many. The default method simply does(dref name locative-type nil)
and callsfn
with result ifdref
succeeds.This function is for extending
definitions
. Do not call it directly.
[generic-function] map-names fn locative-type
Call
fn
with names that form adref
with some locative withlocative-type
. The default method tries to formdref
s by combining each interned symbol withlocative-type
and nolocative-args
.This function is for extending
dref-apropos
. Do not call it directly.
[generic-function] arglist* object
To extend
arglist
, specialize this on a subclass ofdref
if that subclass is notresolve
able, else on the type of object it resolves to. This function is for extension only. Do not call it directly.
[generic-function] docstring* dref
To extend
docstring
, specialize this on a subclass ofdref
if that subclass is notresolve
able, else on the type of object it resolves to. This function is for extension only. Do not call it directly.
[generic-function] source-location* dref
To extend
source-location
, specialize this on a subclass ofdref
if that subclass is notresolve
able, else on the type of object it resolves to. This function is for extension only. Do not call it directly.
7.3 Symbol Locatives
Let's see how the opaque define-symbol-locative-type
and the
obscure define-definer-for-symbol-locative-type
macros work together
to simplify the common task of associating definition with a symbol
in a certain context.
[macro] define-symbol-locative-type locative-type lambda-list &body docstring
Similar to
define-locative-type
, but it assumes that all thingslocate
able withlocative-type
are going to be symbols defined with a definer defined withdefine-definer-for-symbol-locative-type
. Symbol locatives are for attaching a definition (along with arglist, documentation and source location) to a symbol in a particular context. An example will make everything clear:(define-symbol-locative-type direction () "A direction is a symbol.") (define-definer-for-symbol-locative-type define-direction direction "With DEFINE-DIRECTION, one can document what a symbol means when interpreted as a DIRECTION.") (define-direction up () "UP is equivalent to a coordinate delta of (0, -1).")
After all this,
(dref 'up 'direction)
refers to thedefine-direction
form above.
[macro] define-definer-for-symbol-locative-type name locative-type &body docstring
Define a macro with
name
that can be used to attach a lambda list, documentation, and source location to a symbol in the context oflocative-type
. The defined macro's arglist is(symbol lambda-list &optional docstring)
.locative-type
is assumed to have been defined withdefine-symbol-locative-type
.
7.4 dref
Subclasses
These are the dref
subclasses corresponding to
Locative Types. They are exported to make it possible to go
beyond the standard Operations (e.g. pax:document-object*
) and for
subclassing.
for Variables
for Macros
for Functions
for Types and Declarations
for the Condition System
for Packages and Readtables
for DRef Locatives
7.5 Source Locations
These represent the file or buffer position of a defining
form and are returned by the source-location
function. For
the details, see the Elisp function slime-goto-source-location
.
[function] make-source-location &key file file-position buffer buffer-position snippet
Make a Swank source location. The ultimate reference is
slime.el
. Whensnippet
is provided, the match nearest tofile-position
is determined (see the Elispslime-isearch
andsource-location-adjusted-file-position
).
[function] source-location-p object
See if
object
is a source location object.
[function] source-location-file location
Return the name of the file of the defining form. This may be
nil
, for example, iflocation
is of a defining form that was entered at the REPL, or compiled in the*slime-scratch*
buffer.
[function] source-location-file-position location
Return the file position of the defining form or
nil
if it's not available. The first position is 0.
[function] source-location-buffer location
Return the name of the Emacs buffer of the defining form or
nil
if there is no such Emacs buffer.
[function] source-location-buffer-position location
Return the position of the defining form in
source-location-buffer
ornil
if it's not available. The first position is 1.
[function] source-location-snippet location
Return the defining form or a prefix of it as a string or
nil
if it's not available.
[function] source-location-adjusted-file-position location
Return the actual file position
location
points to allowing for some deviation from the rawsource-location-file-position
, which is adjusted by searching for the nearest occurrence ofsource-location-snippet
in the file. Needless to say, this can be a very expensive operation.If
source-location-file
isnil
,nil
is returned. If there is no snippet, or it doesn't match, thensource-location-file-position
(or 0 if that'snil
) is returned.This is a non-interactive companion to the Elisp function
slime-location-offset
, supporting only file positions and non-partial matching of snippets.