1 #!/usr/bin/env gsi-script
5 (define shell-prompt "$ ")
6 (define scheme-prompt "> ")
7 (define scheme-prompt1 "1> ")
8 (define scheme-prompt2 "2> ")
9 (define scheme-prompt3 "3> ")
12 (let ((p (open-process "uname")))
13 (let ((name (read-line p)))
17 (define r5rs-standard-procedures '(
55 call-with-current-continuation
220 interaction-environment
222 scheme-report-environment
226 (define (all-symbols)
228 (define (symbol-next x)
237 (apply append (map f (cdr (vector->list (##symbol-table))))))
240 (not (##unbound? (##global-var-ref (##make-global-var x)))))
242 (define (exported-procedure? sym)
243 (and (> (string-length (symbol->string sym)) 2)
244 (and (not (string=? "##" (substring (symbol->string sym) 0 2)))
245 (not (string=? " " (substring (symbol->string sym) 0 1))))
246 (procedure? (##global-var-ref (##make-global-var sym)))))
248 (define (keep keep? lst)
249 (cond ((null? lst) '())
250 ((keep? (car lst)) (cons (car lst) (keep keep? (cdr lst))))
251 (else (keep keep? (cdr lst)))))
253 (define (sort-list l <?)
255 (define (mergesort l)
257 (define (merge l1 l2)
258 (cond ((null? l1) l2)
261 (let ((e1 (car l1)) (e2 (car l2)))
263 (cons e1 (merge (cdr l1) l2))
264 (cons e2 (merge l1 (cdr l2))))))))
267 (if (or (null? l) (null? (cdr l)))
269 (cons (car l) (split (cddr l)))))
271 (if (or (null? l) (null? (cdr l)))
273 (let* ((l1 (mergesort (split l)))
274 (l2 (mergesort (split (cdr l)))))
279 (define (sort-syms lst)
281 (lambda (x y) (string<? (symbol->string x) (symbol->string y)))))
287 (if (and (exported-procedure? sym)
288 (not (memq sym r5rs-standard-procedures)))
290 (sort-syms (all-symbols)))
295 (define exported-procedures
296 (sort-syms (keep exported-procedure? (all-symbols))))
298 (define (extract-deffn lines)
303 (lambda (line) (prefix? "@deffn " line))
304 (lambda (line) (prefix? "@end deffn" line)))))
306 (define (extract-groups lines begin? end?)
307 (let loop1 ((lines lines)
310 (reverse rev-groups))
311 ((begin? (car lines))
312 (let loop2 ((lines (cdr lines))
313 (rev-gr (list (car lines))))
315 (display "*** WARNING: unterminated group\n")
316 (reverse rev-groups))
319 (cons (reverse (cons (car lines) rev-gr))
323 (cons (car lines) rev-gr))))))
325 (loop1 (cdr lines) rev-groups)))))
327 (define (extract-deffn-head deffn-lines)
328 (let loop1 ((lines deffn-lines) (rev-head '()))
329 (cond ((and (not (null? lines))
330 (prefix? "@deffn" (car lines)))
331 (let ((words (split-at-spaces (car lines))))
332 (if (< (length words) 3)
333 (error "ill-formed deffn")
334 (let ((deffn-key (car words))
338 (cons (if (and (string=? a "{special")
339 (string=? b "form}"))
340 (list (string->symbol (cadddr words))
341 (string-append a " " b)
343 (list (string->symbol b)
348 (cons (reverse rev-head)
351 (define (prefix? str1 str2)
354 (define (suffix? str1 str2)
355 (here? str1 str2 (- (string-length str2) (string-length str1))))
357 (define (here? str1 str2 pos)
358 (let ((len1 (string-length str1))
359 (len2 (string-length str2)))
360 (and (<= (+ pos len1) len2)
361 (string=? str1 (substring str2 pos (+ pos len1))))))
363 (define (every? pred? lst)
365 (and (pred? (car lst))
366 (every? pred? (cdr lst)))))
368 (define (any? pred? lst)
369 (and (not (null? lst))
370 (or (pred? (car lst))
371 (any? pred? (cdr lst)))))
373 (define (find pred? lst)
378 (find pred? (cdr lst)))))
380 (define (split-at-spaces str)
381 (with-input-from-string str
383 (read-all (current-input-port)
384 (lambda (p) (read-line p #\space))))))
386 (define (check-missing-procedures doc-lines out)
388 (extract-deffn doc-lines)))
390 (define (procedure-documented? sym)
396 (if (eq? (car head) sym)
408 (if (not (string=? (cadr head) "procedure"))
409 (print "*** WARNING: " sym " is not defined as a procedure\n"))
412 (define (check-documented sym)
413 (if (not (memq sym r5rs-standard-procedures))
414 (if (not (procedure-documented? sym))
415 (let ((name (symbol->string sym)))
419 "@deffn procedure " name "\n"
422 (define (check-that-exported-procedures-are-documented)
423 (for-each check-documented exported-procedures))
425 (check-that-exported-procedures-are-documented)))
427 (define os-name-prefix
428 (string-append "\n" os-name " "))
430 (define (exec inputs)
444 (define (recv-timeout max-wait-after-newline)
446 (define max-wait-before-newline .1)
447 (define max-idle-time .1)
449 (input-port-timeout-set! p max-wait-before-newline)
450 (let loop1 ((rev-output '()))
451 (let ((c (read-char p)))
452 (if (and (char? c) (not (char=? c #\newline)))
455 (input-port-timeout-set! p max-idle-time)
456 (loop1 (cons c rev-output)))
458 (input-port-timeout-set! p max-wait-after-newline)
459 (let loop2 ((rev-output
463 (let ((c (read-char p)))
467 (input-port-timeout-set! p max-idle-time)
468 (loop2 (cons c rev-output)))
474 (display (string-append input-text "\n") p)
476 (let* ((rev-last-output
479 (clean-up (list->string (reverse rev-last-output))))
481 (string-append input-text "\n")))
485 (if (prefix? expect last-output)
486 (substring last-output
487 (string-length expect)
488 (string-length last-output))
493 (display (string-append "PS1=\"" shell-prompt "\"\n") p)
494 (display "export C_INCLUDE_PATH=../include\n" p)
495 (display "export LIBRARY_PATH=../lib\n" p)
500 (set! rev-output (list shell-prompt))
502 (for-each send inputs)
504 (let ((output (reverse rev-output)))
508 (define (parse-info body)
510 (define (parse rev-accum start i cont)
514 (cons (substring body start i)
518 (if (< i (string-length body))
519 (let ((c (string-ref body i)))
520 (cond ((char=? c #\})
521 (cont (reverse (add))
523 ((and (< (+ i 1) (string-length body))
525 (let ((first (string-ref body (+ i 1))))
526 (if (memv first '(#\@ #\{ #\}))
531 (let loop ((j (+ i 2)))
532 (if (and (< j (string-length body))
534 (string-ref body j)))
536 (let ((key (substring body (+ i 1) j)))
537 (if (and (< j (string-length body))
538 (char=? (string-ref body j)
540 (parse (list (string->symbol key))
544 (if (and (< i (string-length body))
553 (error "} expected"))))
554 (error "{ expected"))))))))
556 (parse rev-accum start (+ i 1) cont))))
557 (cont (reverse (add))
564 (if (= i (string-length body))
566 (error "syntax error")))))
568 (define (replace expr replacement)
569 (lambda (str pos cont)
570 (let loop ((i 0) (j pos))
571 (if (< i (string-length expr))
572 (if (and (< j (string-length str))
573 (let ((x (string-ref expr i))
574 (c (string-ref str j)))
575 (cond ((or (char=? x #\*) (char=? x #\?))
576 (error "misplaced * or ?"))
581 (loop (cond ((and (< (+ i 1) (string-length expr))
582 (char=? (string-ref expr (+ i 1)) #\*))
584 ((and (< (+ i 1) (string-length expr))
585 (char=? (string-ref expr (+ i 1)) #\?))
590 (cond ((and (< (+ i 1) (string-length expr))
591 (char=? (string-ref expr (+ i 1)) #\*))
594 ((and (< (+ i 1) (string-length expr))
595 (char=? (string-ref expr (+ i 1)) #\?))
600 (cont str j replacement)))))
602 (define (either2 t1 t2)
603 (lambda (str pos cont)
606 (lambda (str new-pos replacement)
608 (cont str new-pos replacement)
613 (define (either transformers)
614 (if (null? transformers)
615 (lambda (str pos cont)
617 (either2 (car transformers)
618 (either (cdr transformers)))))
620 (define (transform str transformer)
621 (let loop ((i 0) (j 0) (rev-result '()))
622 (if (< j (string-length str))
626 (lambda (str new-pos replacement)
632 (cons (substring str i j)
642 (cons (substring str i j) rev-result)
645 (define (clean-up str)
649 (list (replace "gsi(##*) malloc:" "gsi(29744) malloc:")
650 (replace "\33[#*A" "")
651 (replace "\33[#*A" "")
652 (replace "\33[#*B" "")
653 (replace "\33[#*C" "")
654 (replace "\33[#*D" "")
655 (replace "\33[46m" "")
656 (replace "\33[1m" "")
657 (replace "\33[m" "")))))
659 (define (plain-text tree)
660 (cond ((string? tree)
664 (map plain-text (cdr tree))))
666 (error "unknown info tree node"))))
668 (define (display-info tree)
669 (cond ((string? tree)
671 (if (< i (string-length tree))
672 (let ((c (string-ref tree i)))
673 (cond ((char=? c #\@)
686 (for-each display-info (cdr tree))
689 (error "unknown info tree node"))))
691 (define (remove-trailing-prompt str)
693 (define (remove prompt)
694 (if (suffix? prompt str)
697 (- (string-length str) (string-length prompt)))
700 (or (remove scheme-prompt1)
701 (remove scheme-prompt2)
702 (remove scheme-prompt3)
703 (remove scheme-prompt)
704 (remove shell-prompt)
707 (define (check-example info)
712 (cond ((equal? (car tree) shell-prompt)
714 ((equal? (car tree) scheme-prompt)
716 ((and (pair? (car tree))
717 (equal? (car (car tree)) 'b))
722 (or (not (eq? type 'shell))
723 (not (pair? (cdr tree)))
724 (not (equal? (cadr tree) '(b "uname -srmp")))
725 (not (pair? (cddr tree)))
726 (not (string? (caddr tree)))
727 (prefix? os-name-prefix (caddr tree)))))
729 (memq type '(shell scheme)))
731 (keep (lambda (x) (and (pair? x) (eq? (car x) 'b))) tree))
733 (if (eq? type 'scheme)
734 (append '("gsi -:h4000") raw-inputs)
739 (if (eq? type 'scheme)
740 (cons scheme-prompt (cdddr raw-output))
743 (remove-trailing-prompt
744 (with-output-to-string
747 (for-each display-info output))))))
749 ((eq? type 'no-execute)
752 (display "---------------------------------- WARNING, example skipped:\n")
756 (define (check-doc filename)
758 (with-input-from-file
761 (read-all (current-input-port) read-line)))))
764 (string-append s "\n"))
766 (let* ((out (open-output-file (string-append filename "-correct"))))
767 (let loop1 ((lines doc-lines))
769 (close-output-port out)
770 (let ((x (car lines)))
775 (string-append "@end "
776 (substring x 1 (string-length x)))))
777 (let loop2 ((lines (cdr lines)) (lst '()))
778 (let ((y (car lines)))
782 (map addnl (reverse lst))))
784 (check-example info)))
787 (display correct-example out)
791 (loop2 (cdr lines) (cons y lst)))))))
795 (if (equal? x "The procedures in this section are not yet documented.")
796 (check-missing-procedures doc-lines out))
797 (loop1 (cdr lines))))))))))
799 (check-doc "gambit-c.txi")