git.fiddlerwoaroof.com
top/symbol-table.scm
4e987026
 ;;; These routines deal with the global symbol table.  The symbol table
 ;;; is represented in two stages: a module table which maps module names
 ;;; onto module structures and local tables within each module which
 ;;; map names (symbols) to definitions.
 
 ;;; The following functions deal with the module table (*modules*):
 
 ;;;  (initialize-module-table) - this clears out all modules from the
 ;;;      symbol table.  Every compilation should start with this.
 ;;;  (add-module-to-module-table module) - this takes a module ast,
 ;;;      either from a .exp file or previous compilation with the same
 ;;;      incarnation of the compiler and adds it to the set of `known'
 ;;;      modules.  Incomplete module ast's in the process of compilation
 ;;;      are also added to this table.
 
 
 (define (initialize-module-table)
   (setf *modules* (make-table)))
 
 (define (add-module-to-symbol-table module)
   (let* ((name (module-name module))
 	 (old-module (table-entry *modules* name)))
     (when (not (eq? old-module '#f))
       (if (eq? *unit* (module-unit old-module))
 	  (signal-module-double-definition name)
 	  (signal-module-already-defined name)))
     (setf (table-entry *modules* name) module)))
 
 (define (remove-module-from-symbol-table module)
   (let ((name (module-name module)))
     (setf (table-entry *modules* name) '#f)))
 
 (define (locate-module name)
   (table-entry *modules* name))
 
 ;;;  (walk-modules fn mod-list) - this calls fn for each module in the
 ;;;      mod-list.  It also binds the global variable *module* to the
 ;;;      current module, *symbol-table* to the local symbol
 ;;;      table.  The fixity table is also placed in a global.
 
 (define (walk-modules mods fn)
   (dolist (mod mods)
     (dynamic-let ((*module* mod)
 		  (*module-name* (module-name mod))
 		  (*symbol-table* (module-symbol-table mod))
 		  (*fixity-table* (module-fixity-table mod))
 		  (*inverted-symbol-table* (module-inverted-symbol-table mod)))
        (funcall fn))))
 
 ;;; create-definition makes a new definition object 
 
 (define (create-definition module name type)
   (cond ((module-prelude? module)
 	 (let ((def (table-entry *core-symbols* name)))
 	   (cond ((eq? def '#f)
 		  (create-definition/non-core module name type))
 		 (else
 		  (setf (def-unit def) *unit*)
 		  (setf (def-module def) (module-name module))
 		  ;; *** Should any other properties be reinitialized here?
 		  (cond ((or (eq? type 'var) (eq? type 'method-var))
 			 (setf (var-fixity def) '#f)
 			 (setf (var-signature def) '#f))
 			((eq? type 'con)
 			 (setf (con-fixity def) '#f)))
 		  def))))
 	(else (create-definition/non-core module name type))))
 
 ;(define (create-definition/non-core module name type)
 ;  (create-definition/new module name type)
 ;      (let* ((interface (module-interface-module module))
 ;	     (old-def (table-entry (module-symbol-table interface) name)))
 ;	(if (eq? old-def '#f)
 ;	    (create-definition/new module name type)
 ;	    (cond ((eq? type 'var)
 ;		   (unless (var? old-def)	
 ;		       (def-conflict module name type old-def))
 ;		   (setf (var-interface-type old-def) (var-type old-def)))
 ;		  ((eq? type 'con)
 ;		   (unless (con? old-def)
 ;		      (def-conflict module name type old-def)))
 ;		  ((eq? type 'synonym)
 ;		   (unless (synonym? old-def)
 ;		      (def-conflict module name type old-def)))
 ;		  ((eq? type 'algdata)
 ;		   (unless (algdata? old-def)
 ;		      (def-conflict module name type old-def)))
 ;		  ((eq? type 'class)
 ;		   (unless (class? old-def)
 ;		      (def-conflict module name type old-def)))
 ;		  ((eq? type 'method-var)
 ;		   (unless (method-var? old-def)
 ;		      (def-conflict module name type old-def)))))
 ;	(setf (def-unit old-def) *unit*)
 ;	old-def)))
 ;
 ;(define (def-conflict module name type def)
 ;  (phase-error 'interface-conflict
 ;    "The ~A ~A in module ~A was defined as a ~A in an interface."
 ;    (cond ((var? def) "variable")
 ;	  ((class? def) "class")
 ;	  ((algdata? def) "data type")
 ;	  ((synonym? def) "synonym")
 ;	  ((con? def) "constructor")
 ;	  (else "widgit"))
 ;    name (module-name module) type))    
 
 (define (create-definition/non-core module name type)
   (let ((mname  (module-name module)))
     (when (eq? (module-type *module*) 'interface)
        (mlet (((mod name1) (rename-interface-symbol name)))
          (setf mname mod)
 	 (setf name name1)))
     (create-definition/inner mname name type)))
 
 (define (create-definition/inner mname name type)
     (cond ((eq? type 'var)
 	   (make var (name name) (module mname) (unit *unit*)))
 	  ((eq? type 'con)
 	   (make con (name name) (module mname) (unit *unit*)))
 	  ((eq? type 'synonym)
 	   (make synonym (name name) (module mname) (unit *unit*)))
 	  ((eq? type 'algdata)
 	   (make algdata (name name) (module mname) (unit *unit*)))
 	  ((eq? type 'class)
 	   (make class (name name) (module mname) (unit *unit*)))
 	  ((eq? type 'method-var)
 	   (make method-var (name name) (module mname) (unit *unit*)))
 	  (else
 	   (error "Bad type argument ~s." type))))
 
 
 (define (create-top-definition name type)
   (let ((def (create-definition *module* name type)))
     (insert-top-definition name def)
     def))
 
 ;;; Interfaces have a special table which resolves imports in the
 ;;; interface.  Given a name in an interface module this returns the
 ;;; corresponding full name: a (module,original-name) pair.  Symbols not
 ;;; imported are assumed to be defined in the interface.
 
 (define (rename-interface-symbol name)
   (let ((res (assq name (module-interface-imports *module*))))
     (if (eq? res '#f)
 	(values *module-name* name)
 	(values (tuple-2-1 (tuple-2-2 res))
 		(tuple-2-2 (tuple-2-2 res))))))
 
 ;;; This creates a locally defined var node.
 
 (define (create-local-definition name)
   (let ((var     (make var (name name) (module *module-name*) (unit *unit*))))
     (setf (var-fixity var) (table-entry *fixity-table* name))
     var))
 
 
 ;;; This function creates a new variable. 
 ;;; The "root" may be either a symbol or a string.
 ;;; *unit* defines the home module of the variable.
 
 ;;; *** Maybe it would be possible to hack this so that it doesn't
 ;;; *** create any symbol at all until the name is demanded by something,
 ;;; *** but that seems like a rather sweeping change.
 
 (define (create-temp-var root)
   (let* ((name   (gensym (if (symbol? root) (symbol->string root) root)))
 	 (module  *unit*))
     (make var (name name) (module module) (unit *unit*))))
 
 
 ;;; The following routines install top level definitions into the symbol
 ;;; table.
 
 (predefine (signal-multiple-name-conflict name old-local-name def))
     ; in import-export/ie-errors.scm
 
 (define (insert-top-definition name def)
   (let ((old-definition (resolve-toplevel-name name)))
     (cond ((eq? old-definition '#f)
 	   (when (not (def-prelude? def))
 	       (setf (table-entry *symbol-table* name) def))
 	   (when (and (var? def) (not (eq? (var-fixity def) '#f)))
              (setf (table-entry *fixity-table* name)
 		   (var-fixity def)))
 	   (when (and (con? def) (not (eq? (con-fixity def) '#f)))
              (setf (table-entry *fixity-table* name)
 		   (con-fixity def)))
 	   (when (not (def-prelude? def))
  	    (if (eq? (local-name def) '#f)
 		(setf (table-entry *inverted-symbol-table* def) name)
 		(signal-multiple-name-conflict name (local-name def) def))))
 	  ((eq? old-definition def)
 	   'OK)
 	  ((def-prelude? old-definition)
 	   (signal-core-redefinition name))
 	  ((and (module-uses-standard-prelude? *module*)
 		(table-entry *prelude-symbol-table* name))
 	   (if (eq? (def-module def) *module-name*)
 	       (signal-prelude-redefinition name)
 	       (signal-prelude-reimport name (def-module def))))
 	  ((eq? (def-module def) *module-name*)
 	   (signal-multiple-definition-in-module name *module-name*))
 	  ((eq? (def-module old-definition) *module-name*)
 	   (signal-redefinition-by-imported-symbol name *module-name*))
 	  (else
 	   (signal-multiple-import name *module-name*)))))
 
 ;;; Gets the fixity of a name.
 
 (define (get-local-fixity name)
   (table-entry *fixity-table* name))
 
 ;;; These routines support general scoping issues.  Only vars have local
 ;;; definitions - all other names are resolved from the global symbol table.
 
 ;;; This is used when the name must be in the top symbols.
 
 (define (fetch-top-def name type)
   (let ((def (resolve-toplevel-name name)))
     (cond ((eq? def '#f)
 	   (cond ((eq? (module-type *module*) 'interface)
 		  (mlet (((mod name1) (rename-interface-symbol name)))
 		    (if (eq? mod *module-name*)
 			(undefined-topsym name)
 			(let ((new-def (create-definition/inner
 					mod name1 type)))
 			  (insert-top-definition name1 new-def)
 			  (cond ((algdata? new-def)
 				 (setf (algdata-n-constr new-def) 0)
 				 (setf (algdata-constrs new-def) '())
 				 (setf (algdata-context new-def) '())
 				 (setf (algdata-tyvars new-def) '())
 				 (setf (algdata-classes new-def) '#f)
 				 (setf (algdata-enum? new-def) '#f)
 				 (setf (algdata-tuple? new-def) '#f)
 				 (setf (algdata-real-tuple? new-def) '#f)
 				 (setf (algdata-deriving new-def) '()))
 				((class? new-def)
 				 (setf (class-method-vars new-def) '())
 				 (setf (class-super new-def) '())
 				 (setf (class-super* new-def) '())
 				 (setf (class-tyvar new-def) '|a|)
 				 (setf (class-instances new-def) '())
 				 (setf (class-kind new-def) 'other)
 				 (setf (class-n-methods new-def) 0)
 				 (setf (class-dict-size new-def) 0)
 				 (setf (class-selectors new-def) '()))) 
 			  new-def))))
 		 (else
 		  (undefined-topsym name))))
 	  (else def))))
 
 (define (undefined-topsym name)
   (signal-undefined-symbol name)
   *undefined-def*)
 
 
 (define (resolve-toplevel-name name)
   (let ((pc (table-entry *prelude-core-symbols* name)))
     (cond ((not (eq? pc '#f))
 	   pc)
 	  ((module-uses-standard-prelude? *module*)
 	   (let ((res (table-entry *prelude-symbol-table* name)))
 	     (if (eq? res '#f)
 		 (resolve-toplevel-name-1 name)
 		 res)))
 	  (else
 	   (resolve-toplevel-name-1 name)))))
 
 (define (resolve-toplevel-name-1 name)
   (cond ((eq? (module-inherited-env *module*) '#f)
 	 (table-entry *symbol-table* name))
 	(else
 	 (let ((res (search-inherited-tables
 		     name (module-inherited-env *module*))))
 	   (if (eq? res '#f)
 	       (table-entry *symbol-table* name)
 	       res)))))
 
 (define (search-inherited-tables name mod)
   (if (eq? mod '#f)
       '#f
       (let ((res (table-entry (module-symbol-table mod) name)))
 	(if (eq? res '#f)
 	    (search-inherited-tables name (module-inherited-env mod))
 	    res))))
 
 ;;; Con-ref's are special in that the naming convention (;Name) ensures
 ;;; that if a def is found it must be a con.
 
 (define (resolve-con con-ref)
   (when (eq? (con-ref-con con-ref) *undefined-def*)
     (remember-context con-ref
       (let ((def (fetch-top-def (con-ref-name con-ref) 'con)))
 	(setf (con-ref-con con-ref) def)))))
 
 (define (resolve-class class-ref)
   (when (eq? (class-ref-class class-ref) *undefined-def*)
     (remember-context class-ref
       (let ((def (fetch-top-def (class-ref-name class-ref) 'class)))
 	(when (not (class? def))
 	  (signal-class-name-required def (class-ref-name class-ref)))
 	(setf (class-ref-class class-ref) def)))))
 
 
 (define (resolve-tycon tycon)
   (when (eq? (tycon-def tycon) *undefined-def*)
     (remember-context tycon
       (let ((def (fetch-top-def (tycon-name tycon) 'algdata)))
 	(when (class? def)
 	  (signal-tycon-name-required (tycon-name tycon)))
 	(setf (tycon-def tycon) def)))))
 
 
 ;;; This should be used after the local environment has been searched.
 ;;; Other routines dealing with variable scoping are elsewhere.
 
 (define (resolve-var var-ref)
   (when (eq? (var-ref-var var-ref) *undefined-def*)
     (remember-context var-ref
       (let ((def (fetch-top-def (var-ref-name var-ref) 'var)))
 	(setf (var-ref-var var-ref) def)))))
 
 
 ;;; *** The inverted-symbol-table is the only table in the whole
 ;;; *** system that is not keyed off of symbols.  If this is a problem,
 ;;; *** things that use it could probably be rewritten to do something
 ;;; *** else, like store an a-list on the def itself.
 
 ;;; This does not need to consult the inherited-env flag because when this
 ;;; is used in extensions only new symbols get inserted.
 
 (define (local-name def)
   (cond ((def-prelude? def)
 	 (def-name def))
 	((module-uses-standard-prelude? *module*)
 	 (let ((res (table-entry *prelude-inverted-symbol-table* def)))
 	   (if (eq? res '#f)
 	    (table-entry *inverted-symbol-table* def)
 	    res)))
 	(else
 	 (table-entry *inverted-symbol-table* def))))
     
 (define (print-name x)
   (let ((res (local-name x)))
     (if (eq? res '#f)
 	(def-name x)
 	res)))
 
 
 ;;; Error signalling routines.
 
 (define (signal-module-double-definition name)
   (fatal-error 'module-double-definition
     "Module ~s is defined more than once."
     name))
 
 (define (signal-module-already-defined name)
   (fatal-error 'module-already-defined
     "Module ~a is defined more than once in the current unit."
     name))
 
 (define (signal-multiple-definition-in-module name modname)
  (if (eq? (module-type *module*) 'extension)
      (phase-error 'cant-redefine-in-extension
         "An extension for module ~A cannot redefine the symbol ~A"
 	modname name)
      (phase-error 'multiple-definition-in-module
         "There is more than one definition for the name ~a in module ~a."
 	name modname)))
 
 (define (signal-redefinition-by-imported-symbol name modname)
   (phase-error 'redefinition-by-imported-symbol
     "The name ~a is defined in module ~a, and cannot be imported."
     name modname))
 
 (define (signal-core-redefinition name)
   (phase-error 'prelude-redefinition
     "The name ~a is defined in the prelude core and cannot be redefined."
     name))
 
 (define (signal-prelude-redefinition name)
   (phase-error 'prelude-redefinition
     "The name ~a is defined in the prelude.~%You must hide it if you wish to use this name."
     name))
 
 (define (signal-prelude-reimport name modname)
   (phase-error 'prelude-redefinition
     "The name ~a is both imported from ~A and defined in the prelude.~%"
     name modname))
 
 (define (signal-multiple-import name modname)
   (phase-error 'multiple-import
     "The name ~a is imported into module ~a multiple times."
     name modname))
 
 (define (signal-undefined-symbol name)
   (phase-error 'undefined-symbol
     "The name ~A is undefined."
     name))
 
 (define (signal-class-name-required name def)
   (phase-error 'class-name-required
     "The name ~A defines a ~A, but a class name is required."
     name
     (if (synonym? def) "synonym" "data type")))
 
 (define (signal-tycon-name-required name)
   (phase-error 'tycon-required
     "The name ~A defines a class, but a type constructor name is required."
     name))