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>
xrefs 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 locates 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 drefs.
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
xreffunction to construct an arbitrary reference without any checking of validity.locateanddrefto construct a syntactically valid reference (matching thelambda-listin the locative type's definition) that refers to an exisiting definition.resolveto 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 subclassdrefrepresents definitions that exist.
-
drefs can be thought of as referring to definitions that actually exist, although changes in the system can invalidate them (for example, adrefto a function definition can be invalidated byfmakunbound).drefs 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-typeoflocative-typeneed not be defined, and thelocative-argsneed not be valid. Uselocateor thedreffunction to createdrefobjects.
[function] xref= xref1 xref2
See if
xref1andxref2have the samexref-nameandxref-locativeunderequal. Comparing like this makes most sense fordrefs. However, twoxrefs different underxref=may denote the samedrefs.
[function] locate object &optional (errorp t)
Return a
drefrepresenting the definition given by the arguments. In the same dynamic environment, twodrefs denote the same thing if and only if they arexref=.objectmust 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(01) is signalled ifobjectis anxrefwith malformedlocative-args, or if no corresponding definition is found. Iferrorpisnil, thenniland thelocate-errorcondition 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
xrefto construct anxrefwithout 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
objectis anxref, then return the first-class object associated with its definition if any. Returnobjectif it's not anxref. Thus, the value returned is never anxref.(resolve (dref 'print 'function)) ==> #<FUNCTION PRINT>(resolve #'print) ==> #<FUNCTION PRINT>If
objectis anxref, and the definition for it cannot belocated, then signal alocate-errorcondition.(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-errorcondition or returnnildepending onerrorp:(resolve (dref '*print-length* 'variable)) .. debugger invoked on RESOLVE-ERROR: .. Could not resolve *PRINT-LENGTH* VARIABLE.(resolve (dref '*print-length* 'variable) nil) => NILresolveis a partial inverse oflocate: if adrefisresolveable, thenlocateing the object it resolves to recovers thedrefequivalent to the original (xref=and of the same type but noteq).Can be extended via
resolve*.
[condition] locate-error error
Signalled by
locatewhen the definition cannot be found, anderrorpis true.
[condition] resolve-error error
Signalled by
resolvewhen the object defined cannot be returned, anderrorpis true.
3 Listing Definitions
[function] definitions name &key (locative-types (lisp-locative-types))
Return all definitions of
namethat matchlocative-typesas a list ofdrefs.The
dref-names may not be the same asname, for example, whennameis 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
drefs 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-nilvalues filter the list of definitions.Roughly speaking, when
nameorpackageis 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
nameorpackageis astring(01), 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,:pseudomatch alllocative-types,lisp-locative-typesandpseudo-locative-types, respectively.When
packageis: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
cbe 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-stringdoes not print the package of symbols. We say that two strings match ifcase-sensitiveisniland they areequalp, orcase-sensitiveis true and they areequal.case-sensitiveaffects substring comparisons too.If
nameis asymbol, then itssymbol-namemust matchp.If
nameis astring, then it must be a substring ofp.If
packageis:none, thencmust not be asymbol.If
packageis notnilor:none, thencmust be a symbol.If
packageis apackage, it must beeqto thesymbol-packageofc.If
packageis asymbolother than:none, then itssymbol-namemust match thepackage-nameor one of thepackage-nicknamesofsymbol-packageofc.If
packageis astring, then it must be a substring of thepackage-nameofsymbol-packageofc.If
external-onlyandcis a symbol, thencmust be external in a matching package.If
locative-typesisnil, then it matches everything.If
locative-types is non-nil, then thelocative-typeof the candidate definition must be in it (handling:all,:lisp, and:pseudoas described above).
Can be extended via
map-names.
-
Return a list of non-alias locative types. This is the
unionoflisp-locative-typesandpseudo-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
objectornilif the arglist cannot be determined.The second return value indicates whether the arglist has been found. Furthermore,
:ordinaryindicates an ordinary lambda list,:macroa macro lambda list,:deftypea deftype lambda list, and:destructuringa destructuring lambda list. Other non-nilvalues 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) => :DESTRUCTURINGThis function supports
macros,compiler-macros,setffunctions,function(01)s,generic-functions,methods,types,locatives. Note thatarglistdepends on the quality ofswank-backend:arglist. With the exception of SBCL, which has perfect support, all Lisp implementations have minor omissions:deftypelambda lists on ABCL, AllegroCL, CLISP, CCL, CMUCL, ECL;default values in
macrolambda 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 ornilif it cannot be determined (this is used bypax:documentwhen Parsing the docstring). This function is similar in purpose tocl:documentation.Note that some locative types such as
asdf:systems anddeclarations have no docstrings, and some Lisp implementations do not record all docstrings. The following are known to be missing:compiler-macrodocstrings on ABCL, AllegroCL, CCL, ECL;method-combinationdocstrings 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 anerrorcondition is signalled iferrorpelse theerroris 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 resolved 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>variablereferences 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. Theconstantlocative is like thevariablelocative, but it also checks that its object isconstantp.constantreferences do notresolve.
5.2 Locatives for Macros
-
Refers to a global macro, typically defined with
defmacro, or to a special operator.macroreferences do notresolve.
-
Refers to a global symbol macro, defined with
define-symbol-macro. Note that sincedefine-symbol-macrodoes not support docstrings,paxdefines methods on thedocumentationgeneric 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-macroreferences do notresolve.
-
Refers to a compiler macro, typically defined with
define-compiler-macro.compiler-macroreferences do notresolve.
[locative] setf &optional method
Refers to a setf expander (see
defsetfanddefine-setf-expander) or a setf function (e.g.(defun (setf name) ...)or the same withdefgeneric). The format indefsectionis(<name> setf)in all these cases.To refer to methods of a setf generic function, use a
methodlocative insidesetflike this:(dref 'documentation '(setf (method () (t symbol (eql function))))References to setf functions
resolveto 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 thesetflocative for how to reference setf functions). It is also allowed to referencegeneric-functions asfunctions:(dref 'docstring 'function) ==> #<DREF DOCSTRING FUNCTION>
-
Refers to a
generic-function, typically defined withdefgeneric. The name must be asymbol(see thesetflocative for how to reference setf functions).
[locative] method method-qualifiers method-specializers
Refers to
methods named bysymbols (forsetfmethods, see thesetflocative).method-qualifiersandmethod-specializersare 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))>methodis notexportable-locative-type-p.
-
Refers to a
method-combination, defined withdefine-method-combination.method-combinationreferences do notresolve.
[locative] accessor class-name
Refers to an
:accessorin adefclass:(defclass foo () ((xxx :accessor foo-xxx))) (dref 'foo-xxx '(accessor foo)) ==> #<DREF FOO-XXX (ACCESSOR FOO)>An
:accessorindefclasscreates a reader and a writer method. Somewhat arbitrarily,accessorreferencesresolveto the writer method but can belocated with either.
[locative] reader class-name
Like
accessor, but refers to a:readermethod in adefclass.
[locative] writer class-name
Like
accessor, but refers to a:writermethod in adefclass.
[locative] structure-accessor &optional structure-class-name
Refers to an accessor function generated by
defstruct. Alocate-errorcondition is signalled if the wrongstructure-class-nameis provided.Note that there is no portable way to detect structure accessors, and on some platforms,
(locate #'my-accessor),definitionsanddref-aproposwill returnfunction(01) references instead. On such platforms,structure-accessorreferences 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, theirarglistis available.classes andconditions may be referred to astypes:(dref 'xref 'type) ==> #<DREF XREF CLASS>(dref 'locate-error 'type) ==> #<DREF LOCATE-ERROR CONDITION>typereferences do notresolve.
-
Naturally,
classis the locative type forclasses.conditions may be referred to asclasses:(dref 'locate-error 'class) ==> #<DREF LOCATE-ERROR CONDITION>
-
Refers to a declaration, used in
declare,declaimandproclaim.User code may also define new declarations with CLTL2 functionality, but there is currently no way to provide a docstring, and their
arglistis alwaysnil.(cl-environments:define-declaration my-decl (&rest things) (values :declare (cons 'foo things)))declarationreferences do notresolve.Also,
source-locationon declarations currently only works on SBCL.
5.5 Locatives for the Condition System
-
conditionis the locative type forconditions.
-
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-listshould be what calls like(invoke-restart '<symbol> ...)must conform to, but this not enforced.pax"defines" standard CL restarts such asuse-value(01) 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:restartclass, 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-systemsupports.asdf:systemis notexportable-locative-type-p.
-
Refers to a
package, defined bydefpackageormake-package. The name may be anythingfind-packagesupports.packageis notexportable-locative-type-p.
-
Refers to a named
readtabledefined withnamed-readtables:defreadtable, which associates a global name and a docstring with the readtable object. The name may be anythingfind-readtablesupports. Unfortunately,source-locationinformation is not available.readtablereferencesresolvetofind-readtableon their name.
5.7 DRef Locatives
-
This is the locative for locative types defined with
define-locative-type,define-pseudo-locative-typeanddefine-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
paxto work in a limited way with locatives it doesn't know.unknowndefinitions come fromdefinitions, which usesswank/backend:find-definitions. The following examples showpaxstuffing the Swank dspec(:define-alien-type double-float)into anunknownlocative 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))>arglistanddocstringreturnnilforunknowns, butsource-locationworks.
[locative] lambda &key arglist arglist-type docstring docstring-package file file-position snippet &allow-other-keys
A pseudo locative type that carries its
arglist,docstringandsource-locationin the locative itself. Seemake-source-locationfor the description offile,file-position, andsnippet.lambdareferences 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:includelocative 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
functionorvariableand together with names form references.A locative can be a symbol or a list whose
caris 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 themethodlocative).See
xref-locativeanddref-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-typeanddref-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
locateand the standard DRef Operations, but which may be used for other, "presentation" purposes. For example, thevariablelocative'sinitformargument 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 ondrefs. Use it as a statement of intent.
[reader] dref-origin dref
The object from which
locateconstructed thisdref. This is anxrefwhen thelocativeargument tolocatewas non-niland the value NAME-OR-OBJECT argument otherwise.dref-originmay have presentation arguments, which are not included inlocative-argsas is the case withinitformargument of thevariablelocative:(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
initformargument overrides the global binding of*standard-output*when it'spax:documented:(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 oflocativeif it's a list. If it's a symbol, it's that symbol itself.
[function] locative-args locative
Return the
restoflocative(which may be fromxref-locative) if it's a list. If it's a symbol, then returnnil. The locative args should match thelambda-listof thelocative-type's definition, but this is guaranteed only for locatives ofdrefs and is not checked for plainxrefs.
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
resolveable, by specializing docstring* on the class class.
source-location* was specialized on class-dref to demonstrate how
this can be done for non-resolveable 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-typeas alocative, which is the first step in Extending DRef.lambda-listis a destructuring lambda list. Thelocative-argsofdrefs 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,docstringandsource-locationall work on it.Locative types defined with
define-locative-typecan be listed withlisp-locative-types.
[macro] define-pseudo-locative-type locative-type lambda-list &body docstring
Like
define-locative-type, but declare thatlocative-typedoes 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-typecan be listed withpseudo-locative-types.
[macro] define-locative-alias alias locative-type &body docstring
Define
aliasas a locative equivalent tolocative-type(bothsymbols).locative-typemust exist (i.e. be amonglocative-types). For example, let's defineobjectas an alias of theclasslocative:(define-locative-alias object class)Then,
locateing withobjectwill find theclass:(dref 'xref 'object) ==> #<DREF XREF CLASS>The
locative-argsofobject(none in the above) are passed on toclass.(arglist (dref 'object 'locative)) => (&REST ARGS) => :DESTRUCTURINGAlso, see Locative Aliases in
pax.
[macro] define-definition-class locative-type class-name &optional (superclasses '(dref)) &body body
Define a subclass of
dref(01). All definitions withlocative-typemust be of this type. If non-nil,bodyisdefclass' slot definitions and other options.
[generic-function] locate* object
Return a definition of
objectas adref, without actualizing it. Ifobjectis adrefalready, then this function simply returns it. If no definition is found forobject, thenlocate-error(01) is signalled.This function is for extending
locate. Do not call it directly.
[generic-function] dref* name locative-type locative-args
locate*calls this forxrefs which are notdrefs.An
eql(01)-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-errorcondition iflocative-argsdo not match thelambda-listargument oflocative-type(not evaluated).
[function] locate-error &rest format-and-args
Call this function to signal a
locate-errorcondition from the dynamic extent of alocate*method (which includesdref*). It is an error to calllocate-errorelsewhere.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
nameto the list of actualizers. Actualizers are functions of a singledrefargument. They are called withinlocatewhenlocate*returns adref. Their job is to make thedrefmore specific.
[function] remove-dref-actualizer name
Remove the global function denoted by the symbol
namefrom the list of actualizers.
[generic-function] resolve* dref
Return the object defined by the definition
drefrefers to. Signal aresolve-errorcondition by calling theresolve-errorfunction if the lookup fails.To keep
resolvea partial inverse oflocate, a specializedlocate*method or an actualizer must be defined forresolveable 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-errorcondition from the dynamic extent of aresolve*method. It is an error to callresolve-errorelsewhere.format-and-args, if non-nil, is a format string and arguments suitable forformat.
[generic-function] map-definitions fn name locative-type
Call
fnwithdrefs which have the givennameandlocative-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 callsfnwith result ifdrefsucceeds.This function is for extending
definitions. Do not call it directly.
[generic-function] map-names fn locative-type
Call
fnwith names that form adrefwith some locative withlocative-type. The default method tries to formdrefs by combining each interned symbol withlocative-typeand 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 ofdrefif that subclass is notresolveable, 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 ofdrefif that subclass is notresolveable, 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 ofdrefif that subclass is notresolveable, 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 thingslocateable withlocative-typeare 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-directionform above.
[macro] define-definer-for-symbol-locative-type name locative-type &body docstring
Define a macro with
namethat 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-typeis 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. Whensnippetis provided, the match nearest tofile-positionis determined (see the Elispslime-isearchandsource-location-adjusted-file-position).
[function] source-location-p object
See if
objectis 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, iflocationis 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
nilif 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
nilif there is no such Emacs buffer.
[function] source-location-buffer-position location
Return the position of the defining form in
source-location-bufferornilif 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
nilif it's not available.
[function] source-location-adjusted-file-position location
Return the actual file position
locationpoints to allowing for some deviation from the rawsource-location-file-position, which is adjusted by searching for the nearest occurrence ofsource-location-snippetin the file. Needless to say, this can be a very expensive operation.If
source-location-fileisnil,nilis 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.