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