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