add scribble/lp2
Unlike `scribble/lp` a programm written with `scribble/lp2` can be used directly, due to its `doc` submodule.
This commit is contained in:
parent
2f3e989cf5
commit
f9622dabf3
|
@ -1,4 +1,5 @@
|
||||||
#lang scribble/lp
|
#lang scribble/lp2
|
||||||
|
@(require scribble/manual)
|
||||||
|
|
||||||
Literate programs have chunks of code, like this one:
|
Literate programs have chunks of code, like this one:
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
@(require scribble/manual scribble/core scribble/html-properties
|
@(require scribble/manual scribble/core scribble/html-properties
|
||||||
scribble/latex-properties
|
scribble/latex-properties
|
||||||
racket/runtime-path
|
racket/runtime-path
|
||||||
|
racket/file
|
||||||
"utils.rkt"
|
"utils.rkt"
|
||||||
(prefix-in lp-ex: "lp-ex-doc.scrbl")
|
(prefix-in lp-ex: "lp-ex-doc.scrbl")
|
||||||
(for-label scribble/lp-include scribble/lp))
|
(for-label scribble/lp-include scribble/lp))
|
||||||
|
@ -12,49 +13,56 @@
|
||||||
(make-tex-addition "lp.tex")))
|
(make-tex-addition "lp.tex")))
|
||||||
]{Literate Programming}
|
]{Literate Programming}
|
||||||
|
|
||||||
Programs written using @racketmodname[scribble/lp] are simultaneously
|
Programs written using @racketmodname[scribble/lp2] are simultaneously
|
||||||
two things: a program and a document describing the program.
|
two things: a program and a document describing the program:
|
||||||
|
|
||||||
Programs in @racketmodname[scribble/lp] are viewed in two different
|
@itemlist[
|
||||||
ways, either by running the program directly or by including it with
|
|
||||||
@racket[lp-include]. When running the program, all of the
|
@item{When the program is run, all of the @racket[chunk] expressions
|
||||||
@racket[chunk] expressions are collected and stitched together into a
|
are collected and stitched together into a program, and the
|
||||||
program, and the rest of the module is discarded. When using
|
rest of the module is discarded.}
|
||||||
@racket[lp-include], the entire contents of the module are preserved
|
|
||||||
and are treated like an ordinary Scribble document, where
|
@item{When the program is provided to Scribble---or used through
|
||||||
@racket[chunk]s are typeset in a manner similar to @racket[codeblock].
|
@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")
|
@(define-runtime-path lp-ex "lp-ex.rkt")
|
||||||
|
|
||||||
For example, consider this program:
|
For example, consider this program:
|
||||||
|
|
||||||
@(call-with-input-file lp-ex
|
@(codeblock (file->string 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))])))))))
|
|
||||||
|
|
||||||
When this file is @racket[require]d in the normal manner, it defines a
|
When this file is @racket[require]d in the normal manner, it defines a
|
||||||
function @racket[f] that squares its argument, and the documentation
|
function @racket[f] that squares its argument, and the documentation
|
||||||
is ignored. When it is included with @racket[lp-include], it looks
|
is ignored. When it is rendered as a Scribble document, the output
|
||||||
like this:
|
looks like this:
|
||||||
|
|
||||||
@(make-nested-flow
|
@(make-nested-flow
|
||||||
(make-style "LPBoxed" null)
|
(make-style "LPBoxed" null)
|
||||||
(part-blocks lp-ex:doc))
|
(part-blocks lp-ex:doc))
|
||||||
|
|
||||||
@section{@racketmodname[scribble/lp] Language}
|
@; ------------------------------------------------------------
|
||||||
|
|
||||||
@defmodulelang[scribble/lp]{The @racketmodname[scribble/lp] language
|
@section{@racketmodname[scribble/lp2] Language}
|
||||||
provides core support for literate programming.}
|
|
||||||
|
@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.
|
||||||
|
|
||||||
|
@history[#:added "1.8"]
|
||||||
|
|
||||||
@defform[(chunk id form ...)]{
|
@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}
|
@section{@racketmodname[scribble/lp-include] Module}
|
||||||
|
|
||||||
@defmodule[scribble/lp-include]{The
|
@defmodule[scribble/lp-include]{The
|
||||||
@racketmodname[scribble/lp-include] library is normally used within a
|
@racketmodname[scribble/lp-include] library is normally used within a
|
||||||
Scribble document---that is, a module that starts with something like
|
Scribble document---that is, a module that starts with something like
|
||||||
@racket[#, @hash-lang[] scribble/base] or @racket[#, @hash-lang[]
|
@racket[#, @hash-lang[] @racketmodname[scribble/base]] or @racket[#, @hash-lang[]
|
||||||
scribble/manual], instead of @racket[#, @hash-lang[] racket].}
|
@racketmodname[scribble/manual]], instead of @racket[#, @hash-lang[] @racketmodname[racket]].}
|
||||||
|
|
||||||
@defform[(lp-include filename)]{
|
@defform[(lp-include filename)]{
|
||||||
Includes the source of @racket[filename] as the typeset version of the literate
|
Includes the source of @racket[filename] as the typeset version of the literate
|
||||||
|
|
|
@ -22,4 +22,4 @@
|
||||||
|
|
||||||
(define pkg-authors '(mflatt eli))
|
(define pkg-authors '(mflatt eli))
|
||||||
|
|
||||||
(define version "1.7")
|
(define version "1.8")
|
||||||
|
|
102
scribble-lib/scribble/lp/lang/common.rkt
Normal file
102
scribble-lib/scribble/lp/lang/common.rkt
Normal file
|
@ -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))
|
|
@ -1,89 +1,7 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
(require "common.rkt")
|
||||||
|
|
||||||
(provide (except-out (all-from-out racket/base) #%module-begin)
|
(provide (except-out (all-from-out "common.rkt")
|
||||||
(rename-out [module-begin #%module-begin]))
|
module-begin/plain
|
||||||
|
module-begin/doc)
|
||||||
(require (for-syntax racket/base syntax/boundmap racket/list
|
(rename-out [module-begin/plain #%module-begin]))
|
||||||
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)))]))]))
|
|
||||||
|
|
7
scribble-lib/scribble/lp/lang/lang2.rkt
Normal file
7
scribble-lib/scribble/lp/lang/lang2.rkt
Normal file
|
@ -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]))
|
|
@ -5,13 +5,11 @@ scribble/lp/lang/lang
|
||||||
#:read read-inside
|
#:read read-inside
|
||||||
#:read-syntax read-syntax-inside
|
#:read-syntax read-syntax-inside
|
||||||
#:whole-body-readers? #t
|
#: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)
|
#:language-info (scribble-base-language-info)
|
||||||
#:info (scribble-base-reader-info)
|
#:info (scribble-base-info)
|
||||||
(require scribble/reader
|
(require scribble/reader
|
||||||
(only-in scribble/base/reader
|
(only-in scribble/base/reader
|
||||||
scribble-base-reader-info
|
scribble-base-info
|
||||||
scribble-base-language-info))
|
scribble-base-language-info))
|
||||||
|
|
||||||
|
|
||||||
|
|
16
scribble-lib/scribble/lp2.rkt
Normal file
16
scribble-lib/scribble/lp2.rkt
Normal file
|
@ -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)))
|
Loading…
Reference in New Issue
Block a user