commit f9622dabf3344a3cce4071101d9ffece53310712
parent 2f3e989cf58c89e606a147a380ea93714dfef7af
Author: Matthew Flatt <mflatt@racket-lang.org>
Date: Mon, 15 Dec 2014 18:03:13 -0700
add `scribble/lp2`
Unlike `scribble/lp` a programm written with `scribble/lp2` can be used
directly, due to its `doc` submodule.
Diffstat:
8 files changed, 190 insertions(+), 123 deletions(-)
diff --git a/scribble-doc/scribblings/scribble/lp-ex.rkt b/scribble-doc/scribblings/scribble/lp-ex.rkt
@@ -1,4 +1,5 @@
-#lang scribble/lp
+#lang scribble/lp2
+@(require scribble/manual)
Literate programs have chunks of code, like this one:
diff --git a/scribble-doc/scribblings/scribble/lp.scrbl b/scribble-doc/scribblings/scribble/lp.scrbl
@@ -2,6 +2,7 @@
@(require scribble/manual scribble/core scribble/html-properties
scribble/latex-properties
racket/runtime-path
+ racket/file
"utils.rkt"
(prefix-in lp-ex: "lp-ex-doc.scrbl")
(for-label scribble/lp-include scribble/lp))
@@ -12,49 +13,56 @@
(make-tex-addition "lp.tex")))
]{Literate Programming}
-Programs written using @racketmodname[scribble/lp] are simultaneously
-two things: a program and a document describing the program.
+Programs written using @racketmodname[scribble/lp2] are simultaneously
+two things: a program and a document describing the program:
-Programs in @racketmodname[scribble/lp] are viewed in two different
-ways, either by running the program directly or by including it with
-@racket[lp-include]. When running the program, all of the
-@racket[chunk] expressions are collected and stitched together into a
-program, and the rest of the module is discarded. When using
-@racket[lp-include], the entire contents of the module are preserved
-and are treated like an ordinary Scribble document, where
-@racket[chunk]s are typeset in a manner similar to @racket[codeblock].
+@itemlist[
+
+ @item{When the program is run, all of the @racket[chunk] expressions
+ are collected and stitched together into a program, and the
+ rest of the module is discarded.}
+
+ @item{When the program is provided to Scribble---or used through
+ @racket[include-section] in another Scribble document with a
+ @raclet[(submod ... doc)] module path---the entire contents of
+ the module are treated like an ordinary Scribble document,
+ where @racket[chunk]s are typeset in a manner similar to
+ @racket[codeblock].}
+
+]
@(define-runtime-path lp-ex "lp-ex.rkt")
For example, consider this program:
-@(call-with-input-file lp-ex
- (lambda (port)
- (verbatim
- #:indent 2
- (apply
- string-append
- (let loop ()
- (let ([line (read-line port 'any)])
- (cond
- [(eof-object? line) '()]
- [(equal? line "") (cons " \n" (loop))]
- [else
- (list* line "\n" (loop))])))))))
+@(codeblock (file->string lp-ex))
When this file is @racket[require]d in the normal manner, it defines a
function @racket[f] that squares its argument, and the documentation
-is ignored. When it is included with @racket[lp-include], it looks
-like this:
+is ignored. When it is rendered as a Scribble document, the output
+looks like this:
@(make-nested-flow
(make-style "LPBoxed" null)
(part-blocks lp-ex:doc))
-@section{@racketmodname[scribble/lp] Language}
+@; ------------------------------------------------------------
+
+@section{@racketmodname[scribble/lp2] Language}
+
+@defmodulelang[scribble/lp2 #:use-sources (scribble/lp)]{The
+@racketmodname[scribble/lp] language provides core support for
+literate programming. It is read like a @racketmodname[scribble/base]
+program, but its bindings extend @racketmodname[racket/base] with two
+forms: @racket[chunk] and @racket[CHUNK].}
+
+More precisely, a module in @racketmodname[scribble/lp2] has its
+@racketmodname[racket/base]-like content in a @racketidfont{doc}
+submodule, which is recognized by tools such as @exec{raco scribble}.
+The content of the @racket[chunk] and @racket[CHUNK] forms is
+stitched together as the immediate content of the module.
-@defmodulelang[scribble/lp]{The @racketmodname[scribble/lp] language
-provides core support for literate programming.}
+@history[#:added "1.8"]
@defform[(chunk id form ...)]{
@@ -83,13 +91,30 @@ use @racket[UNSYNTAX].
}
+@; ------------------------------------------------------------
+
+@section{@racketmodname[scribble/lp] Language}
+
+@defmodulelang[scribble/lp]{Programs written using the older
+@racketmodname[scribble/lp] language are similar to
+@racketmodname[scribble/lp2] programs, except that the module cannot
+be provided directly to Scribble. Instead, the document content must be
+extracted using @racket[lp-include].}
+
+The @racketmodname[scribble/lp] language effectively binds only
+@racket[chunk] and @racket[CHUNK], while all other bindings for
+documentation are taken from the context where @racket[lp-include] is
+used.
+
+@; ------------------------------------------------------------
+
@section{@racketmodname[scribble/lp-include] Module}
@defmodule[scribble/lp-include]{The
@racketmodname[scribble/lp-include] library is normally used within a
Scribble document---that is, a module that starts with something like
-@racket[#, @hash-lang[] scribble/base] or @racket[#, @hash-lang[]
-scribble/manual], instead of @racket[#, @hash-lang[] racket].}
+@racket[#, @hash-lang[] @racketmodname[scribble/base]] or @racket[#, @hash-lang[]
+@racketmodname[scribble/manual]], instead of @racket[#, @hash-lang[] @racketmodname[racket]].}
@defform[(lp-include filename)]{
Includes the source of @racket[filename] as the typeset version of the literate
diff --git a/scribble-lib/info.rkt b/scribble-lib/info.rkt
@@ -22,4 +22,4 @@
(define pkg-authors '(mflatt eli))
-(define version "1.7")
+(define version "1.8")
diff --git a/scribble-lib/scribble/lp/lang/common.rkt b/scribble-lib/scribble/lp/lang/common.rkt
@@ -0,0 +1,102 @@
+#lang racket/base
+
+(provide (except-out (all-from-out racket/base) #%module-begin)
+ module-begin/plain
+ module-begin/doc)
+
+(require (for-syntax racket/base syntax/boundmap racket/list
+ syntax/strip-context))
+
+(begin-for-syntax
+ (define first-id #f)
+ (define main-id #f)
+ (define (mapping-get mapping id)
+ (free-identifier-mapping-get mapping id (lambda () '())))
+ ;; maps a chunk identifier to its collected expressions
+ (define chunks (make-free-identifier-mapping))
+ ;; maps a chunk identifier to all identifiers that are used to define it
+ (define chunk-groups (make-free-identifier-mapping))
+ (define (get-chunk id) (mapping-get chunks id))
+ (define (add-to-chunk! id exprs)
+ (unless first-id (set! first-id id))
+ (when (eq? (syntax-e id) '<*>) (set! main-id id))
+ (free-identifier-mapping-put!
+ chunk-groups id
+ (cons id (mapping-get chunk-groups id)))
+ (free-identifier-mapping-put!
+ chunks id
+ `(,@(mapping-get chunks id) ,@exprs))))
+
+(define-syntax (tangle stx)
+ (define chunk-mentions '())
+ (define stupid-internal-definition-sytnax
+ (unless first-id
+ (raise-syntax-error 'scribble/lp "no chunks")))
+ (define orig-stx (syntax-case stx () [(_ orig) #'orig]))
+ (define (restore nstx d) (datum->syntax orig-stx d nstx nstx))
+ (define (shift nstx) (replace-context orig-stx nstx))
+ (define body
+ (let ([main-id (or main-id first-id)])
+ (restore
+ main-id
+ (let loop ([block (get-chunk main-id)])
+ (append-map
+ (lambda (expr)
+ (if (identifier? expr)
+ (let ([subs (get-chunk expr)])
+ (if (pair? subs)
+ (begin (set! chunk-mentions (cons expr chunk-mentions))
+ (loop subs))
+ (list (shift expr))))
+ (let ([subs (syntax->list expr)])
+ (if subs
+ (list (restore expr (loop subs)))
+ (list (shift expr))))))
+ block)))))
+ (with-syntax ([(body ...) body]
+ ;; construct arrows manually
+ [((b-use b-id) ...)
+ (append-map (lambda (m)
+ (map (lambda (u)
+ (list (syntax-local-introduce m)
+ (syntax-local-introduce u)))
+ (mapping-get chunk-groups m)))
+ chunk-mentions)])
+ #`(begin body ... (let ([b-id (void)]) b-use) ...)))
+
+(define-for-syntax (extract-chunks exprs)
+ (let loop ([exprs exprs])
+ (syntax-case exprs ()
+ [() (void)]
+ [(expr . exprs)
+ (syntax-case #'expr (define-syntax quote-syntax)
+ [(define-values (lifted) (quote-syntax (a-chunk id body ...)))
+ (eq? (syntax-e #'a-chunk) 'a-chunk)
+ (begin
+ (add-to-chunk! #'id (syntax->list #'(body ...)))
+ (loop #'exprs))]
+ [_
+ (loop #'exprs)])])))
+
+(define-for-syntax ((make-module-begin submod?) stx)
+ (syntax-case stx ()
+ [(_ body0 . body)
+ (let ([expanded
+ (expand `(,#'module scribble-lp-tmp-name scribble/private/lp
+ ,@(strip-context #'(body0 . body))))])
+ (syntax-case expanded ()
+ [(module name lang (mb . stuff))
+ (begin (extract-chunks #'stuff)
+ #`(#%module-begin
+ (tangle body0)
+ ;; The `doc` submodule allows a `scribble/lp` module
+ ;; to be provided to `scribble`:
+ #,@(if submod?
+ #`((module doc scribble/doclang2
+ (require scribble/manual
+ (only-in scribble/private/lp chunk CHUNK))
+ #,(strip-context #'(begin body0 . body))))
+ '())))]))]))
+
+(define-syntax module-begin/plain (make-module-begin #f))
+(define-syntax module-begin/doc (make-module-begin #t))
diff --git a/scribble-lib/scribble/lp/lang/lang.rkt b/scribble-lib/scribble/lp/lang/lang.rkt
@@ -1,89 +1,7 @@
#lang racket/base
+(require "common.rkt")
-(provide (except-out (all-from-out racket/base) #%module-begin)
- (rename-out [module-begin #%module-begin]))
-
-(require (for-syntax racket/base syntax/boundmap racket/list
- syntax/strip-context))
-
-(begin-for-syntax
- (define first-id #f)
- (define main-id #f)
- (define (mapping-get mapping id)
- (free-identifier-mapping-get mapping id (lambda () '())))
- ;; maps a chunk identifier to its collected expressions
- (define chunks (make-free-identifier-mapping))
- ;; maps a chunk identifier to all identifiers that are used to define it
- (define chunk-groups (make-free-identifier-mapping))
- (define (get-chunk id) (mapping-get chunks id))
- (define (add-to-chunk! id exprs)
- (unless first-id (set! first-id id))
- (when (eq? (syntax-e id) '<*>) (set! main-id id))
- (free-identifier-mapping-put!
- chunk-groups id
- (cons id (mapping-get chunk-groups id)))
- (free-identifier-mapping-put!
- chunks id
- `(,@(mapping-get chunks id) ,@exprs))))
-
-(define-syntax (tangle stx)
- (define chunk-mentions '())
- (define stupid-internal-definition-sytnax
- (unless first-id
- (raise-syntax-error 'scribble/lp "no chunks")))
- (define orig-stx (syntax-case stx () [(_ orig) #'orig]))
- (define (restore nstx d) (datum->syntax orig-stx d nstx nstx))
- (define (shift nstx) (replace-context orig-stx nstx))
- (define body
- (let ([main-id (or main-id first-id)])
- (restore
- main-id
- (let loop ([block (get-chunk main-id)])
- (append-map
- (lambda (expr)
- (if (identifier? expr)
- (let ([subs (get-chunk expr)])
- (if (pair? subs)
- (begin (set! chunk-mentions (cons expr chunk-mentions))
- (loop subs))
- (list (shift expr))))
- (let ([subs (syntax->list expr)])
- (if subs
- (list (restore expr (loop subs)))
- (list (shift expr))))))
- block)))))
- (with-syntax ([(body ...) body]
- ;; construct arrows manually
- [((b-use b-id) ...)
- (append-map (lambda (m)
- (map (lambda (u)
- (list (syntax-local-introduce m)
- (syntax-local-introduce u)))
- (mapping-get chunk-groups m)))
- chunk-mentions)])
- #`(begin body ... (let ([b-id (void)]) b-use) ...)))
-
-(define-for-syntax (extract-chunks exprs)
- (let loop ([exprs exprs])
- (syntax-case exprs ()
- [() (void)]
- [(expr . exprs)
- (syntax-case #'expr (define-syntax quote-syntax)
- [(define-values (lifted) (quote-syntax (a-chunk id body ...)))
- (eq? (syntax-e #'a-chunk) 'a-chunk)
- (begin
- (add-to-chunk! #'id (syntax->list #'(body ...)))
- (loop #'exprs))]
- [_
- (loop #'exprs)])])))
-
-(define-syntax (module-begin stx)
- (syntax-case stx ()
- [(_ id exprs . body)
- (let ([expanded
- (expand `(,#'module scribble-lp-tmp-name scribble/private/lp
- ,@(strip-context #'(id exprs . body))))])
- (syntax-case expanded ()
- [(module name lang (mb . stuff))
- (begin (extract-chunks #'stuff)
- #'(#%module-begin (tangle id)))]))]))
+(provide (except-out (all-from-out "common.rkt")
+ module-begin/plain
+ module-begin/doc)
+ (rename-out [module-begin/plain #%module-begin]))
diff --git a/scribble-lib/scribble/lp/lang/lang2.rkt b/scribble-lib/scribble/lp/lang/lang2.rkt
@@ -0,0 +1,7 @@
+#lang racket/base
+(require "common.rkt")
+
+(provide (except-out (all-from-out "common.rkt")
+ module-begin/plain
+ module-begin/doc)
+ (rename-out [module-begin/doc #%module-begin]))
diff --git a/scribble-lib/scribble/lp/lang/reader.rkt b/scribble-lib/scribble/lp/lang/reader.rkt
@@ -5,13 +5,11 @@ scribble/lp/lang/lang
#:read read-inside
#:read-syntax read-syntax-inside
#:whole-body-readers? #t
-;; don't use scribble-base-info for the #:info arg, since
-;; scribble/lp files are not directly scribble'able.
#:language-info (scribble-base-language-info)
-#:info (scribble-base-reader-info)
+#:info (scribble-base-info)
(require scribble/reader
(only-in scribble/base/reader
- scribble-base-reader-info
+ scribble-base-info
scribble-base-language-info))
diff --git a/scribble-lib/scribble/lp2.rkt b/scribble-lib/scribble/lp2.rkt
@@ -0,0 +1,16 @@
+#lang racket/base
+(require scribble/private/lp)
+(provide chunk CHUNK)
+
+(module reader syntax/module-reader
+ scribble/lp/lang/lang2
+
+ #:read read-inside
+ #:read-syntax read-syntax-inside
+ #:whole-body-readers? #t
+ #:language-info (scribble-base-language-info)
+ #:info (scribble-base-info)
+ (require scribble/reader
+ (only-in scribble/base/reader
+ scribble-base-info
+ scribble-base-language-info)))