git.fiddlerwoaroof.com
Raw Blame History
;;; 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))