scribble/eval: add eval:result' and eval:results'

original commit: 2d027e7ee5885b8c70e720db968f348df7fa2949
This commit is contained in:
Matthew Flatt 2012-05-09 18:38:09 -06:00
parent bad524ff54
commit 681837dc32
4 changed files with 125 additions and 22 deletions

View File

@ -1,6 +1,7 @@
#lang racket/base
(require "manual.rkt" "struct.rkt" "scheme.rkt" "decode.rkt"
(only-in "core.rkt" content?)
racket/list
file/convertible ;; attached into new namespace via anchor
racket/pretty ;; attached into new namespace via anchor
@ -110,6 +111,8 @@
(values (substring word 0 fits) (substring word fits) #f)
(values #f word #f)))))
(struct formatted-result (content))
(define (interleave inset? title expr-paras val-list+outputs)
(let ([lines
(let loop ([expr-paras expr-paras]
@ -139,9 +142,11 @@
(map (lambda (v)
(list.flow.list
(make-paragraph
(list (elem #:style result-color
(to-element/no-color
v #:expr? (print-as-expression)))))))
(list (if (formatted-result? v)
(formatted-result-content v)
(elem #:style result-color
(to-element/no-color
v #:expr? (print-as-expression))))))))
val-list)))])
(loop (cdr expr-paras) (cdr val-list+outputs) #f))))])
(if inset?
@ -162,6 +167,25 @@
(struct nothing-to-eval ())
(struct eval-results (contents out err))
(define (make-eval-results contents out err)
(unless (and (list? contents)
(andmap content? contents))
(raise-type-error 'eval:results "list of content" contents))
(unless (string? out)
(raise-type-error 'eval:results "string" out))
(unless (string? err)
(raise-type-error 'eval:results "string" err))
(eval-results contents out err))
(define (make-eval-result content out err)
(unless (content? content)
(raise-type-error 'eval:result "content" content))
(unless (string? out)
(raise-type-error 'eval:result "string" out))
(unless (string? err)
(raise-type-error 'eval:result "string" err))
(eval-results (list content) out err))
(define (extract-to-evaluate s)
(let loop ([s s] [expect #f])
(syntax-case s (code:line code:comment eval:alts eval:check)
@ -227,10 +251,14 @@
(raise-syntax-error 'eval "example result check failed" s))))
r)
(lambda (str)
(let-values ([(s expect) (extract-to-evaluate str)])
(if (nothing-to-eval? s)
(values (list (list (void)) "" ""))
(do-ev/expect s expect)))))
(if (eval-results? str)
(list (map formatted-result (eval-results-contents str))
(eval-results-out str)
(eval-results-err str))
(let-values ([(s expect) (extract-to-evaluate str)])
(if (nothing-to-eval? s)
(list (list (void)) "" "")
(do-ev/expect s expect))))))
;; Since we evaluate everything in an interaction before we typeset,
;; copy each value to avoid side-effects.
@ -373,12 +401,23 @@
[else s]))))
list)))
;; Quote an expression to be evaluated:
(define-syntax-rule (quote-expr e) 'e)
;; This means that sandbox evaluation always works on sexprs, to get
;; it to work on syntaxes, use this definition:
;; (require syntax/strip-context)
;; (define-syntax-rule (quote-expr e) (strip-context (quote-syntax e)))
;; Quote an expression to be evaluated or wrap as escaped:
(define-syntax quote-expr
(syntax-rules (eval:alts eval:result eval:results)
[(_ (eval:alts e1 e2)) (quote-expr e2)]
[(_ (eval:result e)) (make-eval-result (list e) "" "")]
[(_ (eval:result e out)) (make-eval-result (list e) out "")]
[(_ (eval:result e out err)) (make-eval-result (list e) out err)]
[(_ (eval:results es)) (make-eval-results es "" "")]
[(_ (eval:results es out)) (make-eval-results es out "")]
[(_ (eval:results es out err)) (make-eval-results es out err)]
[(_ e)
;; Using quote means that sandbox evaluation works on
;; sexprs; to get it to work on syntaxes, use
;; (strip-context (quote-syntax e)))
;; while importing
;; (require syntax/strip-context)
'e]))
(define (do-interaction-eval ev e)
(let-values ([(e expect) (extract-to-evaluate e)])

View File

@ -36,17 +36,45 @@ are used as @tech{content}. Otherwise, when the default
@racket[current-print] is in place, result values are typeset using
@racket[to-element/no-color].
Uses of @racket[code:comment] and @racketidfont{code:blank} are
stipped from each @racket[datum] before evaluation.
Certain patterns in @racket[datum] are treated specially:
If a @racket[datum] has the form @racket[(@#,indexed-racket[eval:alts]
#,(svar show-datum) #,(svar eval-datum))], then @svar[show-datum] is
typeset, while @svar[eval-datum] is evaluated.
@itemlist[
If a @racket[datum] has the form
@racket[(@#,indexed-racket[eval:check] #,(svar eval-datum) #,(svar
expect-datum))], then both @svar[eval-datum] and @svar[check-datum]
are evaluated, and an error is raised if they are not @racket[equal?].
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[code:line] _code-datum (@#,racketidfont{code:comment} _comment-datum ...))]
is treated as @racket[_code-datum] for evaluation.}
@item{Other uses of @racketidfont{code:comment} and
@racketidfont{code:blank} are stripped from each @racket[datum]
before evaluation.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:alts] #,(svar show-datum) #,(svar eval-datum))]
is treated as @svar[show-datum] for typesetting and @svar[eval-datum] for evaluation.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:check] #,(svar eval-datum) #,(svar expect-datum))]
is treated like @racket[_eval-datum], but @svar[check-datum] is also
evaluated, and an error is raised if they are not @racket[equal?].}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:result] _content-expr _out-expr _err-expr)]
involves no sandboxed evaluation; instead, the @tech{content} result of @racket[_content-expr] is used as the
typeset form of the result, @racket[_out-expr] is treated as output printed
by the expression, and @racket[_err-expr] is error output printed by the
expression. The @racket[_out-expr] and/or @racket[_err-expr] can be omitted,
in which case they default to empty strings.
Normally, @racketidfont{eval:result}
is used in the second part of an @racketidfont{eval:alts} combination.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:results] _content-list-expr _out-expr _err-expr)]
is treated like an @racketidfont{eval:result} form, except that @racket[_content-list-expr]
should produce a list of @tech{content} for multiple results of evaluation. As
with @racketidfont{eval:result}, @racket[_out-expr] and @racket[_err-expr] are optional.}
]
As an example,

View File

@ -0,0 +1,14 @@
#lang scribble/manual
@(require scribble/eval)
@interaction[
(+ 1 2)
(code:line (+ 1 2) (code:comment "three"))
(eval:alts (+ 1 2) 5)
(eval:result @bold{example})
(eval:alts (+ 1 2) (eval:result @bold{same}))
(eval:alts (+ 1 2) (eval:result @elem{really the same} "Again..."))
(eval:alts (+ 1 2) (eval:result @bold{still the same} "!" "error: too many repeats"))
(eval:alts (+ 1 2) (eval:results (list @racketresult[1] @elem{2} "3") "counting"))
]

View File

@ -0,0 +1,22 @@
> (+ 1 2)
3
> (+ 1 2) ; three
3
> (+ 1 2)
5
> (eval:result (bold "example"))
example
> (+ 1 2)
same
> (+ 1 2)
Again...
really the same
> (+ 1 2)
!
error: too many repeats
still the same
> (+ 1 2)
counting
1
2
3