scribble/bnf: Add contracts & correct docs

This commit is contained in:
Philip McGrath 2018-04-15 05:27:17 -05:00 committed by Matthew Flatt
parent 58b270adba
commit a2d2f0472f
2 changed files with 77 additions and 36 deletions

View File

@ -1,6 +1,7 @@
#lang scribble/doc
@(require scribble/manual "utils.rkt" scribble/bnf
(for-label scribble/bnf))
;; "utils.rkt" provides scribble/bnf for-label
)
@title[#:tag "bnf"]{BNF Grammars}
@ -43,44 +44,48 @@ produces the output
See also @racket[racketgrammar].
@defproc[(BNF [prod (cons element? (listof (or/c block? element?)))] ...) table?]{
@defproc[(BNF [prod (cons/c (or/c block? content?)
(non-empty-listof (or/c block? content?)))]
...)
table?]{
Typesets a grammar table. Each production starts with an element
(typically constructed with @racket[nonterm]) for the non-terminal
being defined, and then a list of possibilities (typically constructed
with @racket[BNF-seq], etc.) to show on separate lines.}
@defproc[(nonterm (pre-content any/c) ...) element?]{
@defproc[(nonterm [pre-content pre-content?] ...) element?]{
Typesets a non-terminal: italic in angle brackets.}
@defproc[(BNF-seq [elem element?] ...) element?]{
@defproc[(BNF-seq [elem content?] ...) (or/c element? "")]{
Typesets a sequence.}
@defproc[(BNF-seq-lines [elems (listof element?)] ...) block?]{
@defproc[(BNF-seq-lines [elems (listof content?)] ...) block?]{
Typesets a sequence that is broken into multiple lines, where each
@racket[elems] is one line.}
@defproc[(BNF-group [pre-content any/c] ...) element?]{
@defproc[(BNF-group [pre-content pre-content?] ...) element?]{
Typesets a group surrounded by curly braces (so the entire group can
be repeated, for example).}
@defproc[(optional [pre-content any/c] ...) element?]{
@defproc[(optional [pre-content pre-content?] ...) element?]{
Typesets an optional element: in square brackets.}
@defproc[(kleenestar [pre-content any/c] ...) element?]{
@defproc[(kleenestar [pre-content pre-content?] ...) element?]{
Typesets a 0-or-more repetition.}
@defproc[(kleeneplus [pre-content any/c] ...) element?]{
@defproc[(kleeneplus [pre-content pre-content?] ...) element?]{
Typesets a 1-or-more repetition.}
@defproc[(kleenerange [n any/c] [m any/c] [pre-content any/c] ...) element?]{
@defproc[(kleenerange [n any/c] [m any/c] [pre-content pre-content?] ...)
element?]{
Typesets a @racket[n]-to-@racket[m] repetition. The @racket[n] and
@racket[m] arguments are converted to a string using @racket[(format
@ -92,6 +97,14 @@ Typesets alternatives for a production's right-hand side to appear on
a single line. The result is normally used as a single possibility in
a production list for @racket[BNF].}
@defthing[BNF-etc string?]{
@; BNF-alt/close is exported but undocumented.
@; It looks like it produces a more densely packed version of
@; BNF-alt, but I haven't confirmed this.
@defthing[BNF-etc element?]{
An element to use for omitted productions or content.
Renders as: @BNF-etc
}
A string to use for omitted productions or content.}

View File

@ -1,19 +1,45 @@
(module bnf racket
(require "struct.rkt"
"decode.rkt"
(only-in "core.rkt"
(require scribble/decode
(except-in scribble/struct
element?)
(only-in scribble/core
content?
element?
make-style
make-table-columns)
mzlib/kw)
(provide BNF
nonterm
BNF-seq BNF-seq-lines
BNF-alt BNF-alt/close ; single-line alternatives
BNF-etc
BNF-group
optional kleenestar kleeneplus kleenerange)
)
(provide (contract-out
[BNF (-> (cons/c (or/c block? content?)
(non-empty-listof (or/c block? content?)))
...
table?)]
[BNF-etc element?]
;; operate on content
[BNF-seq (-> content? ...
(or/c element? ""))]
[BNF-seq-lines (-> (listof content?) ...
block?)]
[BNF-alt (-> content? ...
element?)]
[BNF-alt/close (-> content? ...
element?)]
;; operate on pre-content
[BNF-group (-> pre-content? ...
element?)]
[nonterm (-> pre-content? ...
element?)]
[optional (-> pre-content? ...
element?)]
[kleenestar (-> pre-content? ...
element?)]
[kleeneplus (-> pre-content? ...
element?)]
[kleenerange (-> any/c any/c pre-content? ...
element?)]
))
(define spacer (make-element 'hspace (list " ")))
(define equals (make-element 'tt (list spacer "::=" spacer)))
(define alt (make-element 'tt (list spacer spacer "|" spacer spacer)))
@ -33,14 +59,16 @@
(list baseline baseline baseline baseline))))
(apply
append
(map (lambda (defn)
(cons
(list (as-flow spacer) (as-flow (car defn)) (as-flow equals) (as-flow (cadr defn)))
(map (lambda (i)
(list (as-flow spacer) (as-flow " ") (as-flow alt) (as-flow i)))
(cddr defn))))
(map (match-lambda
[(cons lhs (cons rhs0 more-rhs))
(cons
(list (as-flow spacer) (as-flow lhs) (as-flow equals) (as-flow rhs0))
(map (lambda (i)
(list (as-flow spacer) (as-flow " ") (as-flow alt) (as-flow i)))
more-rhs))])
defns))))
;; interleave : (listof content?) element? -> element?
(define (interleave l spacer)
(make-element #f (cons (car l)
(apply append
@ -65,28 +93,28 @@
(define BNF-etc (make-element 'roman "..."))
(define/kw (nonterm #:body s)
(define (nonterm . s)
(make-element 'roman (append (list 'lang)
(list (make-element 'italic (decode-content s)))
(list 'rang))))
(define/kw (optional #:body s)
(define (optional . s)
(make-element #f (append (list (make-element 'roman "["))
(decode-content s)
(list (make-element 'roman "]")))))
(define/kw (BNF-group #:body s)
(define (BNF-group . s)
(make-element #f (append (list (make-element 'roman "{"))
(list (apply BNF-seq (decode-content s)))
(list (make-element 'roman "}")))))
(define/kw (kleenestar #:body s)
(define (kleenestar . s)
(make-element #f (append (decode-content s) (list (make-element 'roman "*")))))
(define/kw (kleeneplus #:body s)
(define (kleeneplus . s)
(make-element #f (append (decode-content s) (list (make-element 'superscript (list "+"))))))
(define/kw (kleenerange a b #:body s)
(define (kleenerange a b . s)
(make-element #f (append (decode-content s)
(list (make-element 'roman
(make-element 'superscript