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
|
import "cffc.hff";
import "map.hff";
import "util.hff";
import "common.hff";
struct StringKeyTraits {
fn hash(s *const u8) u32 { return fnv1a_s(FNV1A_INI, s); }
fn eq(a *const u8, b *const u8) bool { return streq(a, b); }
}
struct Env {
parent *Env,
alloc *Allocator,
decls Map<*const u8, *DeclList, StringKeyTraits>,
}
extern fn mkenv(parent *Env, alloc *Allocator) *Env {
let env *Env = xmalloc(sizeof Env);
*env = { parent, alloc };
return env;
}
extern fn envparent(env *Env) *Env {
return env.parent;
}
extern fn envput_alloc(env *Env, alloc *Allocator, decl Decl, old **const Decl) *Decl {
let l **DeclList = env.decls->get_slot(decl.name);
let n *DeclList = anew(alloc, DeclList);
if *l { // decl with this name exists
let old = (*old = &(*l).decl);
switch {
case old.u.#tag == :Fn and decl.u.#tag == :Fn
and decl.u.Fn.ty == old.u.Fn.ty and (old.u.Fn.body->empty() or decl.u.Fn.body->empty());
decl.u.Fn.id = old.u.Fn.id;
case old.u.#tag == :Ty and decl.u.#tag == :Ty and old.u.Ty == decl.u.Ty;
case old.u.#tag == :Def and decl.u.#tag == :Def
and memcmp(&old.u.Def, &decl.u.Def, sizeof(old.u.Def)) == 0;
case old.u.#tag == :Static and decl.u.#tag == :Static
and memcmp(&old.u.Static, &decl.u.Static, sizeof(old.u.Static)) == 0;
case old.u.#tag == :Macro and decl.u.#tag == :Macro
and memcmp(&old.u.Macro, &decl.u.Macro, sizeof(old.u.Macro)) == 0;
case decl.u.#tag == :Let;
case env != old.myenv;
case else;
return #null;
}
}
n.link = *l;
n.decl = decl;
n.decl.myenv = env;
*l = n;
return &n.decl;
}
extern fn envput(env *Env, decl Decl, old **const Decl) *Decl {
return envput_alloc(env, env.alloc, decl, old);
}
extern fn envfind(env *Env, name *const u8) *Decl {
let l **DeclList = env.decls->get(name);
if l == #null {
if env.parent == #null {
return #null;
}
return envfind(env.parent, name);
}
let l = *l;
assert(l != #null, "l?");
return &l.decl;
}
extern fn envfind_noparent(env *Env, name *const u8) *Decl {
let l **DeclList = env.decls->get(name);
return l ? &(*l).decl : #null;
}
extern fn envfree(env *Env) void {
env.decls->clear();
free(env);
}
|