1 ;;; -*- lisp; show-trailing-whitespace: t; indent-tabs: nil -*-
3 ;;;; Part of this software was originally written as docstrings.lisp in
4 ;;;; SBCL, but is now part of the parse-docstrings project. The file
5 ;;;; docstrings.lisp was written by Rudi Schlatte <rudi@constantly.at>,
6 ;;;; mangled by Nikodemus Siivola, turned into a stand-alone project by
7 ;;;; Luis Oliveira. SBCL is in the public domain and is provided with
8 ;;;; absolutely no warranty.
10 ;;;; parse-docstrings is:
12 ;;;; Copyright (c) 2008 David Lichteblau:
14 ;;;; Permission is hereby granted, free of charge, to any person
15 ;;;; obtaining a copy of this software and associated documentation
16 ;;;; files (the "Software"), to deal in the Software without
17 ;;;; restriction, including without limitation the rights to use, copy,
18 ;;;; modify, merge, publish, distribute, sublicense, and/or sell copies
19 ;;;; of the Software, and to permit persons to whom the Software is
20 ;;;; furnished to do so, subject to the following conditions:
22 ;;;; The above copyright notice and this permission notice shall be
23 ;;;; included in all copies or substantial portions of the Software.
25 ;;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 ;;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 ;;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 ;;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
29 ;;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
30 ;;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31 ;;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 ;;;; DEALINGS IN THE SOFTWARE.
34 #+sbcl
;; FIXME: should handle this in the .asd file
35 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
36 (require 'sb-introspect
))
38 (in-package #:parse-docstrings
)
41 ;;; The DOCUMENTATION* class
43 (defvar *documentation-package
*)
45 (defclass documentation
* ()
46 ((name :initarg
:name
:reader get-name
)
47 (kind :initarg
:kind
:reader get-kind
)
48 (content :accessor get-content
)
49 (children :initarg
:children
:initform nil
:reader get-children
)
50 (package :initform
*documentation-package
* :reader get-package
)
51 (package-name :initform
*documentation-package-name
*
52 :reader get-package-name
)))
57 (defclass markup-element
() ())
58 (defclass block-content
(markup-element) ())
59 (defclass inline-content
(markup-element) ())
61 (defclass parent-mixin
()
62 ((child-elements :initarg
:child-elements
63 :accessor child-elements
)))
65 (defmethod print-object ((object parent-mixin
) stream
)
66 (print-unreadable-object (object stream
:type t
)
67 (prin1 (child-elements object
) stream
)))
69 (defclass text
(inline-content)
70 ((characters :initarg
:characters
71 :accessor characters
)))
73 (defclass preformatted
(parent-mixin block-content
) ())
74 (defclass code
(preformatted) ())
75 (defclass itemization
(parent-mixin block-content
) ())
76 (defclass enumeration
(parent-mixin block-content
) ())
78 (defclass paragraph
(parent-mixin block-content
) ())
79 (defclass div
(parent-mixin block-content
) ())
80 (defclass span
(parent-mixin inline-content
) ())
82 (defclass bold
(parent-mixin inline-content
) ())
83 (defclass italic
(parent-mixin inline-content
) ())
84 (defclass underline
(parent-mixin inline-content
) ())
86 ;; this isn't a parent, because its children aren't markup
87 (defclass definition-list
(block-content)
88 ((items :initarg
:items
89 :accessor definition-list-items
)))
91 ;; this isn't markup by itself, because it can only appear in a
92 ;; definition-list, but its children are markup again
93 (defclass definition-list-item
(parent-mixin)
94 ((title :initarg
:title
95 :accessor definition-title
)))
97 (defclass hyperlink
(parent-mixin inline-content
)
101 (defclass inline-cross-reference
(parent-mixin inline-content
)
104 (defclass unknown-element
(parent-mixin inline-content
)
105 ((name :initarg
:name
107 (plist :initarg
:plist
110 (defun make-text (characters)
111 (check-type characters string
)
112 (make-instance 'text
:characters characters
))
114 (macrolet ((%simple-parent
(constructor class
)
115 `(defun ,constructor
(&rest children
)
116 (dolist (child children
)
117 (check-type child markup-element
))
118 (make-instance ',class
:child-elements children
))))
119 (%simple-parent make-preformatted preformatted
)
120 (%simple-parent make-code code
)
121 (%simple-parent make-itemization itemization
)
122 (%simple-parent make-enumeration enumeration
)
123 (%simple-parent make-paragraph paragraph
)
124 (%simple-parent make-div div
)
125 (%simple-parent make-span span
)
126 (%simple-parent make-bold bold
)
127 (%simple-parent make-italic italic
)
128 (%simple-parent make-underline underline
))
130 (defun make-definition-list (&rest items
)
132 (check-type item definition-list-item
))
133 (make-instance 'definition-list
:items items
))
135 (defun make-definition-list-item (title &rest children
)
136 (check-type title string
)
137 (dolist (child children
)
138 (check-type child markup-element
))
139 (make-instance 'definition-list-item
:title title
:child-elements children
))
141 (defun make-hyperlink (href &rest children
)
142 (check-type href string
)
143 (dolist (child children
)
144 (check-type child markup-element
))
145 (make-instance 'hyperlink
:href href
:child-elements children
))
147 (defun make-unknown-element (name plist
&rest children
)
148 (check-type name string
)
149 (dolist (child children
)
150 (check-type child markup-element
))
151 (iter (for (name value
) on plist by
#'cddr
)
152 (check-type name
(or symbol string
))
153 (check-type value string
))
154 (make-instance 'unknown-element
:name name
156 :child-elements children
))
159 ;;;; Annotation Classes
161 (defclass documentation-annotations
()
162 ((arguments :initform nil
163 :accessor argument-annotations
)
164 (return-values :initform nil
165 :accessor return-value-annotations
)
166 (conditions :initform nil
167 :accessor condition-annotations
)
168 (slot-accessors :initform nil
169 :accessor slot-accessor-annotations
)
170 (constructors :initform nil
171 :accessor constructor-annotation
)
172 (see-also-list :initform nil
173 :accessor see-also-annotations
))
175 "This class stores annotations for docstrings, specifing for additional
176 information on arguments, return values, and cross references.
178 Depending on the docstring syntax in use, annotation can be specified
179 directly in the docstring using special markup.
181 Alternatively, the plist of symbol that names a definition can be used
182 to store annotations separately from the docstring. Refer to the
183 ANNOTATE-DOCUMENTATION macro for details."))
185 (annotate-documentation (documentation-annotations type
)
186 (:slot-accessor argument-annotations
)
187 (:slot-accessor return-value-annotations
)
188 (:slot-accessor condition-annotations
)
189 (:slot-accessor slot-accessor-annotations
)
190 (:slot-accessor constructor-annotation
)
191 (:slot-accessor see-also-annotations
)
192 (:constructor annotations
))
194 (annotate-documentation (argument-annotations function
)
195 (:argument object
"An instance of DOCUMENTATION-ANNOTATIONS")
196 (:return-value
"A list of PARAMETER-LIKE-ANNOTATION objects")
197 "Returns annotations for this function's arguments.
199 Each annotation records the name of the argument, and a docstring
200 describing details of the argument, e.g. its type.
202 It is recommended (but currently not required) that arguments
203 in list correspond to the original names in the lambda list, and that
204 their order is preserved.")
206 (annotate-documentation (return-value-annotations function
)
207 (:argument object
"An instance of DOCUMENTATION-ANNOTATIONS")
208 (:return-value
"A list of PARAMETER-LIKE-ANNOTATION objects")
209 "Returns annotations for this function's return values.
211 Each annotation records a docstring describing details of return value,
212 e.g. its type. Additionally, a name can be specified for annotation,
213 allowing HyperSpec-like descriptions of each return value.
215 Only functions using multiple values will have more than one annotation
218 Where multiple values are used, annotations in this list are stored in the
219 order of their return values.")
221 (annotate-documentation (condition-annotations function
)
222 (:argument object
"An instance of DOCUMENTATION-ANNOTATIONS")
223 (:return-value
"A list of CROSS-REFERENCE-ANNOTATION objects")
224 "Returns annotations for condition classes signalled by this function.
226 Each entry is this list is a cross reference for a type, referring to
227 a condition class that might be signalled.
229 Entries in this list can occur in any order.")
231 (annotate-documentation (constructor-annotations function
)
232 (:argument object
"An instance of DOCUMENTATION-ANNOTATIONS")
233 (:return-value
"A list of CROSS-REFERENCE-ANNOTATION objects")
234 "Returns annotations for functions serving as constructors for this type.
236 In this documentation, constructor for a type is any function that
237 returns fresh instances of that type.
239 This kind of annotation is useful when a type FOO is usually created
240 through a wrapper function MAKE-FOO rather than direct calls to
243 Entries in this list can occur in any order.")
245 (annotate-documentation (slot-accessor-annotations function
)
246 (:argument object
"An instance of DOCUMENTATION-ANNOTATIONS")
247 (:return-value
"A list of CROSS-REFERENCE-ANNOTATION objects")
248 "Returns annotations for functions serving as slot readers or accessors.
250 Annotations in this list document that this class has a slot accessible
251 through the function designated by the cross reference, and possibly
252 settable through a setf function for the same name.
254 This kind of annotation is most useful for programs that opt not to
255 document slots directly, and prefer to document the slot accessors as
256 ordinary functions instead.
258 Entries in this list can occur in any order.")
260 (annotate-documentation (see-also-annotations function
)
261 (:argument object
"An instance of DOCUMENTATION-ANNOTATIONS")
262 (:return-value
"A list of CROSS-REFERENCE-ANNOTATION objects")
263 "Returns annotations for related definitions.
265 Cross-reference annotations in this list are meant to augment the
266 CONDITION-ANNOTATIONS, CONSTRUCTOR-ANNOTATIONS, and
267 SLOT-ACCESSOR-ANNOTATIONS. Any cross reference can be added to this list,
268 assuming that the target of the cross reference is related to the current
269 function, and that relation is not made explict in the docstring.
271 Entries in this list can occur in any order.")
273 (defclass cross-reference-annotation
()
274 ((target :initarg
:target
275 :accessor cross-reference-target
)
276 (doc-type :initarg
:doc-type
277 :accessor cross-reference-doc-type
))
279 "Instances of this class specify cross references between documentation
280 strings. The target of a cross-reference is specified as a pair
281 of a documentation name (for example, a symbol) and a doc-type, which
282 would be suitable as an argument to DOCUMENTATION or DOCUMENTATION*.
284 Cross reference annotations are recorded as a part of
285 DOCUMENTATION-ANNOTATIONS objects, as CONDITION-ANNOTATIONS,
286 SLOT-ACCESSOR-ANNOTATIONS, CONSTRUCTOR-ANNOTATIONS, or
287 SEE-ALSO-ANNOTATIONS."))
289 (annotate-documentation (cross-reference-annotation type
)
290 (:slot-accessor cross-reference-target
)
291 (:slot-accessor cross-reference-doc-type
)
292 (:constructor make-cross-reference-annotation
))
294 (defun make-cross-reference-annotation (target doc-type
)
295 "Returns a fresh instance of CROSS-REFERENCE-ANNOTATION with the
296 slots for CROSS-REFERENCE-TARGET and CROSS-REFERENCE-DOC-TYPE bound
297 to TARGET and DOC-TYPE, respectively."
298 (make-instance 'cross-reference-annotation
302 (annotate-documentation (make-cross-reference-annotation function
)
303 (:argument target
"A documentation name, for example a symbol.")
304 (:argument doc-type
"A documentation type as accepted by DOCUMENTATION*"
305 "as a second argument.")
306 (:return-value
"An instance of cross-reference-annotation"))
308 (defclass parameter-annotation
()
309 ((name :initarg
:name
310 :accessor parameter-name
)
311 (docstring :initarg
:docstring
:accessor parameter-docstring
))
313 "Instances of this class specify documentation on function arguments and
316 The annotation specifies a name, which is required or at least highly
317 recommended for arguments, and optional for return values.
319 The docstring is meant to document the argument or return value and
320 should usually specify at least its type, but ideally also describe
323 (annotate-documentation (parameter-annotation type
)
324 (:slot-accessor parameter-name
)
325 (:slot-accessor parameter-docstring
)
326 (:constructor make-parameter-annotation
))
328 (defun make-parameter-annotation (name docstring
)
329 "Returns a fresh instance of PARAMETER-ANNOTATION with the
330 slots for PARAMETER-NAME and PARAMETER-DOCSTRING bound
331 to name and DOCSTRING, respectively."
332 (make-instance 'parameter-annotation
334 :docstring docstring
))
336 (annotate-documentation (make-parameter-annotation function
)
337 (:argument name
"Symbol naming the argument or return value.")
338 (:argument docstring
"String. This is a documentation string in the"
339 "docstring syntax used for the package that is being documented.")
340 (:return-value
"A fresh PARAMETER-ANNOTATION."))