home *** CD-ROM | disk | FTP | other *** search
- ;; pretty-printer by mf
- ;*************************************************************
- (define *pp:port* #t) ; default value = current output
- (define *pp:lgth* 80) ; default value = max length of a line
-
- (define (pp obj . options)
- ; obj = file name in a string or
- ; expression to be pretty printed
- ; options = toutes facultatives
- ; destination = file name in a string
- ; #t ==> current output (default value)
- ; #f ==> a string
- ; line-length = integer >= 0 = max length of a line on output
- ; (default value = 80)
- (let ((dest 'output))
- (set! *pp:port* #t)
- (set! *pp:lgth* 80)
- (let loop ((L options))
- (when (not (null? L))
- ; there is options....
- (cond ((string? (car L)) ; output in a file
- (set! *pp:port* (open-output-file (car L)))
- (set! dest 'file))
- ((integer? (car L))
- (set! *pp:lgth* (car L)))
- ((boolean? (car L)) ; current output or a string
- (when (not (car L))
- (set! *pp:port* (open-output-string))
- (set! dest 'string))))
- (loop (cdr L))))
-
- (if (string? obj) ; file name
- (let* ((p (open-input-file obj))
- (to-pp (read p)))
- (while (not (eof-object? to-pp))
- (*pp:pp-one-exp* to-pp)
- (format *pp:port* "~%")
- (set! to-pp (read p))))
- (*pp:pp-one-exp* obj))
- (cond ((eq? dest 'file) (close-output-port *pp:port*))
- ((eq? dest 'string) (get-output-string *pp:port*)))))
-
- ;*************************************************************
- ; pretty-print an expression
- ;*************************************************************
-
- (define *pp:cur-pos* 0) ; current position in line
-
- (define *pp:line* 1) ; current line
-
- (define *pp:lgth-symb* 0) ; lgth of symb to write
-
- (define *printer-list* '(()))
-
- (define *pp:last-symb-is-new-line* #t)
-
- (define *pp:to-substitute* #t)
-
- (define *pp:last* 0) ; for *pp:fit?*
-
- (define (*pp:pp-one-exp* expr)
- (set! *pp:cur-pos* 0) ; current position in line
- (set! *pp:line* 1) ; current line
- (set! *pp:lgth-symb* 0) ; lgth of symb to write
- (set! *pp:last-symb-is-new-line* #t)
- (set! *pp:to-substitute* #t)
- (set! *pp:last* 0) ; for *pp:fit?*
- (let ((expr (if (procedure? expr) (procedure-body expr)
- expr)))
- (*pp:print-expr* expr *pp:cur-pos*)
- (format *pp:port* "~%")
- #t))
-
-
- (define (*pp:out-char* c) ; output the char c NOT at end of line
- ; c = left parenthesis|quote|quasiquote|unquote|unquote-splicing
- (format *pp:port* "~A" c)
- (set! *pp:last-symb-is-new-line* #t)
- (set! *pp:cur-pos* (+ *pp:cur-pos* 1)))
-
- (define (*pp:left-par*) ; output a left parenthesis
- (*pp:out-char* #\( ))
-
- (define (*pp:out-char-eol* c) ; output the char c perhaps at end of line
- ; c = right parenthesis|space|period
- (format *pp:port* "~A" c)
- (set! *pp:last-symb-is-new-line* #f)
- (set! *pp:cur-pos* (+ *pp:cur-pos* 1)))
-
- (define (*pp:right-par*) ; output a right parenthesis
- (*pp:out-char-eol* #\)))
-
- (define (*pp:space*) ; output a space
- (*pp:out-char-eol* #\space))
-
- (define (*pp:period*) ; output " . "
- (*pp:space*)
- (*pp:out-char-eol* #\.)
- (*pp:space*))
-
- (define (*pp:output-symb* symb) ; output the symbol symb
- (format *pp:port* "~S" symb)
- (set! *pp:last-symb-is-new-line* #f)
- (set! *pp:cur-pos* (+ *pp:cur-pos* *pp:lgth-symb*)))
-
-
- (define (*pp:newline-indent* x) ; output a newline and x spaces
- (when (not *pp:last-symb-is-new-line*)
- (format *pp:port* "~%")
- (cond ((<= x 0) #t)
- ((>= x *pp:lgth*) (set! x 0))
- (else
- (format *pp:port* "~A" (make-string x #\space))))
- (set! *pp:last-symb-is-new-line* #t)
- (set! *pp:line* (+ *pp:line* 1))
- (set! *pp:cur-pos* x)))
-
-
- ; #t if expr will fit between *pp:last* and *pp:lgth*
- (define (*pp:fit?* expr)
-
- (define (inc-pos? val)
- (if (<= (+ *pp:last* val) *pp:lgth*)
- (begin (set! *pp:last* (+ *pp:last* val)) #t)
- #f))
-
- (cond ((keyword? expr)
- (set! *pp:lgth-symb* (string-length (keyword->string expr)))
- (inc-pos? *pp:lgth-symb*))
- ((symbol? expr)
- (set! *pp:lgth-symb* (string-length (symbol->string expr)))
- (inc-pos? *pp:lgth-symb*))
- ((string? expr) ; don't forget " "
- (set! *pp:lgth-symb* (+ 2 (string-length expr)))
- (inc-pos? *pp:lgth-symb*))
- ((boolean? expr) ; #t or #f
- (set! *pp:lgth-symb* 2)
- (inc-pos? *pp:lgth-symb*))
- ((number? expr)
- (set! *pp:lgth-symb* (string-length (number->string expr)))
- (inc-pos? *pp:lgth-symb*))
- ((eof-object? expr) (inc-pos? 5)) ;??????????????????
- ((char? expr) ; #\...
- (inc-pos? (case expr
- (#\null 6)
- (#\bell 6)
- (#\space 7)
- (#\delete 8)
- (#\backspace 11)
- (#\tab 5)
- (#\newline 9)
- (#\page 6)
- (#\return 8)
- (#\escape 8)
- (else 3))))
- ((pair? expr) ; ( a b ...)
- (let ((head (car expr))
- (tail (cdr expr))
- (subst (*pp:abbrev* expr)))
- (cond (subst ; to substitute
- (set! *pp:lgth-symb*
- (if (or (eq? subst 'unquote-splicing)
- (eq? subst 'quote-unquote))
- 2
- 1))
- (and (inc-pos? *pp:lgth-symb*)
- (*pp:fit?* tail)))
- ((null? tail) ; (a)
- (and (inc-pos? 2) (*pp:fit?* head)))
- ((and (pair? tail)
- (null? (cdr tail))) ; (a b)
- (and (inc-pos? 1) (*pp:fit?* head) (*pp:fit?* tail)))
- (else ; (a b ...)
- (and (inc-pos? 2) (*pp:fit?* head) (*pp:fit?* tail))))))
- ((vector? expr)
- (letrec ((vlen (- (vector-length expr) 1))
- (vloop
- (lambda (n)
- (if (< n vlen)
- (and (inc-pos? 1)
- (*pp:fit?* (vector-ref expr n))
- (vloop (+ n 1)))
- (and (inc-pos? 1)
- (*pp:fit?* (vector-ref expr vlen)))))))
- (and (inc-pos? 2) (vloop 0))))
- (else ; null list
- #t)))
-
- ;******************************************************************
- ; output an expression
- ;******************************************************************
- (define (*pp:print-expr* expr pos)
- (let ((special
- (if (and *pp:to-substitute* (pair? expr))
- (assoc (car expr) *printer-list*)
- #f)))
- (if (pair? special)
- ((cdr special) expr pos)
- (begin (set! *pp:last* *pp:cur-pos*)
- (if (not (*pp:fit?* expr))
- (*pp:newline-indent* pos))
- (cond ((vector? expr) (*pp:print-vector* expr pos))
- ((not (pair? expr))
- ; *pp:lgth-symb* = lgth of the last symb
- (*pp:output-symb* expr))
- ((and (not (pair? (car expr)))
- (list? expr)) ; (operator args)
- (*pp:print-op* expr pos))
- (else (*pp:print-list* expr pos)))))))
-
- ;******************************************************************
- ; output a vector
- ;******************************************************************
- (define (*pp:print-vector* vect pos)
- (*pp:out-char* "#")
- ; en attendant de pouvoir mettre :
- ; (*pp:out-char* #\#)
- (*pp:left-par*)
- (let ((vect-lgth (- (vector-length vect) 1))
- (n 0))
- (set! pos (+ pos 2))
- (*pp:print-expr* (vector-ref vect n) pos) ; first element
- (while (< n vect-lgth)
- (*pp:space*)
- (set! n (+ n 1))
- (*pp:print-expr* (vector-ref vect n) pos)))
- (*pp:right-par*))
-
- ;******************************************************************
- ; output (operator args)
- ;******************************************************************
- (define (*pp:print-op* expr pos)
- (*pp:left-par*)
- (*pp:print-expr* (car expr) (+ pos 1))
- (let ((first-line *pp:line*))
- (unless (null? (cdr expr))
- (set! *pp:last* *pp:cur-pos*)
- (if (or (and (pair? (cadr expr)) (not (*pp:fit?* (caadr expr))))
- (and (not (pair? (cadr expr)))
- (not (*pp:fit?* (cadr expr)))))
- (*pp:newline-indent* (+ pos 1))
- (*pp:space*))
-
- (set! pos *pp:cur-pos*)
- (set! *pp:last-symb-is-new-line* #t)
- (*pp:print-expr* (cadr expr) pos) ; 1st arg on the same line
- (for-each (lambda (arg)
- (set! *pp:last* *pp:cur-pos*)
- ; (if (or (not (*pp:fit?* arg)) (< first-line *pp:line*))
- (if (not (*pp:fit?* arg))
- (*pp:newline-indent* pos)
- (*pp:space*))
- (*pp:print-expr* arg pos))
- (cddr expr))))
- (*pp:right-par*))
-
- ;******************************************************************
- ; output (if cond then else)
- ;******************************************************************
- (define (*pp:print-if* expr pos)
- (let ((on-new-line #f) (first-line *pp:line*))
- (*pp:left-par*)
- (*pp:print-expr* (car expr) pos) ; if
- (*pp:space*)
- (set! pos *pp:cur-pos*)
- (set! *pp:last-symb-is-new-line* #t) ; to stay on the same line
- (*pp:print-expr* (cadr expr) pos) ; cond
- (set! *pp:last* *pp:cur-pos*)
- (set! on-new-line (or (not (*pp:fit?* (cddr expr))) ; (then else)
- (< first-line *pp:line*)))
- (if on-new-line (*pp:newline-indent* pos) (*pp:space*))
- (*pp:print-expr* (caddr expr) pos) ; then
- (when (not (null? (cdddr expr)))
- (if on-new-line (*pp:newline-indent* pos) (*pp:space*))
- (*pp:print-expr* (cadddr expr) pos))
- (*pp:right-par*)))
-
- ;******************************************************************
- ; output clause
- ;******************************************************************
- (define (*pp:print-clause* clause pos)
- (*pp:left-par*)
- (unless (null? clause)
- (*pp:print-expr* (car clause) pos)
- (set! *pp:last* *pp:cur-pos*)
- (if (not (*pp:fit?* (cdr clause)))
- (*pp:newline-indent* pos)
- (*pp:space*))
- (set! clause (cdr clause))
- (while (not (null? clause))
- (*pp:print-expr* (car clause) pos)
- (unless (null? (cdr clause))
- (set! *pp:last* *pp:cur-pos*)
- (if (not (*pp:fit?* (cadr clause)))
- (*pp:newline-indent* pos)
- (*pp:space*)))
- (set! clause (cdr clause))))
- (*pp:right-par*))
-
- ;******************************************************************
- ; output (cond clauses)
- ;******************************************************************
- (define (*pp:print-cond* expr pos)
- (*pp:left-par*)
- (*pp:print-expr* (car expr) (+ pos 1)) ; output "cond"
- (*pp:space*)
- (set! pos (+ pos 6))
- (*pp:print-clause* (cadr expr) (+ pos 1)) ; the first clause
- (for-each (lambda (clause)
- (*pp:newline-indent* pos)
- (*pp:print-clause* clause (+ pos 1)))
- (cddr expr))
- (*pp:right-par*))
-
- ;******************************************************************
- ; output (case clauses)
- ;******************************************************************
- (define (*pp:print-case* expr pos)
- (*pp:left-par*)
- (*pp:print-expr* (car expr) (+ pos 1))
- (*pp:space*)
- (set! pos (+ pos 2))
- (*pp:print-expr* (cadr expr) pos)
- (for-each (lambda (clause)
- (*pp:newline-indent* pos)
- (*pp:print-clause* clause pos))
- (cddr expr))
- (*pp:right-par*))
-
- ;******************************************************************
- ; output (do inits exit body)
- ;******************************************************************
- (define (*pp:print-do* expr pos)
- (*pp:left-par*)
- (*pp:print-expr* (car expr) (+ pos 1)) ; do
- (*pp:space*)
- (let ((inits (cadr expr))
- (exit (caddr expr))
- (body (cdddr expr))
- (pos-ie (+ pos 4))
- (pos-body (+ pos 2)))
- (*pp:print-clause* inits pos-ie)
- (*pp:newline-indent* pos-ie)
- (*pp:print-clause* exit pos-ie)
- (for-each (lambda (expr)
- (*pp:newline-indent* pos-body)
- (*pp:print-expr* expr pos-body))
- body))
- (*pp:right-par*))
-
- ;******************************************************************
- ; output (let|let*|letrec|let-syntax|letrec-syntax bindings body)
- ;******************************************************************
- (define (*pp:print-let* expr pos)
-
- (define (print-binding bind pos)
- (*pp:left-par*)
- (*pp:print-expr* (car bind) pos)
- (*pp:space*)
- (set! *pp:last-symb-is-new-line* #t) ; to stay on the same line
- (*pp:print-expr* (cadr bind) pos)
- (*pp:right-par*))
-
- (*pp:newline-indent* pos)
- (*pp:left-par*)
- (*pp:print-expr* (car expr) (+ pos 1))
- (*pp:space*)
- (set! pos (+ pos 2))
- (let ((pos-bind (+ pos *pp:lgth-symb* 1))
- (bindings (cadr expr))
- (body (cddr expr)))
- (if (symbol? bindings) ; named let
- (begin (*pp:print-expr* bindings pos-bind)
- (*pp:space*)
- (set! pos-bind (+ pos-bind *pp:lgth-symb* 1))
- (set! bindings (caddr expr))
- (set! body (cdr body))))
- (*pp:left-par*)
- (when (not (null? bindings))
- (print-binding (car bindings) pos-bind) ; the first binding
- (for-each (lambda (clause)
- (*pp:newline-indent* pos-bind)
- (print-binding clause pos-bind))
- (cdr bindings)))
- (*pp:right-par*)
- (for-each (lambda (expr)
- (*pp:newline-indent* pos)
- (*pp:print-expr* expr pos))
- body))
- (*pp:right-par*))
-
- ;******************************************************************
- ; output (define|define-macro|extend-syntax|when|unless|while arg body)
- ; on a new line
- ;******************************************************************
- (define (*pp:print-sform* expr pos)
- (*pp:newline-indent* pos)
- (*pp:left-par*)
- (*pp:print-expr* (car expr) (+ pos 1))
- (*pp:space*)
- (set! pos (+ pos 2))
- (set! *pp:last* *pp:cur-pos*)
- (if (not (*pp:fit?* (cadr expr))) (*pp:newline-indent* pos))
- (*pp:print-expr* (cadr expr) pos)
- (let ((next-on-new-line (pair? (cadr expr))))
- (for-each (lambda (arg)
- (set! *pp:last* *pp:cur-pos*)
- (if (or next-on-new-line (not (*pp:fit?* arg)))
- (*pp:newline-indent* pos)
- (*pp:space*))
- (*pp:print-expr* arg pos))
- (cddr expr)))
- (*pp:right-par*))
-
- ;******************************************************************
- ; output (lambda arg body)
- ;******************************************************************
- (define (*pp:print-lambda* expr pos)
- (let ((next-line #f))
- (*pp:left-par*)
- (*pp:print-expr* (car expr) (+ pos 1))
- (*pp:space*)
- (set! pos (+ pos 2))
- (set! *pp:last* *pp:cur-pos*)
- (unless (*pp:fit?* (cadr expr))
- (set! next-line #t)
- (*pp:newline-indent* pos))
- (*pp:print-expr* (cadr expr) pos)
- (set! next-line (or next-line (not (*pp:fit?* (cddr expr)))))
- (for-each (lambda (arg)
- (if next-line (*pp:newline-indent* pos))
- (*pp:print-expr* arg pos))
- (cddr expr))
- (*pp:right-par*)))
-
- ;******************************************************************
- ; check for substitution of quote, quasiquote, unquote, unquote-splicing
- ; general rules :
- ; After a quote, symbols don't have to be substitued except for unquote
- ;******************************************************************
- (define (*pp:abbrev* expr)
- (if (and *pp:to-substitute* (pair? expr))
- (cond ((and (pair? (cdr expr))
- (null? (cddr expr))
- (eq? (car expr) 'quote)) ; (quote x)
- (if (and (pair? (cadr expr))
- (eq? (caadr expr) 'unquote))
- 'quote-unquote
- 'quote))
- (else
- (if (memq (car expr)
- '(quasiquote unquote unquote-splicing))
- (car expr)
- #f)))
- #f))
-
- ;******************************************************************
- ; output (quote arg) ==> 'arg
- ; (quote ( arg1 arg2 ...)) ==> '(arg1 ag2 ...)
- ; (quote (unquote arg)) ==> ',arg
- ; (quote (unquote arg1 arg2 ...)) ==> ',(arg1 arg2 ...)
- ; (quasiquote arg) ==> `arg
- ; (quasiquote (arg1 arg2 ...)) ==> `(arg1 arg2 ...)
- ; (unquote arg) ==> , arg
- ; (unquote (arg1 arg2 ...)) ==> ,(arg1 arg2 ...)
- ; (unquote-splicing arg) ==> ,@ arg
- ; (unquote-splicing (arg1 arg2 ...)) ==> ,@(arg1 arg2 ...)
- ;******************************************************************
- (define (*pp:print-quote* expr pos)
- (let ((which (*pp:abbrev* expr)))
- (cond ((not which)
- (set! *pp:to-substitute* #f)
- (*pp:print-expr* expr pos)
- (set! *pp:to-substitute* #t))
- ((eq? which 'quote)
- (set! *pp:to-substitute* #f)
- (set! *pp:last* (+ *pp:cur-pos* 1))
- (if (not (*pp:fit?* (cdr expr))) (*pp:newline-indent* pos))
- (*pp:out-char* #\')
- (*pp:print-expr* (cadr expr) (+ pos 1))
- (set! *pp:to-substitute* #t))
- ((eq? which 'quote-unquote)
- (*pp:out-char* #\') (*pp:out-char* #\,)
- (*pp:print-expr* (car (cdadr expr)) (+ pos 2)))
- (else
- (case which
- (quasiquote (*pp:out-char* #\`))
- (unquote (*pp:out-char* #\,))
- (unquote-splicing (*pp:out-char* #\,) (*pp:out-char* #\@)))
- (*pp:print-expr* (cadr expr)
- (+ pos (if (eq? which 'unquote-splicing)
- 2
- 1)))))))
-
- ;******************************************************************
- ; output (call/cc|call-with-current-continuation body)
- ;******************************************************************
- (define (*pp:print-sform0* expr pos)
- (*pp:left-par*)
- (*pp:print-expr* (car expr) pos)
- (set! pos (+ pos 2))
- (for-each (lambda (arg)
- (*pp:newline-indent* pos)
- (*pp:print-expr* arg pos))
- (cdr expr))
- (*pp:right-par*))
-
-
- ;******************************************************************
- ; output a list
- ;******************************************************************
- (define (*pp:print-list* lst pos)
- (*pp:left-par*)
- (set! pos (+ pos 1))
- (*pp:print-expr* (car lst) pos) ; 1st element
- (let ((last #f) (lst (cdr lst)))
- (while (and (not (null? lst)) (not last))
- (cond ((not (pair? lst))
- (*pp:period*)
- (*pp:print-expr* lst pos)
- (set! last #t))
- (else
- (*pp:space*)
- (*pp:print-expr* (car lst) pos)))
- (if (not last) (set! lst (cdr lst)))))
- (*pp:right-par*))
-
- ;******************************************************************
- ; define special forms
- ;******************************************************************
-
- (define (printer-add form printer) ; add special pretty printers
- (set! *printer-list*
- (cons '()
- (cons (cons form printer)
- (cdr *printer-list*)))))
-
- (printer-add 'quote *pp:print-quote*)
- (printer-add 'quasiquote *pp:print-quote*)
- (printer-add 'unquote *pp:print-quote*)
- (printer-add 'unquote-splicing *pp:print-quote*)
-
- (printer-add 'lambda *pp:print-lambda*)
-
- (printer-add 'define *pp:print-sform*)
- (printer-add 'define-macro *pp:print-sform*)
- (printer-add 'extend-syntax *pp:print-sform*)
- (printer-add 'when *pp:print-sform*)
- (printer-add 'unless *pp:print-sform*)
- (printer-add 'while *pp:print-sform*)
-
- (printer-add 'let *pp:print-let*)
- (printer-add 'letrec *pp:print-let*)
- (printer-add 'let* *pp:print-let*)
- (printer-add 'let-syntax *pp:print-let*)
- (printer-add 'letrec-syntax *pp:print-let*)
-
- (printer-add 'do *pp:print-do*)
-
- (printer-add 'if *pp:print-if*)
-
- (printer-add 'cond *pp:print-cond*)
-
- (printer-add 'case *pp:print-case*)
- (printer-add 'record-case *pp:print-case*)
-
- (printer-add 'call-with-current-continuation *pp:print-sform0*)
- (printer-add 'call/cc *pp:print-sform0*)
-