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))
|