#lang scheme/base (require (for-syntax scheme/base syntax/boundmap) scribble/scheme scribble/decode scribble/manual scribble/struct) (begin-for-syntax ;; maps chunk identifiers to a counter, so we can distinguish multiple uses ;; of the same name (define chunk-numbers (make-free-identifier-mapping)) (define (get-chunk-number id) (free-identifier-mapping-get chunk-numbers id (lambda () #f))) (define (inc-chunk-number id) (free-identifier-mapping-put! chunk-numbers id (+ 1 (free-identifier-mapping-get chunk-numbers id)))) (define (init-chunk-number id) (free-identifier-mapping-put! chunk-numbers id 2))) (define-syntax-rule (define-chunk chunk-id racketblock) (define-syntax (chunk-id stx) (syntax-case stx () [(_ name expr (... ...)) ;; no need for more error checking, using chunk for the code will do that (identifier? #'name) (let* ([n (get-chunk-number (syntax-local-introduce #'name))] [str (symbol->string (syntax-e #'name))] [tag (format "~a:~a" str (or n 1))]) (when n (inc-chunk-number (syntax-local-introduce #'name))) (syntax-local-lift-expression #'(quote-syntax (a-chunk name expr (... ...)))) (with-syntax ([tag tag] [str str] [((for-label-mod (... ...)) (... ...)) (map (lambda (expr) (syntax-case expr (require) [(require mod (... ...)) (let loop ([mods (syntax->list #'(mod (... ...)))]) (cond [(null? mods) null] [else (syntax-case (car mods) (for-syntax) [(for-syntax x (... ...)) (append (loop (syntax->list #'(x (... ...)))) (loop (cdr mods)))] [x (cons #'x (loop (cdr mods)))])]))] [else null])) (syntax->list #'(expr (... ...))))] [(rest (... ...)) (if n #`((subscript #,(format "~a" n))) #`())]) #`(begin (require (for-label for-label-mod (... ...) (... ...))) #,@(if n #'() #'((define-syntax name (make-element-id-transformer (lambda (stx) #'(chunkref name)))) (begin-for-syntax (init-chunk-number #'name)))) (make-splice (list (make-toc-element #f (list (elemtag '(chunk tag) (bold (italic (racket name)) " ::="))) (list (smaller (elemref '(chunk tag) #:underline? #f str rest (... ...))))) (racketblock expr (... ...)))))))]))) (define-chunk chunk racketblock) (define-chunk CHUNK RACKETBLOCK) (define-syntax (chunkref stx) (syntax-case stx () [(_ id) (identifier? #'id) (with-syntax ([tag (format "~a:1" (syntax-e #'id))] [str (format "~a" (syntax-e #'id))]) #'(elemref '(chunk tag) #:underline? #f str))])) (provide (all-from-out scheme/base scribble/manual) chunk CHUNK)