|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 14168 (0x3758) Types: TextFile Names: »pp.scm.175«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/gnu-31mar87/scheme/scm/pp.scm.175«
;;; -*-Scheme-*- ;;; ;;; Copyright (c) 1984 Massachusetts Institute of Technology ;;; ;;; This material was developed by the Scheme project at the ;;; Massachusetts Institute of Technology, Department of ;;; Electrical Engineering and Computer Science. Permission to ;;; copy this software, to redistribute it, and to use it for any ;;; purpose is granted, subject to the following restrictions and ;;; understandings. ;;; ;;; 1. Any copy made of this software must include this copyright ;;; notice in full. ;;; ;;; 2. Users of this software agree to make their best efforts (a) ;;; to return to the MIT Scheme project any improvements or ;;; extensions that they make, so that these may be included in ;;; future releases; and (b) to inform MIT of noteworthy uses of ;;; this software. ;;; ;;; 3. All materials developed as a consequence of the use of ;;; this software shall duly acknowledge such use, in accordance ;;; with the usual standards of acknowledging credit in academic ;;; research. ;;; ;;; 4. MIT has made no warrantee or representation that the ;;; operation of this software will be error-free, and MIT is ;;; under no obligation to provide any services, by way of ;;; maintenance, update, or otherwise. ;;; ;;; 5. In conjunction with products arising from the use of this ;;; material, there shall be no use of the name of the ;;; Massachusetts Institute of Technology nor of any adaptation ;;; thereof in any advertising, promotional, or sales literature ;;; without prior written consent from MIT in each case. ;;; ;;;; Pretty Printer (declare (usual-integrations) (compilable-primitive-functions (list-node? pair?) (list-node-size car) (node-subnodes cdr))) (define scheme-pretty-printer (make-package scheme-pretty-printer ((next-coords) (add-sc-entry!) (sc-relink!)) (define open #/() ;)( -- keeps EMACS happy. (define close #/)) \f ;;;; Top Level (define (pp expression as-code?) (let ((node (numerical-walk expression))) (*unparse-character #\CR) ((if as-code? print-node print-non-code-node) node 0 0))) (define (stepper-pp expression stream p-wrapper table nc relink! sc! offset) (fluid-let ((walk-dispatcher table) (next-coords nc) (sc-relink! relink!) (add-sc-entry! sc!) (print-combination (p-wrapper print-combination)) (forced-indentation (p-wrapper forced-indentation)) (pressured-indentation (p-wrapper pressured-indentation)) (print-procedure (p-wrapper print-procedure)) (print-let-expression (p-wrapper print-let-expression)) (print-node (p-wrapper print-node)) (print-guaranteed-node (p-wrapper print-guaranteed-node))) (let ((node (numerical-walk expression))) (with-output-to-stream stream (lambda () (print-node node (car offset) 0)))))) (define (print-non-code-node node column depth) (fluid-let ((dispatch-list '())) (print-node node column depth))) (define (print-node node column depth) (cond ((list-node? node) (print-list-node node column depth)) ((symbol? node) (*unparse-string (symbol-print-name node))) ((prefix-node? node) (*unparse-string (node-prefix node)) (print-node (node-subnode node) (+ (string-size (node-prefix node)) column) depth)) (else (*unparse-string node)))) (define (print-list-node node column depth) (if (fits-within? node column depth) (print-guaranteed-list-node node) (let ((subnodes (node-subnodes node))) ((disjunction (let ((association (assq (car subnodes) dispatch-list))) (conjunction association (cdr association))) print-combination) subnodes column depth)))) (define (print-guaranteed-node node) (cond ((list-node? node) (print-guaranteed-list-node node)) ((symbol? node) (*unparse-string (symbol-print-name node))) ((prefix-node? node) (*unparse-string (node-prefix node)) (print-guaranteed-node (node-subnode node))) (else (*unparse-string node)))) (define (print-symbol node) (*unparse-string (symbol-print-name node))) (define (print-guaranteed-list-node node) (define (loop nodes) (print-guaranteed-node (car nodes)) (if (not (null? (cdr nodes))) (sequence (*unparse-character #\SP) (loop (cdr nodes))))) (*unparse-character open) (loop (node-subnodes node)) (*unparse-character close)) (define (print-column nodes column depth) (define (loop nodes) (if (null? (cdr nodes)) (print-node (car nodes) column depth) (sequence (print-node (car nodes) column 0) (tab-to column) (loop (cdr nodes))))) (loop nodes)) (define (print-guaranteed-column nodes column) (define (loop nodes) (print-guaranteed-node (car nodes)) (if (not (null? (cdr nodes))) (sequence (tab-to column) (loop (cdr nodes))))) (loop nodes)) \f ;;;; Printers (define (print-combination nodes column depth) (*unparse-character open) (let ((column (1+ column)) (depth (1+ depth))) (cond ((null? (cdr nodes)) (print-node (car nodes) column depth)) ((two-on-first-line? nodes column depth) (print-guaranteed-node (car nodes)) (*unparse-character #\SP) (print-guaranteed-column (cdr nodes) (1+ (+ column (node-size (car nodes)))))) (else (print-column nodes column depth)))) (*unparse-character close)) (define ((special-printer procedure) nodes column depth) (*unparse-character open) (print-symbol (car nodes)) (*unparse-character #\SP) (if (not (null? (cdr nodes))) (procedure (cdr nodes) (+ 2 (+ column (string-size (symbol-print-name (car nodes))))) (+ 2 column) (1+ depth))) (*unparse-character close)) ;;; Force the indentation to be an optimistic column. (define forced-indentation (special-printer (lambda (nodes optimistic pessimistic depth) (print-column nodes optimistic depth)))) ;;; Pressure the indentation to be an optimistic column; no matter ;;; what happens, insist on a column, but accept a pessimistic one if ;;; necessary. (define pressured-indentation (special-printer (lambda (nodes optimistic pessimistic depth) (if (fits-as-column? nodes optimistic depth) (print-guaranteed-column nodes optimistic) (sequence (tab-to pessimistic) (print-column nodes pessimistic depth)))))) ;;; Print a procedure definition. The bound variable pattern goes on ;;; the same line as the keyword, while everything else gets indented ;;; pessimistically. We may later want to modify this to make higher ;;; order procedure patterns be printed more carefully. (define print-procedure (special-printer (lambda (nodes optimistic pessimistic depth) (print-node (car nodes) optimistic 0) (tab-to pessimistic) (print-column (cdr nodes) pessimistic depth)))) \f ;;; Print a binding form. There is a great deal of complication here, ;;; some of which is to gracefully handle the case of a badly-formed ;;; binder. But most important is the code that handles the name when ;;; we encounter a named LET; it must go on the same line as the ;;; keyword. In that case, the bindings try to fit on that line or ;;; start on that line if possible; otherwise they line up under the ;;; name. The body, of course, is always indented pessimistically. (define print-let-expression (special-printer (lambda (nodes optimistic pessimistic depth) (define (print-body nodes) (if (not (null? nodes)) (sequence (tab-to pessimistic) (print-column nodes pessimistic depth)))) (cond ((null? (cdr nodes)) ;Screw case. (print-node (car nodes) optimistic depth)) ((symbol? (car nodes)) ;Named LET. (print-symbol (car nodes)) (let ((new-optimistic (1+ (+ optimistic (string-size (symbol-print-name (car nodes))))))) (cond ((fits-within? (cadr nodes) new-optimistic 0) (*unparse-character #\SP) (print-guaranteed-node (cadr nodes)) (print-body (cddr nodes))) ((fits-as-column? (node-subnodes (cadr nodes)) (+ new-optimistic 2) 0) (*unparse-character #\SP) (*unparse-character open) (print-guaranteed-column (node-subnodes (cadr nodes)) (1+ new-optimistic)) (*unparse-character close) (print-body (cddr nodes))) (else (tab-to optimistic) (print-node (cadr nodes) optimistic 0) (print-body (cddr nodes)))))) (else ;Ordinary LET. (print-node (car nodes) optimistic 0) (print-body (cdr nodes))))))) (define dispatch-list `((COND . ,forced-indentation) (IF . ,forced-indentation) (DISJUNCTION . ,pressured-indentation) (CONJUNCTION . ,pressured-indentation) (LET . ,print-let-expression) (FLUID-LET . ,print-let-expression) (DEFINE . ,print-procedure) (LAMBDA . ,print-procedure) (NAMED-LAMBDA . ,print-procedure))) \f ;;;; Alignment (define (fits-within? node column depth) (> (- *printer-width* depth) (+ column (node-size node)))) ;;; Fits if each node fits when stacked vertically at the given column. (define (fits-as-column? nodes column depth) (define (loop nodes) (if (null? (cdr nodes)) (> (- *printer-width* depth) (+ column (node-size (car nodes)))) (conjunction (> *printer-width* (+ column (node-size (car nodes)))) (loop (cdr nodes))))) (loop nodes)) ;;; Fits if first two nodes fit on same line, and rest fit under the ;;; second node. Assumes at least two nodes are given. (define (two-on-first-line? nodes column depth) (let ((column (1+ (+ column (node-size (car nodes)))))) (conjunction (> *printer-width* column) (fits-as-column? (cdr nodes) column depth)))) ;;; Starts a new line with the specified indentation. (define (tab-to column) (*unparse-character #\CR) (*unparse-string (make-filled-string column #\SP))) \f ;;;; Numerical Walk (define (numerical-walk object) ((walk-dispatcher object) object)) (define (walk-general object) (prin1-to-string object)) (define (walk-string string) (string-append """" string """")) (define (walk-primitive primitive) (let ((name (primitive-procedure-name primitive))) (if (pair? name) (car name) name))) (define (walk-pair pair) (if (conjunction (eq? (car pair) 'QUOTE) (pair? (cdr pair)) (null? (cddr pair))) (make-prefix-node "'" (numerical-walk (cadr pair))) (walk-unquoted-pair pair))) (define (walk-unquoted-pair pair) (if (null? (cdr pair)) (make-singleton-list-node (numerical-walk (car pair))) (make-list-node (numerical-walk (car pair)) (if (pair? (cdr pair)) (walk-unquoted-pair (cdr pair)) (make-singleton-list-node (make-prefix-node ". " (numerical-walk (cdr pair)))))))) (define (walk-vector vector) (if (zero? (vector-size vector)) "#()" (make-prefix-node "#" (walk-unquoted-pair (vector->list vector))))) (define walk-dispatcher (make-type-dispatcher `((,symbol-type ,identity-procedure) (,(microcode-type-object 'STRING) ,walk-string) (,primitive-procedure-type ,walk-primitive) (,(microcode-type-object 'PAIR) ,walk-pair) (,(microcode-type-object 'VECTOR) ,walk-vector) (,unparser-special-object-type ,walk-general)) walk-general)) \f ;;;; Node Model ;;; Carefully crafted to use the least amount of memory, while at the ;;; same time being as fast as possible. The only concession to ;;; space was in the implementation of atomic nodes, in which it was ;;; decided that the extra space needed to cache the size of a string ;;; or the print-name of a symbol wasn't worth the speed that would ;;; be gained by keeping it around. (define (symbol-size symbol) (string-size (symbol-print-name symbol))) (define (make-prefix-node prefix subnode) (cond ((disjunction (list-node? subnode) (symbol? subnode)) (vector (+ (string-size prefix) (node-size subnode)) prefix subnode)) ((prefix-node? subnode) (make-prefix-node (string-append prefix (node-prefix subnode)) (node-subnode subnode))) (else (string-append prefix subnode)))) (define prefix-node? vector?) (define prefix-node-size vector-first) (define node-prefix vector-second) (define node-subnode vector-third) (define (make-list-node car-node cdr-node) (cons (1+ (+ (node-size car-node) (list-node-size cdr-node))) ;+1 space. (cons car-node (node-subnodes cdr-node)))) (define (make-singleton-list-node car-node) (cons (+ 2 (node-size car-node)) ;+1 each parenthesis. (list car-node))) (define list-node? pair?) (define list-node-size car) (define node-subnodes cdr) (define (node-size node) ((cond ((list-node? node) list-node-size) ((symbol? node) symbol-size) ((prefix-node? node) prefix-node-size) (else string-size)) node)) \f ;;; end SCHEME-PRETTY-PRINTER package. )) ;;;; Exports (define pp (let () (define (prepare scode) (let ((s-expression (unsyntax scode))) (if (conjunction (pair? s-expression) (eq? (car s-expression) 'NAMED-LAMBDA)) `(DEFINE ,@(cdr s-expression)) s-expression))) (define (bad-arg argument) (error "Bad optional argument" 'PP argument)) (lambda (scode . optionals) (define (kernel as-code?) (if (scode-constant? scode) ((access pp scheme-pretty-printer) scode as-code?) ((access pp scheme-pretty-printer) (prepare scode) #!TRUE))) (cond ((null? optionals) (kernel #!FALSE)) ((null? (cdr optionals)) (cond ((eq? (car optionals) 'AS-CODE) (kernel #!TRUE)) ((output-stream? (car optionals)) (with-output-to-stream (car optionals) (lambda () (kernel #!FALSE)))) (else (bad-arg (car optionals))))) ((null? (cddr optionals)) (cond ((eq? (car optionals) 'AS-CODE) (if (output-stream? (cadr optionals)) (with-output-to-stream (cadr optionals) (lambda () (kernel #!TRUE))) (bad-arg (cadr optionals)))) ((output-stream? (car optionals)) (if (eq? (cadr optionals) 'AS-CODE) (with-output-to-stream (car optionals) (lambda () (kernel #!TRUE))) (bad-arg (cadr optionals)))) (else (bad-arg (car optionals))))) (else (error "Too many optional arguments" 'PP optionals))) *the-non-printing-object*)))