From: Rudi Schlatte Date: Tue, 6 Apr 2004 15:17:21 +0000 (+0000) Subject: 0.8.9.23 X-Git-Url: http://repo.macrolet.net/gitweb/?a=commitdiff_plain;h=df01da3bc94cf28a52fe949a4f157a970b597ec9;p=sbcl.git 0.8.9.23 - Add a documentation string extractor. Docstrings of exported symbols of the packages listed in doc/manual/Makefile can be included in the manual like so: @include macro-sb-ext-define-source-context.texinfo --- diff --git a/CREDITS b/CREDITS index bb87d4b..c923fd7 100644 --- a/CREDITS +++ b/CREDITS @@ -647,6 +647,12 @@ Stig Erik Sandoe: He showed how to convince the GNU toolchain to build SBCL in a way which supports callbacks from C code into SBCL. +Rudi Schlatte: + He ported Paul Foley's simple-streams implementation from cmucl, + converted the sbcl manual to Texinfo and wrote a documentation + string extractor that keeps function documentation in the manual + current. + Nikodemus Siivola: He provided build fixes, in particular to tame the SunOS toolchain, and has fixed many (stream-related and other) bugs besides. diff --git a/NEWS b/NEWS index 6e9cdc2..8de95f7 100644 --- a/NEWS +++ b/NEWS @@ -2367,6 +2367,11 @@ changes in sbcl-0.8.10 relative to sbcl-0.8.9: * [placeholder for DX summary] ** user code with &REST lists declared dynamic-extent, under high speed or space and low safety and debug optimization policy. + * The manual has been converted to Texinfo format and the debugger + chapter from the cmucl manual has been added + * A facility has been added to extract documentation strings from + sbcl and store them as Texinfo-formatted snippets for inclusion in + the manual (via Texinfo's @include directive) * bug fix: compiler emitted division in optimized DEREF. (thanks for the test case to Dave Roberts) * bug fix: multidimensional simple arrays loaded from FASLs had fill diff --git a/doc/manual/Makefile b/doc/manual/Makefile index f3f5c5a..48c5ec5 100644 --- a/doc/manual/Makefile +++ b/doc/manual/Makefile @@ -7,7 +7,10 @@ PSFILE=sbcl.ps PDFFILE=sbcl.pdf DVIFILE=sbcl.dvi INFOFILE=sbcl.info -HTMLDIR=sbcl +HTMLDIR=$(basename $(ROOTFILE)) +# The value of DOCSTRINGDIR has to end with a slash or you lose (it's +# passed to Lisp's `pathname' function). +DOCSTRINGDIR="docstrings/" ifeq ($(MAKEINFO),) @@ -30,46 +33,54 @@ dist: html pdf - +# html documentation; output in $(HTMLDIR) .PHONY: html html: html-stamp -html-stamp: $(DOCFILES) +html-stamp: $(DOCFILES) docstrings @rm -rf $(HTMLDIR) - $(MAKEINFO) --html $(ROOTFILE) + $(MAKEINFO) -I $(DOCSTRINGDIR) --html $(ROOTFILE) touch html-stamp - +# Postscript documentation .PHONY: ps ps: $(PSFILE) $(PSFILE): $(DVIFILE) dvips -o $@ $< -$(DVIFILE): $(DOCFILES) - texi2dvi $(ROOTFILE) - +$(DVIFILE): $(DOCFILES) docstrings + texi2dvi -I $(DOCSTRINGDIR) $(ROOTFILE) +# PDF documentation .PHONY: pdf pdf: $(PDFFILE) -$(PDFFILE): $(DOCFILES) - texi2pdf $(ROOTFILE) - +$(PDFFILE): $(DOCFILES) docstrings + texi2pdf -I $(DOCSTRINGDIR) $(ROOTFILE) +# info docfiles .PHONY: info info: $(INFOFILE) -$(INFOFILE): $(DOCFILES) - $(MAKEINFO) $(ROOTFILE) +$(INFOFILE): $(DOCFILES) docstrings + $(MAKEINFO) -I $(DOCSTRINGDIR) $(ROOTFILE) + +# Texinfo docstring snippets; output hardcoded in docstrings/ for now. +.PHONY: docstrings +docstrings: docstrings-stamp + +docstrings-stamp: + DOCSTRINGDIR=$(DOCSTRINGDIR) sh docstrings.sh + touch docstrings-stamp .PHONY: clean clean: rm -f *~ *.bak *.orig \#*\# .\#* texput.log - rm -rf $(HTMLDIR) - rm -f $(PSFILE) $(PDFFILE) $(DVIFILE) html-stamp + rm -rf $(HTMLDIR) $(DOCSTRINGDIR) + rm -f $(PSFILE) $(PDFFILE) $(DVIFILE) html-stamp docstrings-stamp rm -f $(TMPFILES) rm -f sbcl.info sbcl.info-* diff --git a/doc/manual/docstrings.lisp b/doc/manual/docstrings.lisp new file mode 100644 index 0000000..44de495 --- /dev/null +++ b/doc/manual/docstrings.lisp @@ -0,0 +1,244 @@ +;;;; -*- lisp -*- + +;;;; (c) 2004 Rudi Schlatte +;;;; Use it as you wish, send changes back to me if you like. + +#+sbcl +(eval-when (:compile-toplevel :load-toplevel :execute) + (require 'sb-introspect) + ) + +(defparameter *documentation-types* + '(compiler-macro + function + method-combination + setf + ;;structure ; also handled by `type' + type + variable) + "A list of symbols accepted as second argument of `documentation'") + +;;; Collecting info from package + +(defun documentation-for-symbol (symbol) + "Collects all doc for a symbol, returns a list of the + form (symbol doc-type docstring). See `*documentation-types*' + for the possible values of doc-type." + (loop for kind in *documentation-types* + for doc = (documentation symbol kind) + when doc + collect (list symbol kind doc))) + +(defun collect-documentation (package) + "Collects all documentation for all external symbols of the + given package, as well as for the package itself." + (let* ((package (find-package package)) + (package-doc (documentation package t)) + (result nil)) + (do-external-symbols (symbol package) + (let ((docs (documentation-for-symbol symbol))) + (when docs (setf result (nconc docs result))))) + (when package-doc + (setf result (nconc (list (list (intern (package-name package) :keyword) + 'package package-doc)) result))))) + +;;; Helpers for texinfo output + +(defvar *texinfo-escaped-chars* "@{}" + "Characters that must be escaped with #\@ for Texinfo.") + +(defun texinfoify (string-designator) + "Return 'string-designator' with characters in + *texinfo-escaped-chars* escaped with #\@" + (let ((name (string string-designator))) + (nstring-downcase + (with-output-to-string (s) + (loop for char across name + when (find char *texinfo-escaped-chars*) + do (write-char #\@ s) + do (write-char char s)))))) + +;;; Begin, rest and end of definition. + +(defun argument-list (fname) + (prog1 + ;; arglist accessors looked up in slime; FIXME: can we depend on + ;; swank instead? Some of the arglist accessors (not found + ;; here) are hairy ... + #+clisp (ext:arglist fname) + #+sbcl (sb-introspect:function-arglist fname) + #+openmcl (ccl:arglist fname) + '(arglist not supported in this implementation) + )) + +(defvar *character-replacements* + '((#\* . "star") (#\/ . "slash")) + "Characters and their replacement names that `alphanumize' + uses. If the replacements contain any of the chars they're + supposed to replace, you deserve to lose.") + +(defvar *characters-to-drop* '(#\\ #\` #\') + "Characters that should be removed by `alphanumize'.") + + +(defun alphanumize (symbol) + "Construct a string without characters like *`' that will + f-star-ck up filename handling. See `*character-replacements*' + and `*characters-to-drop*' for customization." + (let ((name (remove-if #'(lambda (x) (member x *characters-to-drop*)) + (string symbol))) + (chars-to-replace (mapcar #'car *character-replacements*))) + (flet ((replacement-delimiter (index) + (cond ((or (< index 0) (>= index (length name))) "") + ((alphanumericp (char name index)) "-") + (t "")))) + (loop for index = (position-if #'(lambda (x) (member x chars-to-replace)) + name) + while index + do (setf name (concatenate 'string (subseq name 0 index) + (replacement-delimiter (1- index)) + (cdr (assoc (aref name index) + *character-replacements*)) + (replacement-delimiter (1+ index)) + (subseq name (1+ index)))))) + name)) + +(defun unique-name (symbol kind) + (nstring-downcase + (format nil "~A-~A-~A" + (ecase kind + (compiler-macro "compiler-macro") + (function (if (macro-function symbol) + "macro" + "fun")) + (method-combination "method-combination") + (package "package") + (setf "setf-expander") + (structure "struct") + (type (if (find-class symbol) + (if (documentation symbol 'structure) ; cheesy structness check + "struct" + "class") + "type")) + (variable (if (constantp symbol) + "constant" + "var"))) + (package-name (symbol-package symbol)) + (alphanumize symbol) + ))) + +(defun def-begin (symbol kind) + (ecase kind + (compiler-macro "@deffn {Compiler Macro}") + (function (if (macro-function symbol) + "@defmac" + "@defun")) + (method-combination "@deffn {Method Combination}") + (package "@deffn Package") + (setf "@deffn {Setf Expander}") + (structure "@deftp Structure") + (type (if (find-class symbol) + (if (documentation symbol 'structure) ; cheesy structness check + "@deftp Structure" + "@deftp Class") + "@deftp Type")) + (variable (if (constantp symbol) + "@defvr Constant" + "@defvar")))) + +(defparameter *arglist-keywords* + '(&allow-other-keys &aux &body &environment &key &optional &rest &whole)) + +(defun texinfoify-arglist-part (part) + (with-output-to-string (s) + (etypecase part + (string (prin1 (texinfoify part) s)) + (number (prin1 part s)) + (symbol + (if (member part *arglist-keywords*) + (princ (texinfoify part) s) + (format s "@var{~A}" (texinfoify part)))) + (list + (format s "(~{~A~^ ~})" (mapcar #'texinfoify-arglist-part part)))))) + +(defun def-rest (symbol kind) + (case kind + (function + (format nil "~{~A~^ ~}" (mapcar #'texinfoify-arglist-part + (argument-list symbol)))))) + +(defun def-end (symbol kind) + (ecase kind + (compiler-macro "@end deffn") + (function (if (macro-function symbol) + "@end defmac" + "@end defun")) + (method-combination "@end deffn") + (package "@end deffn") + (setf "@end deffn") + ;;(structure "@end deftp") ; caught by `type' + (type (if (find-class symbol) + (if (documentation symbol 'structure) ; cheesy structness check + "@end deftp" + "@end deftp") + "@end deftp")) + (variable (if (constantp symbol) + "@end defvr" + "@defvar")))) + +(defun make-info-file (package &optional filename) + "Create a file containing all available documentation for the + exported symbols of `package' in Texinfo format. If `filename' + is not supplied, a file \".texinfo\" is generated. + + The definitions can be referenced using Texinfo statements like + @ref{__.texinfo}. Texinfo + syntax-significant characters are escaped in symbol names, but + if a docstring contains invalid Texinfo markup, you lose." + (let* ((package (find-package package)) + (filename (or filename (make-pathname + :name (string-downcase (package-name package)) + :type "texinfo"))) + (docs (sort (collect-documentation package) #'string< :key #'first))) + (with-open-file (out filename :direction :output + :if-does-not-exist :create :if-exists :supersede) + (loop for (symbol kind docstring) in docs + do (format out "~&@anchor{~A}~%~A ~A~@[ ~A~]~%~A~%~A~%~%" + (unique-name symbol kind) + (def-begin symbol kind) + (texinfoify symbol) + (def-rest symbol kind) + docstring + (def-end symbol kind)))) + filename)) + +(defun docstrings-to-texinfo (directory &rest packages) + "Create files in `directory' containing Texinfo markup of all + docstrings of each exported symbol in `packages'. `directory' + is created if necessary. If you supply a namestring that + doesn't end in a slash, you lose. The generated files are of + the form \"__.texinfo\" and + can be included via @include statements. Texinfo + syntax-significant characters are escaped in symbol names, but + if a docstring contains invalid Texinfo markup, you lose." + (let ((directory (merge-pathnames (pathname directory)))) + (ensure-directories-exist directory) + (dolist (package packages) + (loop + with docs = (collect-documentation (find-package package)) + for (symbol kind docstring) in docs + for doc-identifier = (unique-name symbol kind) + do (with-open-file (out + (merge-pathnames + (make-pathname :name doc-identifier :type "texinfo") + directory) + :direction :output + :if-does-not-exist :create :if-exists :supersede) + (format out "~&@anchor{~A}~%~A ~A~@[ ~A~]~%~A~%~A~%~%" + (unique-name symbol kind) + (def-begin symbol kind) + (texinfoify symbol) + (def-rest symbol kind) + docstring + (def-end symbol kind))))) + directory)) diff --git a/doc/manual/docstrings.sh b/doc/manual/docstrings.sh new file mode 100644 index 0000000..51a971d --- /dev/null +++ b/doc/manual/docstrings.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +# Create Texinfo snippets from the documentation of exported symbols. + +# This software is part of the SBCL system. See the README file for +# more information. +# +# This software is in the public domain and is provided with +# absolutely no warranty. See the COPYING and CREDITS files for +# more information. + +# how we invoke SBCL +# +# Until sbcl-0.6.12.8, the shell variable SBCL was bound to a relative +# pathname, but now we take care to bind it to an absolute pathname (still +# generated relative to `pwd` in the tests/ directory) so that tests +# can chdir before invoking SBCL and still work. + +# We create the documentation from the in-tree sbcl if it is found, +# else an installed sbcl is used. +sbclsystem=`pwd`/../../src/runtime/sbcl +if [ -e $sbclsystem ] +then +SBCL="${1:-$sbclsystem --core `pwd`/../output/sbcl.core}" +else +SBCL="${1:-`which sbcl`}" +fi + +# List of package names that documentation will be created for. +PACKAGES=":SB-EXT" + +# Output directory. This has to end with a slash (it's interpreted by +# Lisp's `pathname' function) or you lose. +DOCSTRINGDIR="${DOCSTRINGDIR:-docstrings/}" + + +echo /creating docstring snippets from SBCL=\'$SBCL\' for packages \'$PACKAGES\' + +echo "(progn (load \"docstrings.lisp\") (docstrings-to-texinfo \"$DOCSTRINGDIR\" $PACKAGES) (sb-ext:quit))" | $SBCL --noinform --sysinit /dev/null --userinit /dev/null --noprint --disable-debugger diff --git a/doc/manual/intro.texinfo b/doc/manual/intro.texinfo index 10297f6..8a98d73 100644 --- a/doc/manual/intro.texinfo +++ b/doc/manual/intro.texinfo @@ -229,6 +229,3 @@ have been deleted or are no longer used in the implementation of SBCL itself. @end itemize - - - diff --git a/version.lisp-expr b/version.lisp-expr index 86fcfc8..0915947 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -17,4 +17,4 @@ ;;; checkins which aren't released. (And occasionally for internal ;;; versions, especially for internal versions off the main CVS ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".) -"0.8.9.22" +"0.8.9.23"