symtab.c 5.7 KiB raw
1
#include <assert.h>
2
#include <string.h>
3
4
#include "ast.h"
5
#include "io.h"
6
#include "module.h"
7
#include "resolver.h"
8
#include "scanner.h"
9
#include "symtab.h"
10
11
/* Symbol storage across all scopes. */
12
static symbol_t SYMBOLS[MAX_SYMBOLS] = { 0 };
13
static usize    NSYMBOLS             = 0;
14
15
/* Scope storage across all modules/functions. */
16
static scope_t SCOPES[MAX_SCOPES] = { 0 };
17
static usize   NSCOPES            = 0;
18
19
static symkind_t symbol_entry(node_t *n) {
20
    switch (n->cls) {
21
    case NODE_IDENT:
22
    case NODE_VAR:
23
    case NODE_STATIC:
24
    case NODE_PARAM:
25
    case NODE_UNION_VARIANT: /* This should use SYM_VARIANT */
26
    case NODE_RECORD_FIELD:
27
        return SYM_VARIABLE;
28
    case NODE_CONST:
29
        return SYM_CONSTANT;
30
    case NODE_FN:
31
        return SYM_FUNCTION;
32
    case NODE_UNION:
33
    case NODE_RECORD:
34
    case NODE_PTR:
35
        return SYM_TYPE;
36
    case NODE_MOD:
37
    case NODE_USE:
38
        return SYM_MODULE;
39
    case NODE_REF:
40
        return symbol_entry(n->val.ref.target);
41
    case NODE_RETURN:
42
    case NODE_BLOCK:
43
    case NODE_LOOP:
44
    case NODE_WHILE:
45
    case NODE_WHILE_LET:
46
    case NODE_FOR:
47
    case NODE_IF:
48
    case NODE_IF_LET:
49
    case NODE_IF_CASE:
50
    case NODE_GUARD_CASE:
51
    case NODE_GUARD_LET:
52
    case NODE_BINOP:
53
    case NODE_UNOP:
54
    case NODE_TYPE:
55
    case NODE_NUMBER:
56
    case NODE_CHAR:
57
    case NODE_NIL:
58
    case NODE_UNDEF:
59
    case NODE_STRING:
60
    case NODE_BOOL:
61
    case NODE_ASSIGN:
62
    case NODE_CALL:
63
    case NODE_CALL_ARG:
64
    case NODE_BUILTIN:
65
    case NODE_ATTRIBUTE:
66
    case NODE_BREAK:
67
    case NODE_RECORD_TYPE:
68
    case NODE_RECORD_LIT:
69
    case NODE_ARRAY_LIT:
70
    case NODE_ARRAY_REPEAT_LIT:
71
    case NODE_ACCESS:
72
    case NODE_RECORD_LIT_FIELD:
73
    case NODE_EXPR_STMT:
74
    case NODE_ARRAY_INDEX:
75
    case NODE_RANGE:
76
    case NODE_MATCH_CASE:
77
    case NODE_MATCH:
78
    case NODE_SCOPE:
79
    case NODE_MOD_BODY:
80
    case NODE_AS:
81
    case NODE_PLACEHOLDER:
82
    case NODE_ALIGN:
83
    case NODE_THROW:
84
    case NODE_TRY:
85
    case NODE_CATCH:
86
    case NODE_PANIC:
87
    case NODE_SUPER:
88
        break;
89
    }
90
    bail("node of class %d cannot have a symbol table entry", n->cls);
91
}
92
93
/* Allocate a scope. */
94
scope_t *symtab_scope(scope_t *parent, module_t *mod) {
95
    if (NSCOPES >= MAX_SCOPES) {
96
        bail("scope overflow: too many scopes");
97
        return NULL;
98
    }
99
    scope_t *slot = &SCOPES[NSCOPES++];
100
101
    *slot = (scope_t){
102
        .mod      = mod,
103
        .parent   = parent,
104
        .symbols  = { 0 },
105
        .nsymbols = 0,
106
    };
107
    return slot;
108
}
109
110
/* Search for a symbol in the given scope only. */
111
symbol_t *symtab_scope_lookup(
112
    scope_t *s, const char *name, u16 length, symkind_t kind
113
) {
114
    for (usize i = 0; i < s->nsymbols; i++) {
115
        symbol_t *sym = s->symbols[i];
116
117
        if ((kind == SYM_ANY || sym->kind == kind) && sym->length == length &&
118
            memcmp(sym->name, name, length) == 0) {
119
            return sym;
120
        }
121
    }
122
    return NULL;
123
}
124
125
/* Search for a symbol from the current to the top-level scope. */
126
symbol_t *symtab_lookup(
127
    scope_t *s, const char *name, u16 length, symkind_t kind
128
) {
129
    for (scope_t *scope = s; scope != NULL; scope = scope->parent) {
130
        symbol_t *sym = NULL;
131
132
        if ((sym = symtab_scope_lookup(scope, name, length, kind)))
133
            return sym;
134
    }
135
    return NULL;
136
}
137
138
/* Add a symbol to the current scope. */
139
bool symtab_add_ident(scope_t *s, node_t *ident, node_t *n) {
140
    symkind_t   kind   = symbol_entry(n);
141
    const char *name   = ident->val.ident.name;
142
    u16         length = ident->val.ident.length;
143
144
    if (symtab_scope_lookup(s, name, length, kind))
145
        return false; /* Variable already defined in this scope. */
146
147
    symbol_t *sym = alloc_symbol((symbol_t){
148
        .name   = name,
149
        .length = length,
150
        .node   = n,
151
        .kind   = kind,
152
        .scope  = s,
153
    });
154
155
    /* Nb. static variables are never exposed. */
156
    if (kind == SYM_FUNCTION || kind == SYM_CONSTANT) {
157
        /* Copy qualified name for top-level symbols */
158
159
        module_path(sym->qualified, s->mod->qualified);
160
        module_qualify_str(sym->qualified, sym->name, sym->length);
161
    }
162
    assert(s->nsymbols < MAX_SCOPE_SYMBOLS);
163
    s->symbols[s->nsymbols++] = sym;
164
    n->sym                    = sym;
165
166
    return true;
167
}
168
169
/* Add a symbol to the current scope. */
170
bool symtab_insert(scope_t *s, const char *name, u16 length, node_t *n) {
171
    symkind_t kind = symbol_entry(n);
172
173
    if (symtab_lookup(s, name, length, kind)) {
174
        return false;
175
    }
176
    symbol_t *sym = alloc_symbol((symbol_t){
177
        .name   = name,
178
        .length = length,
179
        .node   = n,
180
        .kind   = kind,
181
    });
182
183
    assert(s->nsymbols < MAX_SCOPE_SYMBOLS);
184
    s->symbols[s->nsymbols++] = sym;
185
    n->sym                    = sym;
186
187
    return true;
188
}
189
190
/* Allocate a symbol. */
191
symbol_t *alloc_symbol(symbol_t sym) {
192
    if (NSYMBOLS >= MAX_SYMBOLS) {
193
        bail("symbol table overflow: too many symbols");
194
        return NULL;
195
    }
196
    symbol_t *slot = &SYMBOLS[NSYMBOLS++];
197
    *slot          = sym;
198
199
    strncpy(slot->qualified, slot->name, slot->length);
200
201
    return slot;
202
}
203
204
/* Add an imported symbol as an alias in the current scope. */
205
bool symtab_add_alias(scope_t *s, node_t *ident, symbol_t *original) {
206
    /* Check for conflicts */
207
    if (symtab_scope_lookup(
208
            s, ident->val.ident.name, ident->val.ident.length, original->kind
209
        )) {
210
        return false;
211
    }
212
    /* Create alias that points to the original symbol instead of copying it */
213
    assert(s->nsymbols < MAX_SCOPE_SYMBOLS);
214
    s->symbols[s->nsymbols++] = original;
215
    ident->sym                = original;
216
217
    return true;
218
}
219
220
/* Add a symbol directly to a scope. */
221
void symtab_add_symbol(scope_t *s, symbol_t *sym) {
222
    assert(s->nsymbols < MAX_SCOPE_SYMBOLS);
223
    s->symbols[s->nsymbols++] = sym;
224
}