git.fiddlerwoaroof.com
printers/util.scm
4e987026
 ;;; util.scm -- utilities for printing AST structures
 ;;;
 ;;; author :  Sandra Loosemore
 ;;; date   :  15 Jan 1992
 ;;;
 ;;;
 
 
 ;;; The AST syntax printers are only used if this variable is true.
 
 (define *print-ast-syntax* '#t)
 
 
 ;;; Here's a macro for defining AST printers.
 
 (define-syntax (define-ast-printer type lambda-list . body)
   (let ((printer  (symbol-append 'write- type)))
     `(begin
        (define (,printer ,@lambda-list) ,@body)
        (define-struct-printer ,type ,printer))
     ))
 
 
 ;;; This variable controls how much indentation to perform on block
 ;;; bodies.
 
 (define *print-ast-indent* 2)
 
 
 ;;; Begin a logical block with the default indentation.
 
 (define-syntax (with-ast-block xp-stuff . body)
   (let ((xp  (car xp-stuff)))
     `(pprint-logical-block (,xp '() "" "")
        (pprint-indent 'block (dynamic *print-ast-indent*) ,xp)
        (pprint-pop)  ; prevents unused variable warning
        ,@body)))
 
 
 ;;; Write a space and maybe a fill line break.
 
 (define (write-whitespace xp)
   (write-char #\space xp)
   (pprint-newline 'fill xp))
 
 
 ;;; Write a space and maybe a mandatory line break.
 
 (define (write-newline xp)
   (write-char #\space xp)
   (pprint-newline 'mandatory xp))
 
 
 
 ;;; Write a list of things separated by delimiters and maybe
 ;;; surrounded by delimiters.
 
 (define (write-delimited-list objects xp fn delim prefix suffix)
   (pprint-logical-block (xp '() prefix suffix)
     (do ((objects objects (cdr objects)))
 	((null? objects) '#f)
 	(pprint-pop)
 	(funcall fn (car objects) xp)
 	(when (cdr objects)
 	  (write-string delim xp)
 	  (write-whitespace xp)))))
 
 
 ;;; Here's a couple common special cases of the above.
 
 (define (write-commaized-list objects xp)
   (write-delimited-list objects xp (function write) "," "(" ")"))
 
 (define (write-ordinary-list objects xp)
   (write-delimited-list objects xp (function write) "" "" ""))
 
 
 ;;; Here's another helper function that's used to implement the layout
 ;;; rule.  The layout rule is only used to format output if *print-pretty*
 ;;; is true.
 ;;; *** should do pprint-indent here?
 
 (define (write-layout-rule objects xp fn)
   (pprint-logical-block (xp '()
 			    (if (dynamic *print-pretty*) "" "{")
 			    (if (dynamic *print-pretty*) "" "}"))
     (do ((objects objects (cdr objects)))
 	((null? objects) '#f)
 	(pprint-pop)
 	(funcall fn (car objects) xp)
 	(when (cdr objects)
 	  (if (dynamic *print-pretty*)
 	      (pprint-newline 'mandatory xp)
 	      (write-string "; " xp))))))
 
 
 ;;; This filters a list of decls, removing the recursive marker added by
 ;;; dependency analysis.
 
 (define (remove-recursive-grouping decls)
   (cond ((null? decls) '())
 	((is-type? 'recursive-decl-group (car decls))
 	 (append (recursive-decl-group-decls (car decls))
 		 (remove-recursive-grouping (cdr decls))))
 	(else
 	 (cons (car decls) (remove-recursive-grouping (cdr decls))))))
 
 ;;; Write where-decls, using the layout rule if appropriate.
 
 (define (write-wheredecls decls xp)
   (when (not (null? decls))
     (write-whitespace xp)
     (write-string "where" xp)
     (write-whitespace xp)
     (write-layout-rule (remove-recursive-grouping decls) xp (function write))))
 
 
 ;;; Write an ordinary variable name.
 
 (define (write-avarid name xp)
   (write-string (symbol->string name) xp))
   
 
 ;;; Constructor name symbols have a funny prefix attached; have to strip
 ;;; this off, so can't just print the symbol using write-avarid.
 
 (define (write-aconid name xp)
   (let ((s  (symbol->string name)))
     (write-string (substring s 1 (string-length s)) xp)))
 
 
 ;;; There are a couple places where conids and varids are mixed up
 ;;; together.
 
 (define (conid? name)
   (eqv? (string-ref (symbol->string name) 0) #\;))
 
 (define (write-varop-conop name xp)
   (if (conid? name)
       (write-conop name xp)
       (write-varop name xp)))
 
 (define (write-varid-conid name xp)
   (if (conid? name)
       (write-conid name xp)
       (write-varid name xp)))
 
 
 
 ;;; Stuff for writing a variable name as either an operator or an ordinary
 ;;; variable ID.  This is necessary because some kinds of symbol names
 ;;; default to being operators and others default to being ordinary names.
 ;;; Bleah....
 
 
 (define (write-varop name xp)
   (if (avarid? name)
       (begin
         (write-char #\` xp)
 	(write-avarid name xp)
 	(write-char #\` xp))
       (write-avarid name xp)))
 
 (define (write-varid name xp)
   (if (avarid? name)
       (write-avarid name xp)
       (begin
         (write-char #\( xp)
 	(write-avarid name xp)
 	(write-char #\) xp))))
 
 
 ;;; This tests for alphabetic rather than lower-case characters
 ;;; so that gensym'ed variables with uppercase names don't print funny.
 
 (define (avarid? name)
   (let ((ch  (string-ref (symbol->string name) 0)))
     (char-alphabetic? ch)))
 
 
 ;;; Similar stuff for doing constructor names.  Moby bleah....
 
 (define (write-conop name xp)
   (if (aconid? name)
       (begin
         (write-char #\` xp)
 	(write-aconid name xp)
 	(write-char #\` xp))
       (write-aconid name xp)))
 
 (define (write-conid name xp)
   (if (aconid? name)
       (write-aconid name xp)
       (begin
         (write-char #\( xp)
 	(write-aconid name xp)
 	(write-char #\) xp))))
 
 (define (aconid? name)
   (let ((ch  (string-ref (symbol->string name) 1)))
     (char-upper-case? ch)))
 
 
 ;;; These are officially aconid in the syntax, but they aren't
 ;;; prefixed so write them using write-avarid instead.  Barf.
 
 (define (write-modid name xp)
   (write-avarid name xp))
 
 (define (write-tyconid name xp)
   (write-avarid name xp))
 
 (define (write-tyclsid name xp)
   (write-avarid name xp))