commit e2578af0efa85274e4ddb26c153310e72d1ad732
parent 9f4dba78866f5ffe8fd4878cca227849c28812b8
Author: Matthew Flatt <mflatt@racket-lang.org>
Date: Tue, 30 Apr 2013 07:56:09 -0600
scribble/manual: make `defmodule' more flexible
original commit: eb924d75b638f10780fad46126072311e54d88ed
Diffstat:
4 files changed, 338 insertions(+), 157 deletions(-)
diff --git a/collects/scribble/private/manual-mod.rkt b/collects/scribble/private/manual-mod.rkt
@@ -6,7 +6,8 @@
"manual-ex.rkt"
"manual-style.rkt"
"manual-scheme.rkt"
- (for-syntax scheme/base)
+ (for-syntax scheme/base
+ syntax/parse)
(for-label scheme/base))
(provide defmodule defmodule*
@@ -39,91 +40,134 @@
(define spacer (hspace 1))
+(begin-for-syntax
+ (define-splicing-syntax-class link-target?-kw
+ #:description "#:link-target? keyword"
+ (pattern (~seq #:link-target? expr))
+ (pattern (~seq)
+ #:with expr #'#t)))
+
+(define-syntax (defmodule stx)
+ (syntax-parse stx
+ [(_ (~or (~seq #:require-form req)
+ (~seq))
+ (~or (~seq #:multi (name2 ...))
+ name)
+ (~or (~optional (~seq #:link-target? link-target-expr)
+ #:defaults ([link-target-expr #'#t]))
+ (~optional (~seq #:use-sources (pname ...)))
+ (~optional (~seq #:module-paths (modpath ...)))
+ (~optional (~and #:no-declare no-declare))
+ (~optional (~or (~and #:lang language)
+ (~and #:reader readr))))
+ ...
+ . content)
+ (with-syntax ([(name2 ...) (if (attribute name)
+ #'(name)
+ #'(name2 ...))]
+ [(pname ...) (if (attribute pname)
+ #'(pname ...)
+ #'())])
+ (with-syntax ([(decl-exp ...)
+ (if (attribute no-declare)
+ #'()
+ (if (attribute modpath)
+ #'((declare-exporting modpath ... #:use-sources (pname ...)))
+ #'((declare-exporting name2 ... #:use-sources (pname ...)))))]
+ [kind (cond
+ [(attribute language) #'#t]
+ [(attribute readr) #''reader]
+ [else #'#f])]
+ [modpaths (if (attribute modpath)
+ #'(list (racketmodname modpath) ...)
+ #'#f)]
+ [req (if (attribute req)
+ #'req
+ #'(racket require))]
+ [(show-name ...)
+ (if (attribute modpath)
+ #'(name2 ...)
+ #'((racketmodname name2) ...))])
+ #'(begin
+ decl-exp ...
+ (*defmodule (list show-name ...)
+ modpaths
+ link-target-expr
+ kind
+ (list . content)
+ req))))]))
+
+;; ----------------------------------------
+;; old forms for backward compatibility:
+
(define-syntax defmodule*/no-declare
(syntax-rules ()
[(_ #:require-form req (name ...) . content)
- (*defmodule (list (racketmodname name) ...)
- #f
- #f
- (list . content)
- req)]
+ (defmodule #:require-form req
+ #:names (name ...)
+ #:no-declare
+ . content)]
[(_ (name ...) . content)
- (defmodule*/no-declare #:require-form (racket require) (name ...)
+ (defmodule #:multi (name ...)
+ #:no-declare
. content)]))
(define-syntax defmodule*
(syntax-rules ()
- [(_ #:require-form req (name ...) #:use-sources (pname ...) . content)
- (begin (declare-exporting name ... #:use-sources (pname ...))
- (defmodule*/no-declare #:require-form req (name ...) . content))]
- [(_ #:require-form req (name ...) . content)
- (defmodule* #:require-form req (name ...) #:use-sources () . content)]
- [(_ (name ...) #:use-sources (pname ...) . content)
- (defmodule* #:require-form (racket require) (name ...) #:use-sources (pname ...)
- . content)]
- [(_ (name ...) . content)
- (defmodule* (name ...) #:use-sources () . content)]))
-
-(define-syntax defmodule
- (syntax-rules ()
- [(_ #:require-form req name . content)
- (defmodule* #:require-form req (name) . content)]
- [(_ name . content)
- (defmodule* (name) . content)]))
+ [(_ #:require-form req (name ...) . options+content)
+ (defmodule #:require-form req #:multi (name ...)
+ . options+content)]
+ [(_ (name ...) . options+content)
+ (defmodule #:multi (name ...) . options+content)]))
(define-syntax defmodulelang*/no-declare
(syntax-rules ()
- [(_ (lang ...) #:module-paths (modpath ...) . content)
- (*defmodule (list lang ...)
- (list (racketmodname modpath) ...)
- #t (list . content) #f)]
- [(_ (lang ...) . content)
- (*defmodule (list (racketmodname lang) ...)
- #f #t (list . content) #f)]))
+ [(_ (lang ...) . options+content)
+ (defmodule #:multi (lang ...)
+ #:lang
+ #:no-declare
+ . options+content)]))
(define-syntax defmodulelang*
(syntax-rules ()
- [(_ (name ...) #:module-paths (modpath ...)
- #:use-sources (pname ...)
- . content)
- (begin (declare-exporting modpath ... #:use-sources (pname ...))
- (defmodulelang*/no-declare (name ...)
- #:module-paths (modpath ...)
- . content))]
- [(_ (name ...) #:module-paths (modpath ...) . content)
- (defmodulelang* (name ...)
- #:module-paths (modpath ...)
- #:use-sources () . content)]
- [(_ (name ...) #:use-sources (pname ...) . content)
- (defmodulelang* ((racketmodname name) ...)
- #:module-paths (name ...)
- #:use-sources (pname ...) . content)]
- [(_ (name ...) . content)
- (defmodulelang* (name ...) #:use-sources () . content)]))
+ [(_ (name ...) . options+content)
+ (defmodule #:multi (name ...)
+ #:lang
+ . options+content)]))
(define-syntax defmodulelang
(syntax-rules ()
- [(_ lang #:module-path modpath . content)
- (defmodulelang* (lang) #:module-paths (modpath) . content)]
- [(_ lang . content)
- (defmodulelang* (lang) . content)]))
-
-(define-syntax-rule (defmodulereader*/no-declare (lang ...) . content)
- (*defmodule (list (racketmodname lang) ...)
- #f 'reader (list . content) #f))
+ [(_ lang #:module-path modpath . options+content)
+ (defmodule lang
+ #:module-paths (modpath)
+ #:lang
+ . options+content)]
+ [(_ lang . options+content)
+ (defmodule lang
+ #:lang
+ . options+content)]))
+
+(define-syntax-rule (defmodulereader*/no-declare (lang ...) . options+content)
+ (defmodule #:multi (lang ...)
+ #:reader
+ #:no-declare
+ . options+content))
(define-syntax defmodulereader*
(syntax-rules ()
- [(_ (name ...) #:use-sources (pname ...) . content)
- (begin (declare-exporting name ... #:use-sources (pname ...))
- (defmodulereader*/no-declare (name ...) . content))]
- [(_ (name ...) . content)
- (defmodulereader* (name ...) #:use-sources () . content)]))
+ [(_ (name ...) . options+content)
+ (defmodule #:multi (name ...)
+ #:reader
+ . options+content)]))
+
+(define-syntax-rule (defmodulereader lang . options+content)
+ (defmodule lang
+ #:reader
+ . options+content))
-(define-syntax-rule (defmodulereader lang . content)
- (defmodulereader* (lang) . content))
+;; ----------------------------------------
-(define (*defmodule names modpaths lang content req)
+(define (*defmodule names modpaths link-target? lang content req)
(let ([modpaths (or modpaths names)])
(make-splice
(cons
@@ -131,6 +175,9 @@
"defmodule"
(map
(lambda (name modpath)
+ (define modname (if link-target?
+ (make-defracketmodname name modpath)
+ name))
(list
(make-flow
(list
@@ -139,21 +186,24 @@
spacer
(case lang
[(#f)
- (list (racket (#,req #,(make-defracketmodname name modpath))))]
+ (list (racket (#,req #,modname)))]
[(#t)
- (list (hash-lang) spacer (make-defracketmodname name modpath))]
+ (list (hash-lang) spacer modname)]
[(reader)
- (list (racketmetafont "#reader") spacer (make-defracketmodname name modpath))]
+ (list (racketmetafont "#reader") spacer modname)]
[(just-lang)
- (list (hash-lang) spacer (make-defracketmodname name modpath))])))))))
+ (list (hash-lang) spacer modname)]
+ [else (error 'defmodule "unknown mode: ~e" lang)])))))))
names
modpaths))
- (append (map (lambda (modpath)
- (make-part-tag-decl
- (intern-taglet
- `(mod-path ,(datum-intern-literal
- (element->string modpath))))))
- modpaths)
+ (append (if link-target?
+ (map (lambda (modpath)
+ (make-part-tag-decl
+ (intern-taglet
+ `(mod-path ,(datum-intern-literal
+ (element->string modpath))))))
+ modpaths)
+ null)
(flow-paragraphs (decode-flow content)))))))
(define the-module-path-index-desc (make-module-path-index-desc))
diff --git a/collects/scribblings/scribble/manual.scrbl b/collects/scribblings/scribble/manual.scrbl
@@ -518,87 +518,90 @@ corresponding @racketidfont{racket...} binding.}
@; ------------------------------------------------------------------------
@section[#:tag "doc-modules"]{Documenting Modules}
-@defform/subs[(defmodule maybe-req id maybe-sources pre-flow ...)
+@defform/subs[(defmodule maybe-req one-or-multi option ... pre-flow ...)
([maybe-req code:blank
- (code:line #:require-form expr)]
- [maybe-sources code:blank
- (code:line #:use-sources (mod-path ...))])]{
-
-Produces a sequence of flow elements (encaptured in a @racket[splice])
-to start the documentation for a module that can be @racket[require]d
-using the path @racket[id]. The @tech{decode}d @racket[pre-flow]s
-introduce the module, but need not include all of the module content.
-
-Besides generating text, this form expands to a use of
-@racket[declare-exporting] with @racket[id]; the
-@racket[#:use-sources] clause, if provided, is propagated to
-@racket[declare-exporting]. Consequently, @racket[defmodule] should be
-used at most once in a section, though it can be shadowed with
-@racket[defmodule]s in sub-sections.
-
-If a @racket[#:require-form] clause is provided, the given expression
-produces an element to use instead of @racket[require] for
-the declaration of the module. This is useful to suggest a different
-way of accessing the module instead of through @racket[require].
-
-Hyperlinks created by @racket[racketmodname] are associated with the
-enclosing section, rather than the local @racket[id] text.}
-
-
-@defform*[[(defmodulelang id maybe-sources pre-flow ...)
- (defmodulelang content-expr #:module-paths (mod-path ...)
- maybe-sources pre-flow ...)]]{
-
-Like @racket[defmodule], but documents @racket[id] as a module path
-suitable for use by either @racket[require] or @hash-lang[]. If the
-module path for @racket[require] is syntactically different from the
-@hash-lang[] form, use the @racket[#:module-paths] to provide them
-separately.}
-
-@defform[(defmodulereader id maybe-sources pre-flow ...)]{
-
-Like @racket[defmodule], but documents @racket[id] as a module path
-suitable for use with @racketmetafont{#reader}.}
-
-
-@deftogether[(
-@defform[(defmodule* maybe-req (id ...+) maybe-sources pre-flow ...)]
-@defform*[[(defmodulelang* (id ...+) maybe-sources pre-flow ...)
- (defmodulelang* (content-expr ...+) #:module-paths (mod-path ...+)
- maybe-sources pre-flow ...)]]
-@defform[(defmodulereader* (id ...+) maybe-sources pre-flow ...)]
-)]{
-
-Like @racket[defmodule], etc., but introduces multiple module paths instead
-of just one.}
-
-@deftogether[(
-@defform[(defmodule*/no-declare maybe-req (id ...) pre-flow ...)]
-@defform*[[(defmodulelang*/no-declare (id ...) pre-flow ...)
- (defmodulelang*/no-declare (content-expr ...)
- #:module-paths (mod-path ...+) pre-flow ...)]]
-@defform[(defmodulereader*/no-declare (id ...) pre-flow ...)]
-)]{
-
-Like @racket[defmodule*], etc., but without expanding to
-@racket[declare-exporting]. Use this form when you want to provide a
-more specific list of modules (e.g., to name both a specific module
-and one that combines several modules) via your own
-@racket[declare-exporting] declaration.}
-
-@defform/subs[(declare-exporting mod-path ... maybe-sources)
+ (code:line #:require-form content-expr)]
+ [one-or-multi module-spec
+ (code:line #:multi (module-spec ...+))]
+ [module-spec module-path
+ content-expr]
+ [option (code:line #:module-paths (module-path ...))
+ #:no-declare
+ (code:line #:use-sources (src-module-path ...))
+ (code:line #:link-target? link-target?-expr)
+ #:lang
+ #:reader])]{
+
+Produces a sequence of flow elements (in a @racket[splice])
+to start the documentation for a module---or for multiple modules, if
+the @racket[#:multi] form is used.
+
+Each documented module specified as either a @racket[module-path] (in
+the sense of @racket[require]), in which case the module path is
+typeset using @racket[racketmodname], or by a
+@racket[content-expr]. The latter case is triggered by the presence of
+a @racket[#:module-paths] clause, which provides a plain
+@racket[module-path] for each @racket[module-spec], and the plain
+@racket[module-path] is used for cross-referencing.
+
+If a @racket[#:require-form] clause is provided and if @racket[#:lang]
+and @racket[#:reader] are not provided, the given expression produces
+content to use instead of @racket[require] for the declaration of the
+module. The @racket[#:require-form] clause is useful to suggest a
+different way of accessing the module instead of through
+@racket[require].
+
+Besides generating text, unless @racket[#:no-declare] appears as an
+option, this form expands to a use of @racket[declare-exporting] with
+@racket[module-path]s; the @racket[#:use-sources] clause, if provided,
+is propagated to @racket[declare-exporting]. Consequently,
+@racket[defmodule] should be used at most once in a section without
+@racket[#:no-declare], though it can be shadowed with
+@racket[defmodule]s in sub-sections. Use @racket[#:no-declare] form
+when you want to provide a more specific list of modules (e.g., to
+name both a specific module and one that combines several modules) via
+your own @racket[declare-exporting] declaration
+
+Unless @racket[#:link-target?] is specified with an expression that
+produces a true value, then the @racket[module-path]s are also
+declared as link targets though a @racket[part-tag-decl] (which means
+that the @racket[defmodule] form must appear before any
+sub-parts). These link targets are referenced via
+@racket[racketmodname], which thus points to the enclosing section,
+rather than the individual @racket[module-path]s.
+
+If @racket[#:lang] is provided as an option, then the module name is
+shown after @hash-lang[] (instead of in a @racket[require] form) to
+indicate that the @racket[module-path]s are suitable for use by either
+@racket[require] or @hash-lang[]. If the module path for
+@racket[require] is syntactically different from the @hash-lang[]
+form, use @racket[#:module-paths] to provide the @racket[require]
+variant (and make each @racket[module-spec] a @racket[content-expr]).
+
+If @racket[#:reader] is provided, then the module name is shown after
+@racketmetafont{#reader} to indicate that the module path is intended
+for use as a reader module.
+
+Each @racket[option] form can appear at most once, and @racket[#:lang]
+and @racket[#:reader] are mutually exclusive.
+
+The @tech{decode}d @racket[pre-flow]s introduce the module, but need
+not include all of the module content.}
+
+
+@defform/subs[(declare-exporting module-path ... maybe-sources)
([maybe-sources code:blank
- (code:line #:use-sources (mod-path ...))])]{
+ (code:line #:use-sources (module-path ...))])]{
-Associates the @racket[mod-path]s to all bindings defined within the
+Associates the @racket[module-path]s to all bindings defined within the
enclosing section, except as overridden by other
@racket[declare-exporting] declarations in nested sub-sections. The
-list of @racket[mod-path]s before @racket[#:use-sources] is shown, for
+list of @racket[module-path]s before @racket[#:use-sources] is shown, for
example, when the user hovers the mouse over one of the bindings
defined within the section.
-More significantly, the first @racket[mod-path] before
-@racket[#:use-sources] plus the @racket[mod-path]s after
+More significantly, the first @racket[module-path] before
+@racket[#:use-sources] plus the @racket[module-path]s after
@racket[#:use-sources] determine the binding that is documented by
each @racket[defform], @racket[defproc], or similar form within the
section that contains the @racket[declare-exporting] declaration:
@@ -607,15 +610,15 @@ section that contains the @racket[declare-exporting] declaration:
@item{If no @racket[#:use-sources] clause is supplied, then the
documentation applies to the given name as exported by the first
- @racket[mod-path].}
+ @racket[module-path].}
- @item{If @racket[#:use-sources] @racket[mod-path]s are supplied, then
- they are tried in order before the first @racket[mod-path]. The
- @racket[mod-path] that provides an export with the same
+ @item{If @racket[#:use-sources] @racket[module-path]s are supplied, then
+ they are tried in order before the first @racket[module-path]. The
+ @racket[module-path] that provides an export with the same
symbolic name and @racket[free-label-identifier=?] to the given
name is used as the documented binding. This binding is assumed
to be the same as the identifier as exported by the first
- @racket[mod-path] in the @racket[declare-exporting]
+ @racket[module-path] in the @racket[declare-exporting]
declaration.}
]
@@ -651,11 +654,11 @@ documentation for @racketmodname[racket/base] (unless a re-export has
its own documentation, which would override the automatic connection
when searching for documentation).
-The initial @racket[mod-path]s sequence can be empty if
-@racket[mod-path]s are given with @racket[#:use-sources]. In that
+The initial @racket[module-path]s sequence can be empty if
+@racket[module-path]s are given with @racket[#:use-sources]. In that
case, the rendered documentation never reports an exporting module for
identifiers that are documented within the section, but the
-@racket[mod-path]s in @racket[#:use-sources] provide a binding context
+@racket[module-path]s in @racket[#:use-sources] provide a binding context
for connecting (via hyperlinks) definitions and uses of identifiers.
The @racket[declare-exporting] form should be used no more than once
@@ -671,6 +674,31 @@ sub-sections.}
}
+@defform*[[(defmodulelang one-or-multi maybe-sources option ... pre-flow ...)
+ (defmodulelang one-or-multi #:module-path module-path
+ option ... pre-flow ...)]]{
+Equivalent to @racket[defmodule] with @racket[#:lang]. The
+@racket[#:module-path module-path] is provided, it is converted to
+@racket[#:module-paths (module-path)].}
+
+@defform[(defmodulereader one-or-multi option ... pre-flow ...)]{
+Equivalent to @racket[defmodule] with @racket[#:reader].}
+
+
+@deftogether[(
+@defform[(defmodule* maybe-req (module-spec ...+) option ... pre-flow ...)]
+@defform[(defmodulelang* (module-spec ...+) option ... pre-flow ...)]
+@defform[(defmodulereader* (module-spec ...+) option ... pre-flow ...)]
+)]{
+Equivalent to @racket[defmodule] variants with @racket[#:multi].}
+
+@deftogether[(
+@defform[(defmodule*/no-declare maybe-req (module-spec ...) option ... pre-flow ...)]
+@defform[(defmodulelang*/no-declare (module-spec ...) option ... pre-flow ...)]
+@defform[(defmodulereader*/no-declare (module-spec ...) option ... pre-flow ...)]
+)]{
+Equivalent to @racket[defmodule] variants @racket[#:no-declare].}
+
@; ------------------------------------------------------------------------
@section[#:tag "doc-forms"]{Documenting Forms, Functions, Structure Types, and Values}
diff --git a/collects/tests/scribble/docs/manual.scrbl b/collects/tests/scribble/docs/manual.scrbl
@@ -65,4 +65,48 @@
@defstruct*[#:link-target? #f pn ([x real?] [y real?]) #:extra-constructor-name pt]{A structure type with extra name, again.}
-@defstruct[#:link-target? #f pt ([x real?] [y real?]) #:mutable]{A mutable structure type with extra name, again.}
-\ No newline at end of file
+@defstruct[#:link-target? #f pt ([x real?] [y real?]) #:mutable]{A mutable structure type with extra name, again.}
+
+
+@defmodule["manual-ex0.rkt" #:no-declare #:link-target? #f]
+@defmodule["manual-ex0.rkt" #:lang #:no-declare #:link-target? #f]
+@defmodule["manual-ex0.rkt" #:reader #:no-declare #:link-target? #f]
+
+@section{Sub2}
+@defmodule["manual-ex2.rkt" #:no-declare]
+
+@section{Sub2a}
+@defmodule*/no-declare[("manual-ex2a.rkt")]
+
+@section{Sub3}
+@defmodule["manual-ex3.rkt" #:lang #:no-declare]
+
+@section{Sub3a}
+@defmodulelang*/no-declare[("manual-ex3a.rkt")]
+
+@section{Sub4-5}
+@defmodule[#:multi ("manual-ex4.rkt" "manual-ex5.rkt")]
+
+@section{Sub4a-5a}
+@defmodule*[("manual-ex4a.rkt" "manual-ex5a.rkt")]
+
+@section{Sub6}
+@defmodule[#:require-form (racket load) "manual-ex6.rkt"]
+
+@section{Sub6a}
+@defmodule*[#:require-form (racket load) ("manual-ex6a.rkt")]
+
+@section{Sub7}
+@defmodule["manual-ex7.rkt" #:use-sources (racket/base)]
+
+@section{Sub7a}
+@defmodule*[("manual-ex7a.rkt") #:use-sources (racket/base)]
+
+@section{Sub8}
+@defmodule["manual-ex8.rkt" #:reader]
+
+@section{Sub8a}
+@defmodulereader["manual-ex8a.rkt"]
+
+@section{Sub8b}
+@defmodulereader*[("manual-ex8b.rkt")]
diff --git a/collects/tests/scribble/docs/manual.txt b/collects/tests/scribble/docs/manual.txt
@@ -165,3 +165,63 @@ A structure type with extra name, again.
y : real?
A mutable structure type with extra name, again.
+
+ (require "manual-ex0.rkt")
+
+ #lang "manual-ex0.rkt"
+
+ #reader "manual-ex0.rkt"
+
+1. Sub2
+
+ (require "manual-ex2.rkt")
+
+2. Sub2a
+
+ (require "manual-ex2a.rkt")
+
+3. Sub3
+
+ #lang "manual-ex3.rkt"
+
+4. Sub3a
+
+ #lang "manual-ex3a.rkt"
+
+5. Sub4-5
+
+ (require "manual-ex4.rkt")
+ (require "manual-ex5.rkt")
+
+6. Sub4a-5a
+
+ (require "manual-ex4a.rkt")
+ (require "manual-ex5a.rkt")
+
+7. Sub6
+
+ (load "manual-ex6.rkt")
+
+8. Sub6a
+
+ (load "manual-ex6a.rkt")
+
+9. Sub7
+
+ (require "manual-ex7.rkt")
+
+10. Sub7a
+
+ (require "manual-ex7a.rkt")
+
+11. Sub8
+
+ #reader "manual-ex8.rkt"
+
+12. Sub8a
+
+ #reader "manual-ex8a.rkt"
+
+13. Sub8b
+
+ #reader "manual-ex8b.rkt"