git.fiddlerwoaroof.com
Raw Blame History
;;; dump-interface.scm -- interface file writer/loader
;;;
;;; author :  John & Sandra
;;; date   :  8 Jul 1992
;;;
;;; This writes binary interface files.  A binary interface file is just
;;; a lisp (mumble) source file which directly builds the ast structure
;;; created by a compilation.  These files could be stored in either
;;; source or binary (compiled lisp) form.

;;; An interface may reference entities defined in other interfaces.
;;; To ensure consistancy between when an interface is written and
;;; when it is read back in, a stamp is assigned to all interface files
;;; which serves as a unique id.  The stamps of all imported units are
;;; saved and examined at load time.



;;;==================================================================
;;; Interface to compilation system
;;;==================================================================


;;; For compiled code, don't actually write out all the source code.
;;; Use a magic macro to memoize the form to be compiled.

(define *form-to-compile* '#f)
(define *magic-file-to-compile* "$HASKELL/bin/magic.scm")


;;; The output from compiling the prelude can completely overwhelm
;;; the Lisp compiler.  If this variable is a number, it specifies
;;; a "reasonable" number of top-level forms which can be compiled
;;; and write-compiled-code-file will try to break up the input
;;; code automagically.

(define *magic-chunk-size* '#f)


;;; This is called to write both the code file and the interface file.

(define (write-compiled-code-file filename code code-quality chunk-size)
  (let ((phase-start-time (get-run-time))
        (forms            (flatten-forms code)))
    (dynamic-let ((*magic-chunk-size*
		   (or chunk-size (dynamic *magic-chunk-size*)))
		  (*code-quality*
		   (or code-quality (dynamic *code-quality*))))
      (if (or (not (dynamic *magic-chunk-size*))
	      (<= (the fixnum (length forms))
		  (the fixnum (dynamic *magic-chunk-size*))))
	  (write-compiled-code-file-aux filename `(begin ,@forms))
	  (with-compilation-unit ()
	    (write-compiled-code-file-aux
	      filename
	      `(begin
		 ,@(map (lambda (f) `(load ,f))
			(write-compiled-code-file-split filename forms)))
	      ))))
    (when (memq 'phase-time *printers*)
      (let* ((current-time (get-run-time))
	     (elapsed-time (- current-time phase-start-time)))
	(format '#t "Lisp compilation complete: ~A seconds~%" elapsed-time)))
    ))

(define (write-compiled-code-file-split filename forms)
  (let ((place     (filename-place filename))
	(name      (filename-name filename))
	(type      (filename-type filename))
	(result    '()))
    (do ((i 0 (1+ i)))
	((null? forms))
	(multiple-value-bind (head tail)
	    (split-list forms (dynamic *magic-chunk-size*))
	  (let ((fname
		  (assemble-filename
		    place (format '#f "~a-part~a" name i) type)))
	    (push fname result)
	    (write-compiled-code-file-aux fname `(begin ,@head))
	    (setf forms tail))))
    (nreverse result)))

(define (flatten-forms code)
  (if (and (pair? code) (eq? (car code) 'begin))
      (nreverse (flatten-forms-aux (cdr code) '()))
      (list code)))

(define (flatten-forms-aux forms result)
  (dolist (f forms)
    (if (and (pair? f) (eq? (car f) 'begin))
	(setf result (flatten-forms-aux (cdr f) result))
	(push f result)))
  result)
	

(define (write-compiled-code-file-aux filename code)
  (dynamic-let ((*form-to-compile*  code))
    (compile-file (dynamic *magic-file-to-compile*) filename)))

(define-syntax (magic-form-to-compile)
  (dynamic *form-to-compile*))


;;; Writing source code is good for debugging purposes, but slow.
;;; The *print-circle* and *print-shared* flags have to be set because
;;; the code printed out may contain gensyms, and this will ensure
;;; that the code can be read in again.

(define (write-interpreted-code-file filename code hairy?)
  (dynamic-let ((*print-circle*   '#t)
		(*print-shared*   '#t))
    (call-with-output-file
      filename
      (lambda (port)
	(if hairy?
	    (pprint-flatten code port)
	    (print-flatten code port))))))


;;; This attempts to read a compiled interface for a unit.  This is
;;; done whenever the unit file is newer than the source file.  If
;;; imported units have changed, the load will fail and recompilation
;;; will be attempted.  
;;; The caller is responsible for making sure that the interface file exists
;;; and for making sure that the interface file is up-to-date with
;;; respect to imported modules and that all the imported modules are
;;; known.

;;; These variables are assigned by the code in the dump file.

(define *modules-loaded* '())
(define *modules-imported* '())
(define *defs-referenced* '())
(define *saved-cse-values* '())
(define *writer-version* '())

(define (read-binary-interface unit)
  (dynamic-let ((*modules-loaded*  '())
		(*modules-imported* '())
		(*defs-referenced*  '())
		(*saved-cse-values* '())
		(*writer-version* '()))
    (let ((file-date
	   (load-more-recent-file (ucache-cifile unit) (ucache-sifile unit))))
      (cond ((string=? *writer-version* *haskell-compiler-version*)
	     (setf (ucache-idate unit) file-date)
	     (setf (ucache-modules unit) (vector->list *modules-loaded*))
	     (setf (ucache-ifile-loaded unit) '#t)
	     '#t)
	    (else
	     (signal-incompatible-interface-file (ucache-cifile unit))
	     '#f)))))

(define (signal-incompatible-interface-file filename)
  (fatal-error 'incompatible-interface-file
    "File ~A~%~
     was written by a different version of the Haskell system.~%~
     You must remove it and recompile."
    filename))


(define (load-more-recent-file cfile sfile)
  (cond ((file-exists? cfile)
	 (if (or (not (file-exists? sfile))
		 (> (file-write-date cfile)
		    (file-write-date sfile)))
	     (load-compiled-interface-file cfile)
	     (load-interpreted-interface-file sfile)))
	((file-exists? sfile)
	 (load-interpreted-interface-file sfile))
	(else
	 (signal-file-not-found cfile))))

(define (load-interpreted-interface-file file)
  (load file)
  (file-write-date file))

(define (load-compiled-interface-file file)
  (load file)
  (file-write-date file))


;;;==================================================================
;;; Dump code generator
;;;==================================================================

;;; Globals

(define *dump-defs* '())
(define *dump-slot-init-code* '())
(define *dump-def-counter* 0)
(define *dump-def-code-table* (make-table))
(define *cse-objects* '())
(define *cse-value-num* 0)
(define *cse-object-num* '())
(define *gtype-class-index* '())
(define *context-class-index* '())
(define *gtype-tycon-index* '())
(define *gtype-list-index* '())
(define *gtype-index* '())
(define *number-vars-dumped* 0)


(define-syntax (def-dump-code def)
  `(table-entry *dump-def-code-table* ,def))

;;; This saves slot initialization code.

(define (add-dump-init code)
  (push code *dump-slot-init-code*))


;;; Here is the top-level call.

(define (create-dump-code unit modules load-prelude?)
  (dynamic-let ((*unit* (module-unit (car modules)))
		(*dump-defs*  '())
		(*dump-slot-init-code*  '())
		(*dump-def-counter* 0)
		(*dump-def-code-table* (make-table))
		(*cse-objects* '())
		(*cse-object-num* *num-saved-gtyvars*)
		(*gtype-class-index* '())
		(*context-class-index* '())
		(*gtype-tycon-index* '())
		(*gtype-list-index* '())
		(*gtype-index* '())
		(*number-vars-dumped* 0)
		(*number-types-dumped* 0)
		(*number-classes-dumped* 0))
    (let ((res (create-dump-code-aux unit modules load-prelude?)))
      (when (memq 'dumper (dynamic *printers*))
        (pprint* res))
      (when (memq 'dump-stat (dynamic *printers*))
	(format '#t
	  "~&Dumped ~A definitions, ~A type objects, and ~A classes.~%"
          *number-vars-dumped* *number-types-dumped*
	  *number-classes-dumped*)
	(format '#t "Used ~A definitions and ~A type cells.~%"
		*dump-def-counter* (length *cse-objects*)))
      res)))

;;; This assumes all modules are in the same compilation unit and that
;;; *unit* is set to that unit.
;;; imod-code establishes local bindings for all the imported modules.
;;; dmod-code establishes local bindings for all the modules defined in
;;; this compilation unit.

(define (create-dump-code-aux unit modules load-prelude?)
  (let* ((imod-counter  0)
	 (imod-alist    '())
	 (explicit-imports (collect-all-imported-modules unit))
	 (all-imports   (if load-prelude?
			    (append (collect-prelude-modules) explicit-imports)
			    explicit-imports))
	 (imod-code     (map (lambda (m)
			       (push (cons (module-name m) imod-counter)
				     imod-alist)
			       (incf imod-counter)
			       `(locate-module ',(module-name m)))
			     all-imports))
	 (dmod-counter  0)
	 (dmod-alist    '())
	 (dmod-code     (map (lambda (m)
			       (push (cons (module-name m) dmod-counter)
				     dmod-alist)
			       (incf dmod-counter)
			       `(make module
				      (unit ',(module-unit m))
				      (name ',(module-name m))
				      (type ',(module-type m))))
			     modules)))
    ;; This actually does most of the work.  It dumps the module asts by
    ;; placing inits for each slot into *dump-slot-init-code*.  A list of
    ;; definitions referenced is maintained in *dump-defs*.
    (dolist (m modules)
      (dump-module m (cdr (assq (module-name m) dmod-alist))))
    ;; This creates the final code
    `(begin
       (setf *writer-version* ',*haskell-compiler-version*)
       (setf *modules-imported* (vector ,@imod-code))
       (setf *modules-loaded* (vector ,@dmod-code))
       ;; This sets the elements individually instead of using the vector
       ;; function, because the vector may be longer than
       ;; call-arguments-limit.
       (setf *defs-referenced*
	     (make-vector ,(dynamic *dump-def-counter*)))
       ,@(map (lambda (d)
		`(setf ,(def-dump-code d)
		       ,(make-def-init-code d imod-alist dmod-alist)))
	      *dump-defs*)
       ,@(cse-init-code)
       ,@(dynamic *dump-slot-init-code*)
       )
    ))


;;; Runtime support

(define-syntax (lookup-imported-mod i)
  `(vector-ref *modules-imported* ,i))

(define-syntax (lookup-defined-mod i)
  `(vector-ref *modules-loaded* ,i))

(define (set-export-from-def-vector table key index)
  (setf (table-entry table key)
	(list (cons key (vector-ref *defs-referenced* index)))))

(define (set-export-from-def table key def)
  (setf (table-entry table key)
	(list (cons key def))))

(define (set-symtab-from-def-vector table key index)
  (setf (table-entry table key)
	(vector-ref *defs-referenced* index)))

(define (init-variable-slots var exported? toplevel? type simple? strict?)
  (setf (def-exported? var) exported?)
  (setf (var-toplevel? var) toplevel?)
  (setf (var-type var) type)
  (setf (var-simple? var) simple?)
  (setf (var-strict? var) strict?)
  var)

(define (init-function-slots var exported? toplevel? type simple? strict?
			     arity strictness opt-entry)
  (setf (def-exported? var) exported?)
  (setf (var-toplevel? var) toplevel?)
  (setf (var-type var) type)
  (setf (var-simple? var) simple?)
  (setf (var-strict? var) strict?)
  (setf (var-arity var) arity)
  (setf (var-strictness var) strictness)
  (setf (var-optimized-entry var) opt-entry)
  var)

(define (init-method-var-slots var class default method-signature)
  (setf (method-var-class var) class)
  (setf (method-var-default var) default)
  (setf (method-var-method-signature var) method-signature)
  var)

(define (init-constructor-slots
  	   con arity types signature tag alg fixity infix?)
  (setf (con-arity con) arity)
  (setf (con-types con) types)
  (setf (con-signature con) signature)
  (setf (con-tag con) tag)
  (setf (con-alg con) alg)
  (setf (con-fixity con) fixity)
  (setf (con-infix? con) infix?)
  (dotimes (i arity)
    (push '#f (con-slot-strict? con)))
  con)

(define (make-new-instance algdata tyvars class context gcontext dictionary m)
  (make instance
	(algdata algdata)
	(tyvars tyvars)
	(class class)
	(context context)
	(gcontext gcontext)
	(dictionary dictionary)
	(methods m)
	(ok? '#t)))


;;; This computes the transitive closure of all modules available to
;;; a unit.

(define (collect-all-imported-modules unit)
  (collect-all-modules-1 (ucache-imported-units unit) '() '()))

(define (collect-all-modules-1 units mods-so-far units-seen)
  (cond ((null? units)
	 mods-so-far)
	((mem-string (car units) units-seen)
	 (collect-all-modules-1 (cdr units) mods-so-far units-seen))
	(else
	 (let ((u (lookup-compilation-unit (car units))))
	   (collect-all-modules-1
	    (append (ucache-imported-units u) (cdr units))
	    (append (ucache-modules u) mods-so-far)
	    (cons (ucache-ufile u) units-seen))))
	))

(define (collect-prelude-modules)
  (let ((prelude-unit (lookup-compilation-unit *prelude-unit-filename*)))
    (append (ucache-modules prelude-unit)
	    (collect-all-imported-modules prelude-unit))))

(define (def->core-name-string def)
  (if (con? def)
      (remove-con-prefix (symbol->string (def-name def)))
      (symbol->string (def-name def))))

;;; This code returns the load time definition for an object.  When the
;;; object is a core symbol or in a different unit, previously
;;; created definitions are returned.  Otherwise, a new definition is
;;; created.
  
(define (make-def-init-code d imod-alist dmod-alist)
  (declare (ignore dmod-alist))
  (cond ((def-core? d)
	 `(core-symbol ,(def->core-name-string d)))
	((eq? (def-unit d) *unit*)
	 `(create-definition/inner
	    ',(def-module d)
	    ',(def-name d)
	    ',(cond ((method-var? d) 'method-var)
		    ((var? d) 'var)
		    ((con? d) 'con)
		    ((synonym? d) 'synonym)
		    ((algdata? d) 'algdata)
		    ((class? d) 'class))))
	((is-tuple-constructor? d)
	 `(tuple-constructor ,(tuple-constructor-arity d)))
	((is-tuple-tycon? d)
	 `(tuple-tycon ,(tuple-constructor-arity (car (algdata-constrs d)))))
	(else
	 (let ((m (assq (def-module d) imod-alist)))
	   ;; This is a bogus error message.  The problem is that nothing
	   ;; so far ensures units are closed under import/export: some
	   ;; modules may be referenced that are accidentally in the symbol
	   ;; table.  The unif file for the current module needs to be
	   ;; updated when this happens.
	   (when (eq? m '#f)
	     (fatal-error 'symbol-not-in-unit
 "Reference to symbol ~A in module ~A: not in compilation unit.~%"
                (def-name d) (def-module d)))
	 `(table-entry
	    (module-symbol-table
	      (lookup-imported-mod ,(tuple-2-2 m)))
	    ',(def-name d))))
	))


;;; Once a module has been compiled, most of its slots are useless.
;;; All we really need to save are the identifying information,
;;; symbol table, and export table.
;;; Instances also need to be dumped here instead of with class objects;
;;; this is because links can go across compilation unit boundaries.
;;; They are fixed up when pulling units out of the cache.
;;; The identifying info is stored when the module variable is bound.


(define (dump-module module index)
  (let ((mod-exp `(lookup-defined-mod ,index))
	(save-all-symbols (or (eq? (module-type module) 'standard)
			      (eq? (module-name module) '|Prelude|))))
    ;; Dump symbol table entries only for defs for which this is
    ;; the "home" module.  (In other words, ignore imported defs.)
    ;; The purpose of this is to allow references from other
    ;; interface files to be resolved; see make-def-init-code.
    ;; Jcp: we need to save the complete symbol table for incremental
    ;; compilation to work.
    (let ((code  '()))
      (table-for-each
        (lambda (key val)
	  (when (or save-all-symbols
		    (eq? (def-module val) (module-name module)))
	    (let ((def  (dump-object val)))
	      (push
	        (if (and (pair? def)
			 (eq? (car def) 'vector-ref)
			 (eq? (cadr def) '*defs-referenced*))
		    `(set-symtab-from-def-vector table ',key ,(caddr def))
		    `(setf (table-entry table ',key) ,def))
		code))))
	(module-symbol-table module))
      (add-dump-init `(setf (module-symbol-table ,mod-exp)
			    (let ((table  (make-table))) ,@code table))))
    ;; dump the fixity table - needed by the incremental compiler
    (when save-all-symbols
      (let ((code  '()))
	(table-for-each
	  (lambda (key val)
	    (push `(setf (table-entry table ',key)
			 (make-fixity ',(fixity-associativity val)
				      ',(fixity-precedence val)))
		  code))
	  (module-fixity-table module))
	(add-dump-init `(setf (module-fixity-table ,mod-exp)
			      (let ((table  (make-table))) ,@code table)))))
    ;; Dump all export table entries.  This is used by the import/export
    ;; phase to resolve references.  
    (let ((code  '()))
      (table-for-each
        (lambda (key val)
	  ;; val is an a-list of (sym . def) pairs.
	  ;; Look for shortcut to reduce size of generated code.
	  (push
	    (if (and (null? (cdr val))
		     (eq? (car (car val)) key))
		(let ((def  (dump-object (cdr (car val)))))
		  (if (and (pair? def)
			   (eq? (car def) 'vector-ref)
			   (eq? (cadr def) '*defs-referenced*))
		      `(set-export-from-def-vector table ',key ,(caddr def))
		      `(set-export-from-def table ',key ,def)))
		`(setf (table-entry table ',key) ,(dump-object val)))
	    code))
	(module-export-table module))
      (add-dump-init `(setf (module-export-table ,mod-exp)
			    (let ((table  (make-table))) ,@code table))))
    ;; Dump the instances.
    (add-dump-init `(setf (module-instance-defs ,mod-exp)
			  ,(dump-object (module-instance-defs module))))
    (add-dump-init `(setf (module-default ,mod-exp)
			  ,(dump-object (module-default module))))
    (add-dump-init `(setf (module-uses-standard-prelude? ,mod-exp)
			  ,(dump-object
			    (module-uses-standard-prelude? module))))
    ))

(define (make-fixity a p)
  (make fixity (associativity a) (precedence p)))


;;;==================================================================
;;; Dump structure traversal
;;;==================================================================

;;; This is the general object dumper.  It recognizes the basic Lisp
;;; objects and dumps them.  Given an object, this generates lisp code
;;; to recreate the object at load time.

(define (dump-object x)
  (cond ((struct? x)
	 (dump x))
	((or (symbol? x) (null? x))
	 ;; Symbols and lists must be quoted.
	 `',x)
	((or (number? x)
	     (eq? x '#t)
	     (eq? x '#f)
	     (string? x)   ; This makes dumped strings immutable.
	     (char? x))
	 ;; These objects are self-evaluating.
	 x)
	((list? x)
	 ;; True lists
	 `(list ,@(map (function dump-object) x)))
	((pair? x)
	 `(cons ,(dump-object (car x))
		,(dump-object (cdr x))))
	((vector? x)
	 `(vector ,@(map (function dump-object) (vector->list x))))
	((table? x)
	 `(list->table ,@(dump-object (table->list x))))
	(else
	 (error "Don't know how to dump ~A." x))))


;;; *** Should install the walker in the type descriptor.

(define-walker dump)

(define (dump x)
  (call-walker dump x))



;;;==================================================================
;;; Dumpers for defs
;;;==================================================================


;;; All walkers for def structures should call this macro.  The body
;;; is invoked only if the def belongs to the current compilation unit
;;; and hasn't already been traversed.  Within the body, the 
;;; variable "v" is bound to a form that will evaluate to the 
;;; corresponding def structure at run time.  This is also
;;; the return value from the macro.

(define-local-syntax (with-new-def (v d stat-var) . body)
  (let ((temp   (gensym))
	(expvar (gensym)))
    `(let ((,temp  ,d)
	   (,expvar '#f))
       (if (not (def-dump-code ,temp))
	   (begin
	     (cond ((not (def-core? ,temp))
		    (setf ,expvar
			  (list 'vector-ref
				'*defs-referenced*
				(dynamic *dump-def-counter*)))
		    (incf (dynamic *dump-def-counter*))
		    (push ,temp *dump-defs*))
		   (else
		    (setf ,expvar
			  (make-core-symbol-name
			    (def->core-name-string ,temp)))))
	     (setf (def-dump-code ,temp) ,expvar)
	     (when (eq? (def-unit ,temp) *unit*)
	       (incf (dynamic ,stat-var))
	       (let ((,v  ,expvar))
		 ,@body))
	     ,expvar)
	   (def-dump-code ,temp)))))


;;; This macro is used to save the value of a structure slot in the
;;; initforms of the dump.

(define-local-syntax (dump-def-slots obj-var type dexp slots)
  `(add-dump-init
     (list 'update-slots ',type ,dexp
	   ,@(map (lambda (s)
		    `(list ',s
			   (dump-object (struct-slot ',type ',s ,obj-var))))
		  slots)))
  )



(define-walker-method dump var (var)
  (dump-var/n var))

(define (dump-var/n var)
  (with-new-def (dexp var *number-vars-dumped*)
    (do-dump-var dexp var '#f)))

(define (do-dump-var dexp var method-var?)
  (let ((code            '())
	(exported?       (def-exported? var))
	(toplevel?       (var-toplevel? var))
	(type            (var-type var))
	(simple?         (var-simple? var))
	(strict?         (var-strict? var))
	(arity           (var-arity var))
	(strictness      (var-strictness var))
	(opt-entry       (var-optimized-entry var))
	(complexity      (var-complexity var))
	(fixity          (var-fixity var))
	(value           (var-value var))
	(inline-value    (var-inline-value var))
	(sel?            (var-selector-fn? var)))
    ;; Some slots are useless for vars that don't name functions.
    (if (eqv? arity 0)
	(push `(init-variable-slots var
	         ',exported?
		 ',toplevel?
		 ,(dump-object type)
		 ',simple?
		 ',strict?)
	      code)
	(push `(init-function-slots var
		 ',exported?
		 ',toplevel?
		 ,(dump-object type)
		 ',simple?
		 ',strict?
		 ',arity
		 ,(dump-strictness strictness)
		 ',opt-entry)
	      code))
    ;; These slots rarely need to be tweaked from the default.
    (when sel?
      (push `(setf (var-selector-fn? var) '#t) code))
    (when complexity
      (push `(setf (var-complexity var) ,complexity) code))
    (when fixity
      (push `(setf (var-fixity var) ,(dump-object fixity)) code))
    ;; Save values of simple variables to permit inlining.
    ;; Save values of structured constants to permit folding of flic-sel
    ;; operations -- this is necessary to optimize dictionary lookups.
    (when (or simple? sel?
	      (and value
		   (is-type? 'flic-app value)
		   (structured-constant-app?
		     (flic-app-fn value) (flic-app-args value))))
      (push `(setf (var-value var) ,(dump-flic-top value)) code))
    (when inline-value
      (push `(setf (var-inline-value var) ,(dump-flic-top inline-value)) code))
    ;; Save extra stuff for method vars
    (when method-var?
      (push `(init-method-var-slots var
	       ,(dump-object (method-var-class var))
	       ,(dump-object (method-var-default var))
	       ,(dump-object (method-var-method-signature var)))
	    code))
    ;; Push the whole mess onto the init code.
    (add-dump-init `(let ((var  ,dexp)) ,@(nreverse code)))))


(define-walker-method dump method-var (var)
  (dump-method-var/n var))

(define (dump-method-var/n var)
  (with-new-def (dexp var *number-vars-dumped*)
    (do-dump-var dexp var '#t)))

(define-walker-method dump con (con)
  (dump-con/n con))

(define (dump-con/n con)
  (with-new-def (dexp con *number-types-dumped*)
    (add-dump-init
      `(let ((con (init-constructor-slots
		   ,dexp
		   ,(con-arity con)
		   ,(dump-object (con-types con))
		   ,(dump-object (con-signature con))
		   ,(con-tag con)
		   ,(dump-object (con-alg con))
		   ,(dump-object (con-fixity con))
		   ',(con-infix? con))))
	 ,@(if (memq '#t (con-slot-strict? con))
	       `((setf (con-slot-strict? con) ',(con-slot-strict? con)))
	       '())
	 ,@(if (eq? (con-lisp-fns con) '())
	       '()
	       `((setf (con-lisp-fns con) ',(con-lisp-fns con))))
	 con))))

;;; *** Could define similar init functions for other defs instead
;;; *** of setting slots inline, but I'm lazy and they don't show up
;;; *** nearly as often as the others.

(define-walker-method dump algdata (alg)
  (dump-algdata/n alg))

(define (dump-algdata/n alg)
  (with-new-def (dexp alg *number-types-dumped*)
    (dump-def-slots alg algdata dexp
		    (arity n-constr constrs context tyvars signature
			   enum? tuple? real-tuple? implemented-by-lisp?))))

(define-walker-method dump synonym (syn)
  (dump-synonym/n syn))

(define (dump-synonym/n syn)
  (with-new-def (dexp syn *number-types-dumped*)
    (dump-def-slots syn synonym dexp (arity args body))))

(define-walker-method dump class (class)
  (dump-class/n class))

(define (dump-class/n class)
  (with-new-def (dexp class *number-classes-dumped*)
    (dump-def-slots class class dexp
		    (super super* tyvar method-vars selectors kind
		     n-methods dict-size))))


;;;==================================================================
;;; Dumpers for non-def AST structs
;;;==================================================================

;;; This section contains dumpers to handle type-related structs that
;;; are referenced by the various def guys.


(define-walker-method dump instance (o)
  (if (not (instance-ok? o))
      (error "Attempt to dump instance that's not ok!"))
  `(make-new-instance
     ,(dump-object (instance-algdata o))
     ,(dump-object (instance-tyvars o))
     ,(dump-object (instance-class o))
     ,(dump-object (instance-context o))
     ,(dump-object (instance-gcontext o))
     ,(dump-object (instance-dictionary o))
     ,(dump-object (instance-methods o))))



(define-walker-method dump gtype (o)
  (dump-gtype/cse o))

(define-walker-method dump fixity (o)
  `(**fixity ',(fixity-associativity o) ',(fixity-precedence o)))

(define-walker-method dump tyvar (o)
  `(**tyvar ',(tyvar-name o)))

(define-walker-method dump class-ref (o)
  `(**class/def ,(dump-object (class-ref-class o))))

(define-walker-method dump context (o)
  `(**context ,(dump-object (context-class o))
	      ,(dump-object (context-tyvar o))))

(define-walker-method dump tycon (o)
  `(**tycon/def ,(dump-object (tycon-def o))
		,(dump-object (tycon-args o))))

(define-walker-method dump default-decl (o)
  `(make default-decl (types ,(dump-object (default-decl-types o)))))

(define-walker-method dump signature (o)
  `(make signature (context ,(dump-object (signature-context o)))
	           (type ,(dump-object (signature-type o)))))

;;; All ntyvars should be instantiated at this point

; (define-walker-method dump ntyvar (o)
;  (dump-object (prune o)))