summaryrefslogtreecommitdiff
path: root/top/symbol-table.scm
blob: 499bfb8aa261bc9616f6636cdef65e1c671e51c8 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
;;; 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))