tags 16726 notabug thanks Hi,
Nigel Warner <nwarne...@gmail.com> writes: > This file is an extract of a documentation and code assembly process > which works from a list of elements and attributes. Perhaps I'm > being particularly stupid but I can't see why the function > emit-groff-bug? does not work as expected. In the future, please show us what output the program produced, and what output you expected. There are several mistakes in your program. > (define-syntax say > (syntax-rules () > ((say format-string ...) > (format #t format-string ...)) > ((say format-string) > (format #t format-string)))) The second rule will never be used, because the first rule covers that case. In macros, "x ..." matches zero or more items. > (define-syntax emit > (syntax-rules () > ((emit a-string) > (say (string-append a-string "\n"))) > ((emit a-string ...) > (say (string-append (format #f a-string ...) "\n"))))) This is a bad idea, because you are conflating the format string with the strings you want to output. If the string you want to output includes "~", then it will misbehave. Did you notice the compiler warnings about non-literal format strings? > (define (process-attributes-for-groff lst) > (for-each > (lambda (element) > (emit ".attribute ~a ~a" (list-ref element 0) > (list-ref element 1)) > (emit ".start-hint") > (emit "~a" (list-ref element 2)) > (emit ".end-hint")) > lst)) I suggest that you use the (ice-9 match) module to destructure 'element' into its components. The code will look a lot nicer, and it will also be more efficient. > (define (emit-groff lst) > (for-each > (lambda (element) > (cond ((and (pair? element) > (eq? #:object-name (car element))) > (emit ".object-name ~a" (cdr element))) > ((and (pair? element) > (eq? #:description (car element))) > (emit ".start-description") > (emit "~a" (cdr element)) > (emit ".end-description")) > ((and (list? element) > (eq? #:attributes (car element))) > (process-attributes-for-groff (cdr element))) > (else > (emit "emit-groff | unknown list type") > (throw 'snafu)))) > lst)) > > (define (emit-groff-bug? lst) > (for-each > (lambda (element) > (cond ((pair? element) > (cond ((eq? #:object-name (car element)) > (emit ".object-name ~a" (cdr element))) > ((eq? #:description (car element)) > (emit ".start-description") > (emit "~a" (cdr element)) > (emit ".end-description")))) > ((list? element) > (cond ((eq? #:attributes (car element))) > (process-attributes-for-groff (cdr element))) > (else > (emit "emit-groff | unknown list type") > (throw 'snafu))))) > lst)) There are several mistakes in this procedure: * Every list is also a pair, so the (list? element) case is never taken. The (pair? element) case is taken for the #:attributes, and then no matching case is found in the inner 'cond' there. There are two parenthesis errors: * You have the (process-attributes-for-groff (cdr element)) in a position where its treated as a clause of the inner 'cond', instead of as an expression within the (eq? #:attributes (car element)) case. * You've put the 'else' within the "(list? element)" case, instead of as its own clause. Did you see the compiler warning about "possibly unbound variable `else'"? Mark