1 module ddparser.symtab;
2 
3 import std.bitmanip;
4 import ddparser.util;
5 
6 import core.stdc.string;
7 import core.stdc.stdio;
8 
9 enum INITIAL_SYMHASH_SIZE =	3137;
10 
11 struct D_SymHash {
12   int		index;
13   int		grow;
14   Vec!(D_Sym*)	syms;
15 }
16 
17 alias D_UserSym = uint;
18 
19 struct D_Sym {
20   string name;
21   uint	 hash;
22   D_Scope *scope_;
23   D_Sym	 *update_of;
24   D_Sym	 *next;
25   D_UserSym	 user;
26 }
27 
28 enum D_SCOPE_INHERIT =			0;
29 enum D_SCOPE_RECURSIVE =		1;
30 enum D_SCOPE_PARALLEL =		2;
31 enum D_SCOPE_SEQUENTIAL =		3;
32 
33 
34 
35 struct D_Scope {
36     mixin(bitfields!(
37                 uint, "kind", 2,
38                 uint, "owned_by_user", 1,  /* don't automatically delete */
39                 uint, "", 29
40                 ));
41   uint depth;
42   D_Sym		 	*ll;
43   D_SymHash	*hash;
44   D_Sym		 	*updates;
45   D_Scope *search;       /* scope to start search */
46   D_Scope *dynamic;      /* dynamic scope (e.g. methods) */
47   D_Scope *up;		/* enclosing scope */
48   D_Scope *up_updates;	/* prior scope in speculative parse */
49   D_Scope *down;		/* enclosed scopes (for FREE) */
50   D_Scope *down_next;	/* next enclosed scope */
51 }
52 
53 /*
54   How this works.  In a normal symbol table there is simply
55   a stack of scopes representing the scoping structure of
56   the program.  Because of speculative parsing, this symbol table
57   also has a tree of all 'updates' representing different
58   views of the state of scoped variables by each speculative
59   parse state.  Periodically, when the parse state collapses
60   to a single state (we are nolonger speculating), these changes
61   are can be 'committed' and the changes pushed into the top
62   level hash table.
63  
64   All D_Scope's except the top level just have a 'll' of symbols, the
65   top level has a 'hash'.
66  
67   'updates' is a list of changes to symbols in other scopes.  It is
68   searched to find the current version of a symbol with respect to the
69   speculative parse path represented by D_Scope.
70 
71   'up' points to the enclosing scope, it isn't used much.
72 
73   'up_updates' is the prior scope in speculative parsing, it is used find
74   the next D_Scope to look in for 'updates' after the current one has been
75   searched.
76 
77   'down' and 'down_next' are used to hold enclosing scopes, or in the
78   case of the top level, sibling scopes (created by commmit).
79 */
80   
81 
82 private void
83 symhash_add(D_SymHash *sh, D_Sym *s) {
84   uint i, h = s.hash % sh.syms.n, n;
85   D_Sym **v = sh.syms.v;
86   D_Sym *x;
87   Vec!(D_Sym*) vv, tv;
88 
89   sh.index++;
90   s.next = v[h];
91   v[h] = s;
92 
93   if (sh.index > sh.grow) {
94     vv.v = sh.syms.v;
95     vv.n = sh.syms.n;
96     sh.syms.n = sh.grow;
97     sh.grow = sh.grow * 2 + 1;
98     sh.syms.v = (new D_Sym*[sh.syms.n]).ptr;// cast(D_Sym**)MALLOC(sh.syms.n * (void *).sizeof);
99     v = sh.syms.v;
100     n = sh.syms.n;
101     vec_clear(&tv);
102     for (i = 0; i < vv.n; i++)
103       /* use temporary to preserve order */
104       while (vv.v[i]) {
105 	x = vv.v[i];
106 	vv.v[i] = x.next;
107 	vec_add(&tv, x);
108       }
109       while (tv.v[i]) {
110 	x = tv.v[i];
111 	tv.v[i] = x.next;
112 	h = x.hash % n;
113 	x.next = v[h];
114 	v[h] = x;
115       }
116     FREE(vv.v);
117   }
118 }
119 
120 private D_SymHash * 
121 new_D_SymHash() {
122   D_SymHash *sh = new D_SymHash();
123   sh.grow = INITIAL_SYMHASH_SIZE * 2 + 1;
124   sh.syms.n = INITIAL_SYMHASH_SIZE;
125   sh.syms.v = (new D_Sym*[sh.syms.n]).ptr; // cast(D_Sym**)MALLOC(sh.syms.n * (void *).sizeof);
126   return sh;
127 }
128 
129 private void
130 free_D_SymHash(D_SymHash *sh) {
131   int i;
132   D_Sym *sym;
133   for (i = 0; i < sh.syms.n; i++)
134     for (; sh.syms.v[i]; sh.syms.v[i] = sym) {
135       sym = sh.syms.v[i].next; 
136       free_D_Sym(sh.syms.v[i]);
137     }
138   FREE(sh.syms.v);
139   FREE(sh);
140 }
141 
142 D_Scope *
143 new_D_Scope(D_Scope *parent) {
144   D_Scope *st = new D_Scope();
145   if (parent) {
146     st.depth = parent.depth + 1;
147     st.kind = parent.kind;
148     st.search = parent;
149     st.up = parent;
150     st.up_updates = parent;
151     st.down_next = parent.down;
152     parent.down = st;
153   } else
154     st.hash = new_D_SymHash();
155   return st;
156 }
157 
158 D_Scope *
159 equiv_D_Scope(D_Scope *current) {
160   D_Scope *s = current, last = current;
161   D_Sym *sy;
162   if (!s)
163     return s;
164   while (s.depth >= current.depth) {
165     if (s.depth == last.depth) {
166       if (current.up == s.up)
167 	last = s;
168       else
169 	break;
170     }
171     if (s.ll || s.hash)
172       break;
173     if (s.dynamic)
174       break;
175     sy = s.updates;
176     while (sy) {
177       if (sy.scope_.depth <= current.depth)
178 	break;
179       sy = sy.next;
180     }
181     if (sy)
182       break;
183     if (!s.up_updates)
184       break;
185     s = s.up_updates;
186   }
187   return last;
188 }
189 
190 
191 D_Scope *
192 enter_D_Scope(D_Scope *current, D_Scope *scope_) {
193   D_Scope *st = new D_Scope(), parent = scope_.up;
194   st.depth = scope_.depth;
195   st.up = parent;
196   st.kind = scope_.kind;
197   st.search = scope_;
198   st.up_updates = current;
199   st.down_next = current.down;
200   current.down = st;
201   return st;
202 }
203 
204 D_Scope *
205 global_D_Scope(D_Scope *current) {
206   D_Scope *g = current;
207   while (g.up) g = g.search;
208   return enter_D_Scope(current, g);
209 }
210 
211 D_Scope *
212 scope_D_Scope(D_Scope *current, D_Scope *scope_) {
213   D_Scope *st = new D_Scope(), parent = current.up;
214   st.depth = current.depth;
215   st.up = parent;
216   st.kind = current.kind;
217   st.search = current;
218   st.dynamic = scope_;
219   st.up_updates = current;
220   st.down_next = current.down;
221   current.down = st;
222   return st;
223 }
224 
225 void
226 free_D_Scope(D_Scope *st, int force) {
227   D_Scope *s;
228   D_Sym *sym;
229   for (; st.down; st.down = s) {
230     s = st.down.down_next;
231     free_D_Scope(st.down, 0);
232   }
233   if (st.owned_by_user && !force)
234     return;
235   if (st.hash)
236     free_D_SymHash(st.hash);
237   else
238     for (; st.ll; st.ll = sym) {
239       sym = st.ll.next;
240       free_D_Sym(st.ll);
241     }
242   for (; st.updates; st.updates = sym) {
243     sym = st.updates.next;
244     free_D_Sym(st.updates);
245   }
246   FREE(st);
247 }
248 
249 private void 
250 commit_ll(D_Scope *st, D_SymHash *sh) {
251   D_Sym *sym;
252   if (st.search) {
253     commit_ll(st.search, sh);
254     for (; st.ll; st.ll = sym) {
255       sym = st.ll.next;
256       symhash_add(sh, st.ll);
257     }
258   }
259 }
260 
261 /* make direct links to the latest update */
262 private void 
263 commit_update(D_Scope *st, D_SymHash *sh) {
264   int i;
265   D_Sym *s;
266 
267   for (i = 0; i < sh.syms.n; i++)
268     for (s = sh.syms.v[i]; s; s = s.next) 
269       s.update_of = current_D_Sym(st, s);
270 }
271 
272 /* currently only commit the top level scope */
273 D_Scope *
274 commit_D_Scope(D_Scope *st) {
275   D_Scope *x = st;
276   if (st.up)
277     return st;
278   while (x.search) x = x.search;
279   commit_ll(st, x.hash);
280   commit_update(st, x.hash);
281   return x;
282 }
283 
284 D_Sym *
285 new_D_Sym(D_Scope *st, string name, int sizeof_D_Sym) {
286   D_Sym *s = cast(D_Sym*)MALLOC(sizeof_D_Sym);
287   memset(s, 0, sizeof_D_Sym);
288   s.name = name;
289   s.hash = strhashl(name);
290   s.scope_ = st;
291   if (st) {
292     if (st.hash) {
293       symhash_add(st.hash, s);
294     } else {
295       s.next = st.ll;
296       st.ll = s;
297     }
298   }
299   return s;
300 }
301 
302 void
303 free_D_Sym(D_Sym *s) {
304   FREE(s);
305 }
306 
307 D_Sym *
308 current_D_Sym(D_Scope *st, D_Sym *sym) {
309   D_Scope *sc;
310   D_Sym *uu;
311 
312   if (sym.update_of) sym = sym.update_of;
313   /* return the last update */
314   for (sc = st; sc; sc = sc.up_updates) {
315     for (uu = sc.updates; uu; uu = uu.next)
316       if (uu.update_of == sym)
317 	return uu;
318   }
319   return sym;
320 }
321 
322 private D_Sym *
323 find_D_Sym_in_Scope_internal(D_Scope *st, string name, uint h) {
324     D_Sym *ll;
325     for (;st ; st = st.search) {
326         if (st.hash) 
327             ll = st.hash.syms.v[h % st.hash.syms.n];
328         else
329             ll = st.ll;
330         while (ll) {
331             if (ll.hash == h && ll.name == name)
332                 return ll;
333             ll = ll.next;
334         }
335         if (st.dynamic)
336         {
337             ll = find_D_Sym_in_Scope_internal(st.dynamic, name, h);
338             if (ll)
339                 return ll;
340         }
341         if (!st.search || st.search.up != st.up)
342             break;
343     }
344     return null;
345 }
346 
347 private D_Sym *
348 find_D_Sym_internal(D_Scope *cur, string name, uint h) {
349     D_Sym *ll;
350     if (!cur)
351         return null;
352     if (cur.hash) 
353         ll = cur.hash.syms.v[h % cur.hash.syms.n];
354     else
355         ll = cur.ll;
356     while (ll) {
357         if (ll.hash == h && ll.name == name)
358             break;
359         ll = ll.next;
360     }
361     if (!ll) { 
362         if (cur.dynamic)
363         {
364             ll = find_D_Sym_in_Scope_internal(cur.dynamic, name, h);
365             if (ll)
366                 return ll;
367         }
368         if (cur.search)
369             return find_D_Sym_internal(cur.search, name, h);
370         return ll;
371     }
372     return ll;
373 }
374 
375 D_Sym *
376 find_D_Sym(D_Scope *st, string name) {
377   uint h = strhashl(name);
378   D_Sym *s = find_D_Sym_internal(st, name, h);
379   if (s)
380     return current_D_Sym(st, s);
381   return null;
382 }
383 
384 D_Sym *
385 find_global_D_Sym(D_Scope *st, string name) {
386   uint h = strhashl(name);
387   D_Scope *cur = st;
388   while (cur.up) cur = cur.search;
389   D_Sym *s = find_D_Sym_internal(cur, name, h);
390   if (s)
391     return current_D_Sym(st, s);
392   return null;
393 }
394 
395 D_Sym *
396 find_D_Sym_in_Scope(D_Scope *st, D_Scope *cur, string name) {
397   uint h = strhashl(name);
398   D_Sym *s = find_D_Sym_in_Scope_internal(cur, name, h);
399   if (s)
400     return current_D_Sym(st, s);
401   return null;
402 }
403 
404 D_Sym *
405 next_D_Sym_in_Scope(D_Scope **scope_, D_Sym **sym) {
406   D_Sym *last_sym = *sym, ll = last_sym;
407   D_Scope *st = *scope_;
408   if (ll) {
409     ll = ll.next;
410     if (ll)
411       goto Lreturn;
412   }
413   for (;st ; st = st.search) {
414     if (st.hash) {
415       int i = last_sym ? ((last_sym.hash + 1) % st.hash.syms.n) : 0;
416       if (!last_sym || i)
417 	ll = st.hash.syms.v[i];
418     } else {
419       if (!last_sym)
420 	ll = st.ll;
421     }
422     last_sym = null;
423     if (ll)
424       goto Lreturn;
425     if (!st.search || st.search.up != st.up)
426       break;
427   }
428  Lreturn:
429   if (ll)
430     *sym = ll;
431   *scope_ = st;
432   return ll;
433 }
434 
435 D_Sym *
436 update_additional_D_Sym(D_Scope *st, D_Sym *sym, int sizeof_D_Sym) {
437   sym = current_D_Sym(st, sym);
438   D_Sym *s = cast(D_Sym*)MALLOC(sizeof_D_Sym);
439   memcpy(s, sym, (D_Sym).sizeof);
440   if (sym.update_of) sym = sym.update_of;
441   s.update_of = sym;
442   s.next = st.updates;
443   st.updates = s;
444   return s;
445 }
446 
447 D_Sym *
448 update_D_Sym(D_Sym *sym, D_Scope **pst, int sizeof_D_Sym) {
449   *pst = enter_D_Scope(*pst, *pst);
450   return update_additional_D_Sym(*pst, sym, sizeof_D_Sym);
451 }
452 
453 void
454 print_sym(D_Sym *s) {
455   logf("%s, ", s.name);
456 }
457 
458 void
459 print_scope(D_Scope *st) {
460   printf("SCOPE %p: ", st);
461   printf("  owned: %d, kind: %d, ", st.owned_by_user, st.kind);
462   if (st.ll) printf("  LL\n");
463   if (st.hash) printf("  HASH\n");
464   if (st.hash) {
465     int i;
466     for (i = 0; i < st.hash.syms.n; i++)
467       if (st.hash.syms.v[i])
468 	print_sym(st.hash.syms.v[i]);
469   } else {
470     D_Sym *ll = st.ll;
471     while (ll) {
472       print_sym(ll);
473       ll = ll.next;
474     }
475   }
476   printf("\n\n");
477   if (st.dynamic) print_scope(st.dynamic);
478   if (st.search) print_scope(st.search);
479 }