Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/gravity
Path: blob/master/src/compiler/gravity_symboltable.c
1214 views
1
//
2
// gravity_symboltable.c
3
// gravity
4
//
5
// Created by Marco Bambini on 12/09/14.
6
// Copyright (c) 2014 CreoLabs. All rights reserved.
7
//
8
9
#include "gravity_symboltable.h"
10
#include "gravity_macros.h"
11
#include "gravity_array.h"
12
#include "gravity_hash.h"
13
14
// symbol table implementation using a stack of hash tables
15
typedef marray_t(gravity_hash_t*) ghash_r;
16
17
#define scope_stack_init(r) marray_init(*r)
18
#define scope_stack_size(r) marray_size(*r)
19
#define scope_stack_get(r,n) marray_get(*r,n)
20
#define scope_stack_free(r) marray_destroy(*r)
21
#define scope_stack_push(r,hash) marray_push(gravity_hash_t*,*r,hash)
22
#define scope_stack_pop(r) (marray_size(*r) ? marray_pop(*r) : NULL)
23
24
#define VALUE_FROM_NODE(x) ((gravity_value_t){.isa = NULL, .p = (gravity_object_t *)(x)})
25
#define VALUE_AS_NODE(x) ((gnode_t *)VALUE_AS_OBJECT(x))
26
27
// MARK: -
28
29
struct symboltable_t {
30
ghash_r *stack;
31
uint32_t counter;
32
};
33
34
// MARK: -
35
36
static void check_upvalue_inscope (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data) {
37
#pragma unused(hashtable, key)
38
39
uint32_t index = *(uint32_t *)data;
40
gnode_t *node = VALUE_AS_NODE(value);
41
if (NODE_ISA(node, NODE_VARIABLE)) {
42
gnode_var_t *var = (gnode_var_t *)node;
43
if (var->upvalue) {
44
if ((index == UINT32_MAX) || (var->index < index)) *(uint32_t *)data = var->index;
45
}
46
}
47
}
48
49
// MARK: -
50
51
static void symboltable_hash_free (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data) {
52
#pragma unused(hashtable, value, data)
53
// free key only because node is usually retained by other objects and freed in other points
54
gravity_value_free(NULL, key);
55
}
56
57
static void symboltable_keyvalue_free (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data) {
58
#pragma unused(hashtable, data)
59
// in enum nodes are retained by the symboltable
60
gnode_t *node = VALUE_AS_NODE(value);
61
gnode_free(node);
62
gravity_value_free(NULL, key);
63
}
64
65
symboltable_t *symboltable_create (bool is_enum) {
66
symboltable_t *table = mem_alloc(sizeof(symboltable_t));
67
gravity_hash_t *hash = gravity_hash_create(0, gravity_value_hash, gravity_value_equals,
68
(is_enum) ? symboltable_keyvalue_free : symboltable_hash_free, NULL);
69
if (!table) return NULL;
70
71
// init symbol table
72
table->counter = 0;
73
table->stack = mem_alloc(sizeof(ghash_r));
74
scope_stack_init(table->stack);
75
scope_stack_push(table->stack, hash);
76
77
return table;
78
}
79
80
void symboltable_free (symboltable_t *table) {
81
size_t i, n = scope_stack_size(table->stack);
82
83
for (i=0; i<n; ++i) {
84
gravity_hash_t *h = scope_stack_get(table->stack, i);
85
gravity_hash_free(h);
86
}
87
88
if (table->stack) {
89
scope_stack_free(table->stack);
90
mem_free(table->stack);
91
}
92
93
mem_free(table);
94
}
95
96
bool symboltable_insert (symboltable_t *table, const char *identifier, gnode_t *node) {
97
size_t n = scope_stack_size(table->stack);
98
gravity_hash_t *h = scope_stack_get(table->stack, n-1);
99
100
// insert node with key identifier into hash table (and check if already exists in current scope)
101
gravity_value_t key = VALUE_FROM_CSTRING(NULL, identifier);
102
if (gravity_hash_lookup(h, key) != NULL) {
103
gravity_value_free(NULL, key);
104
return false;
105
}
106
gravity_hash_insert(h, key, VALUE_FROM_NODE(node));
107
108
++table->counter;
109
return true;
110
}
111
112
gnode_t *symboltable_lookup (symboltable_t *table, const char *identifier) {
113
STATICVALUE_FROM_STRING(key, identifier, strlen(identifier));
114
115
size_t n = scope_stack_size(table->stack);
116
for (int i=(int)n-1; i>=0; --i) {
117
gravity_hash_t *h = scope_stack_get(table->stack, i);
118
gravity_value_t *v = gravity_hash_lookup(h, key);
119
if (v) return VALUE_AS_NODE(*v);
120
}
121
122
return NULL;
123
}
124
125
uint32_t symboltable_count (symboltable_t *table, uint32_t index) {
126
gravity_hash_t *h = scope_stack_get(table->stack, index);
127
return gravity_hash_count(h);
128
}
129
130
// MARK: -
131
132
gnode_t *symboltable_global_lookup (symboltable_t *table, const char *identifier) {
133
gravity_hash_t *h = scope_stack_get(table->stack, 0);
134
STATICVALUE_FROM_STRING(key, identifier, strlen(identifier));
135
136
gravity_value_t *v = gravity_hash_lookup(h, key);
137
return (v) ? VALUE_AS_NODE(*v) : NULL;
138
}
139
140
void symboltable_enter_scope (symboltable_t *table) {
141
gravity_hash_t *h = gravity_hash_create(0, gravity_value_hash, gravity_value_equals, symboltable_hash_free, NULL);
142
scope_stack_push(table->stack, h);
143
}
144
145
uint32_t symboltable_local_index (symboltable_t *table) {
146
return table->counter - 1;
147
}
148
149
uint32_t symboltable_exit_scope (symboltable_t *table, uint32_t *nlevel) {
150
gravity_hash_t *h = (gravity_hash_t *)scope_stack_pop(table->stack);
151
if (nlevel) {
152
*nlevel = UINT32_MAX;
153
gravity_hash_iterate(h, check_upvalue_inscope, (void *)nlevel);
154
}
155
gravity_hash_free(h);
156
return table->counter;
157
}
158
159
void symboltable_dump (symboltable_t *table) {
160
size_t n = scope_stack_size(table->stack);
161
162
for (int i=(int)n-1; i>=0; --i) {
163
gravity_hash_t *h = (gravity_hash_t *)scope_stack_get(table->stack, i);
164
gravity_hash_dump(h);
165
}
166
}
167
168