// selfhost/cmd/wcc/sym.ww — port of cmd/wcc/sym.c. // // Per-scope hashtable, chained to the parent. Lookup walks up. // Plan 9 / Hare flavoured. Duplicate definitions in the same scope // return nil; the caller flags the error. use mem; use typ; use ast; // Symbol kinds — must stay numerically aligned with cmd/wcc/ww.h Skind. def SK_NONE: i32 = 0; def SK_VAR: i32 = 1; def SK_PARAM: i32 = 2; def SK_DEF: i32 = 3; def SK_TYPE: i32 = 4; def SK_FN: i32 = 5; def SK_USE: i32 = 6; def SK_FIELD: i32 = 7; type sym = struct { name: str, skind: i32, type_: *tinfo, decl: *node, exported: i32, snext: *sym, // iteration order hashnext: *sym, // hash bucket chain scope: *scope, }; def NBUCKETS: i32 = 16; type scope = struct { parent: *scope, first: *sym, last: *sym, buckets: **sym, // length = NBUCKETS nbuckets: i32, a: *arena, }; // FNV-1a 64 — same hash the C side uses, so bucket distribution is // identical when both walk a scope in declaration order. fn hashstr(s: str) u64 = { let h: u64 = 14695981039346656037u64; let i: i32 = 0; for (i < s.len) { let c: u8 = s[i]; h = h ^ (c: u64); h = h * 1099511628211u64; i += 1; }; return h; }; export fn newscope(a: *arena, parent: *scope) *scope = { let s: *scope = amalloc(a, 64u64): *scope; s.parent = parent; s.a = a; s.nbuckets = NBUCKETS; s.buckets = amalloc(a, (NBUCKETS: u64) * 8u64): **sym; return s; }; export fn streq(a: str, b: str) bool = { if (a.len != b.len) { return false; }; let i: i32 = 0; for (i < a.len) { if (a[i] != b[i]) { return false; }; i += 1; }; return true; }; export fn scopelookuplocal(s: *scope, name: str) *sym = { if (s == nil) { return nil; }; let h: u64 = hashstr(name); let bi: i32 = (h % (s.nbuckets: u64)): i32; let b: *sym = s.buckets[bi]; for (b != nil) { let bn: str = b.name; if (streq(bn, name)) { return b; }; b = b.hashnext; }; return nil; }; export fn scopelookup(s: *scope, name: str) *sym = { for (s != nil) { let r: *sym = scopelookuplocal(s, name); if (r != nil) { return r; }; s = s.parent; }; return nil; }; export fn scopedefine(s: *scope, name: str, k: i32, t: *tinfo, decl: *node) *sym = { if (scopelookuplocal(s, name) != nil) { return nil; }; let sy: *sym = amalloc(s.a, 80u64): *sym; sy.name = name; sy.skind = k; sy.type_ = t; sy.decl = decl; sy.scope = s; let h: u64 = hashstr(name); let bi: i32 = (h % (s.nbuckets: u64)): i32; sy.hashnext = s.buckets[bi]; s.buckets[bi] = sy; if (s.first == nil) { s.first = sy; } else { s.last.snext = sy; }; s.last = sy; return sy; };