Skip to content

Commit 9e11760

Browse files
asarhaddonkanaka
authored andcommitted
c.2: use a hashtable for special symbols
instead of repeated string comparisons
1 parent b96d2a3 commit 9e11760

File tree

10 files changed

+307
-412
lines changed

10 files changed

+307
-412
lines changed

impls/c.2/hashmap.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct map {
4040
size_t size;
4141
struct bucket {
4242
MalType key;
43-
MalType value;
43+
void* value;
4444
} buckets[];
4545
};
4646

@@ -102,7 +102,7 @@ size_t search(hashmap map, MalType key) {
102102
return index;
103103
}
104104

105-
void put(struct map* map, MalType key, MalType value) {
105+
void put(struct map* map, MalType key, void* value) {
106106
size_t i = search(map, key);
107107
if (!map->buckets[i].key) {
108108
map->used++;
@@ -112,7 +112,8 @@ void put(struct map* map, MalType key, MalType value) {
112112
map->buckets[i].value = value;
113113
}
114114

115-
struct map* hashmap_put(struct map* map, MalType key, MalType value) {
115+
struct map* hashmap_put(struct map* map, MalType key, void* value) {
116+
assert(value);
116117
if (map->size <= 2 * (map->used + 1)) {
117118
// Reallocate.
118119
size_t size = map->size * GROW_FACTOR;
@@ -130,7 +131,7 @@ struct map* hashmap_put(struct map* map, MalType key, MalType value) {
130131
return map;
131132
}
132133

133-
inline MalType hashmap_get(hashmap map, MalType key) {
134+
inline void* hashmap_get(hashmap map, MalType key) {
134135
return map->buckets[search(map, key)].value; // may be null
135136
}
136137

@@ -168,7 +169,7 @@ inline MalType map_key(hashmap map, map_cursor position) {
168169
return map->buckets[position].key;
169170
}
170171

171-
inline MalType map_val(hashmap map, map_cursor position) {
172+
inline void* map_val(hashmap map, map_cursor position) {
172173
assert(position < map->size);
173174
assert(map->buckets[position].key);
174175
assert(map->buckets[position].value);

impls/c.2/hashmap.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ struct map* map_empty();
1212

1313
struct map* map_copy(hashmap);
1414

15-
struct map* hashmap_put(struct map* map, MalType key, MalType value);
15+
struct map* hashmap_put(struct map* map, MalType key, void* value);
16+
// Value must not be NULL.
1617
// May reallocate.
1718

18-
MalType hashmap_get(hashmap map, MalType key);
19+
void* hashmap_get(hashmap map, MalType key);
1920
// Returns NULL if the map does not contain the key.
2021

2122
void map_dissoc_mutate(struct map* map, MalType key);
@@ -30,6 +31,6 @@ map_cursor map_iter(hashmap);
3031
bool map_cont(hashmap, map_cursor);
3132
map_cursor map_next(hashmap, map_cursor);
3233
MalType map_key(hashmap, map_cursor);
33-
MalType map_val(hashmap, map_cursor);
34+
void* map_val(hashmap, map_cursor);
3435

3536
#endif

impls/c.2/step3_env.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ MalType evaluate_hashmap(hashmap lst, Env* env);
2121
MalType eval_defbang(list, Env*);
2222
MalType eval_letstar(list, Env*);
2323

24+
typedef MalType (*special_t)(list, Env*);
25+
struct map* specials;
26+
2427
#define generic_arithmetic(name, op, iconst, fconst) \
2528
MalType name(list args) { \
2629
explode2(#op, args, a1, a2); \
@@ -87,14 +90,12 @@ MalType EVAL(MalType ast, Env* env) {
8790
lst = lst->next;
8891

8992
/* handle special symbols first */
90-
if (equal_forms(first, SYMBOL_DEF)) {
91-
return eval_defbang(lst, env);
92-
// Implicit error propagation
93-
}
94-
else if (equal_forms(first, SYMBOL_LET)) {
95-
return eval_letstar(lst, env);
96-
// Implicit error propagation
93+
if (type(first) & MALTYPE_SYMBOL) {
94+
special_t special = hashmap_get(specials, first);
95+
if (special) {
96+
return special(lst, env);
9797
}
98+
}
9899

99100
/* first element is not a special symbol */
100101
MalType func = EVAL(first, env);
@@ -134,6 +135,10 @@ int main() {
134135
types_init();
135136
printer_init();
136137

138+
specials = map_empty();
139+
specials = hashmap_put(specials, SYMBOL_DEF, eval_defbang);
140+
specials = hashmap_put(specials, SYMBOL_LET, eval_letstar);
141+
137142
Env* repl_env = env_make(NULL);
138143

139144
env_set(repl_env, make_symbol("+"), make_function(mal_add));

impls/c.2/step4_if_fn_do.c

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ MalType eval_if(list, Env*);
2525
MalType eval_fnstar(list, const Env*);
2626
MalType eval_do(list, Env*);
2727

28+
typedef MalType (*special_t)(list, Env*);
29+
struct map* specials;
30+
2831
MalType READ(const char* str) {
2932

3033
return read_str(str);
@@ -43,7 +46,7 @@ Env* env_apply(MalClosure closure, list args) {
4346
while (true) {
4447
if (!seq_cont(params, c)) {
4548
if (a) {
46-
make_error("'apply': expected [%M], got [%N]", params, args);
49+
make_error("'apply': expected %M, got [%N]", params, args);
4750
}
4851
break;
4952
}
@@ -55,7 +58,7 @@ Env* env_apply(MalClosure closure, list args) {
5558
break;
5659
}
5760
if (!a) {
58-
make_error("'apply': expected [%M], got [%N]", params, args);
61+
make_error("'apply': expected %M, got [%N]", params, args);
5962
}
6063
env_set(fn_env, parameter, a->data);
6164
c = seq_next(params, c);
@@ -102,26 +105,12 @@ MalType EVAL(MalType ast, Env* env) {
102105
lst = lst->next;
103106

104107
/* handle special symbols first */
105-
if (equal_forms(first, SYMBOL_DEF)) {
106-
return eval_defbang(lst, env);
107-
// Implicit error propagation
108-
}
109-
else if (equal_forms(first, SYMBOL_LET)) {
110-
return eval_letstar(lst, env);
111-
// Implicit error propagation
112-
}
113-
else if (equal_forms(first, SYMBOL_IF)) {
114-
return eval_if(lst, env);
115-
// Implicit error propagation
116-
}
117-
else if (equal_forms(first, SYMBOL_FN)) {
118-
return eval_fnstar(lst, env);
119-
// Implicit error propagation
120-
}
121-
else if (equal_forms(first, SYMBOL_DO)) {
122-
return eval_do(lst, env);
123-
// Implicit error propagation
108+
if (type(first) & MALTYPE_SYMBOL) {
109+
special_t special = hashmap_get(specials, first);
110+
if (special) {
111+
return special(lst, env);
124112
}
113+
}
125114

126115
/* first element is not a special symbol */
127116
MalType func = EVAL(first, env);
@@ -183,6 +172,13 @@ int main() {
183172
types_init();
184173
printer_init();
185174

175+
specials = map_empty();
176+
specials = hashmap_put(specials, SYMBOL_DEF, eval_defbang);
177+
specials = hashmap_put(specials, SYMBOL_LET, eval_letstar);
178+
specials = hashmap_put(specials, SYMBOL_IF, eval_if);
179+
specials = hashmap_put(specials, SYMBOL_FN, eval_fnstar);
180+
specials = hashmap_put(specials, SYMBOL_DO, eval_do);
181+
186182
Env* repl_env = env_make(NULL);
187183

188184
ns core;

impls/c.2/step5_tco.c

Lines changed: 37 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@ MalType apply(MalType, list); // For the apply phase and core apply/map/swap.
1919
list evaluate_list(list, Env*);
2020
MalType evaluate_vector(vector_t, Env*);
2121
MalType evaluate_hashmap(hashmap lst, Env* env);
22-
MalType eval_defbang(list, Env*);
23-
MalType eval_letstar(list, Env**); // TCO
24-
MalType eval_if(list, Env*); // TCO (even for nil)
25-
MalType eval_fnstar(list, const Env*);
26-
MalType eval_do(list, Env*); // TCO in the same env
22+
MalType eval_defbang(list, Env**);
23+
MalType eval_letstar(list, Env**);
24+
MalType eval_if(list, Env**);
25+
MalType eval_fnstar(list, Env**);
26+
MalType eval_do(list, Env**);
27+
28+
typedef MalType (*special_t)(list, Env**);
29+
struct map* specials;
2730

2831
MalType READ(const char* str) {
2932

@@ -43,7 +46,7 @@ Env* env_apply(MalClosure closure, list args) {
4346
while (true) {
4447
if (!seq_cont(params, c)) {
4548
if (a) {
46-
make_error("'apply': expected [%M], got [%N]", params, args);
49+
make_error("'apply': expected %M, got [%N]", params, args);
4750
}
4851
break;
4952
}
@@ -55,7 +58,7 @@ Env* env_apply(MalClosure closure, list args) {
5558
break;
5659
}
5760
if (!a) {
58-
make_error("'apply': expected [%M], got [%N]", params, args);
61+
make_error("'apply': expected %M, got [%N]", params, args);
5962
}
6063
env_set(fn_env, parameter, a->data);
6164
c = seq_next(params, c);
@@ -105,38 +108,16 @@ MalType EVAL(MalType ast, Env* env) {
105108
lst = lst->next;
106109

107110
/* handle special symbols first */
108-
if (equal_forms(first, SYMBOL_DEF)) {
109-
return eval_defbang(lst, env);
110-
// Implicit error propagation
111-
}
112-
else if (equal_forms(first, SYMBOL_LET)) {
113-
114-
/* TCE - modify ast and env directly and jump back to eval */
115-
ast = eval_letstar(lst, &env);
116-
117-
if (mal_error) { return NULL; }
118-
goto TCE_entry_point;
119-
}
120-
else if (equal_forms(first, SYMBOL_IF)) {
121-
122-
/* TCE - modify ast directly and jump back to eval */
123-
ast = eval_if(lst, env);
124-
125-
if (mal_error) { return NULL; }
126-
goto TCE_entry_point;
127-
}
128-
else if (equal_forms(first, SYMBOL_FN)) {
129-
return eval_fnstar(lst, env);
130-
// Implicit error propagation
131-
}
132-
else if (equal_forms(first, SYMBOL_DO)) {
133-
134-
/* TCE - modify ast and env directly and jump back to eval */
135-
ast = eval_do(lst, env);
111+
if (type(first) & MALTYPE_SYMBOL) {
112+
special_t special = hashmap_get(specials, first);
113+
if (special) {
114+
ast = special(lst, &env);
115+
if (mal_error) return NULL;
136116

137-
if (mal_error) { return NULL; }
117+
if(!env) { return ast; }
138118
goto TCE_entry_point;
139119
}
120+
}
140121

141122
/* first element is not a special symbol */
142123
MalType func = EVAL(first, env);
@@ -201,6 +182,13 @@ int main() {
201182
types_init();
202183
printer_init();
203184

185+
specials = map_empty();
186+
specials = hashmap_put(specials, SYMBOL_DEF, eval_defbang);
187+
specials = hashmap_put(specials, SYMBOL_LET, eval_letstar);
188+
specials = hashmap_put(specials, SYMBOL_IF, eval_if);
189+
specials = hashmap_put(specials, SYMBOL_FN, eval_fnstar);
190+
specials = hashmap_put(specials, SYMBOL_DO, eval_do);
191+
204192
Env* repl_env = env_make(NULL);
205193

206194
ns core;
@@ -229,16 +217,17 @@ int main() {
229217
return EXIT_SUCCESS;
230218
}
231219

232-
MalType eval_defbang(list lst, Env* env) {
220+
MalType eval_defbang(list lst, Env** env) {
233221

234222
explode2("def!", lst, defbang_symbol, defbang_value);
235223

236-
MalType result = EVAL(defbang_value, env);
224+
MalType result = EVAL(defbang_value, *env);
237225
if (mal_error) {
238226
return NULL;
239227
}
240228
check_type("def!", MALTYPE_SYMBOL, defbang_symbol);
241-
env_set(env, defbang_symbol, result);
229+
env_set(*env, defbang_symbol, result);
230+
*env = NULL; // no TCO
242231
return result;
243232
}
244233

@@ -276,7 +265,7 @@ MalType eval_letstar(list lst, Env** env) {
276265
return forms;
277266
}
278267

279-
MalType eval_if(list lst, Env* env) {
268+
MalType eval_if(list lst, Env** env) {
280269

281270
if (!lst) {
282271
bad_arg_count("if", "two or three arguments", lst);
@@ -299,7 +288,7 @@ MalType eval_if(list lst, Env* env) {
299288
else_form = NULL;
300289
}
301290

302-
MalType condition = EVAL(raw_condition, env);
291+
MalType condition = EVAL(raw_condition, *env);
303292

304293
if (mal_error) {
305294
return NULL;
@@ -312,6 +301,7 @@ MalType eval_if(list lst, Env* env) {
312301
return else_form;
313302
}
314303
else {
304+
*env = NULL; // no TCO
315305
return make_nil();
316306
}
317307

@@ -320,7 +310,7 @@ MalType eval_if(list lst, Env* env) {
320310
}
321311
}
322312

323-
MalType eval_do(list lst, Env* env) {
313+
MalType eval_do(list lst, Env** env) {
324314

325315
/* handle empty 'do' */
326316
if (!lst) {
@@ -330,7 +320,7 @@ MalType eval_do(list lst, Env* env) {
330320
/* evaluate all but the last form */
331321
while (lst->next) {
332322

333-
EVAL(lst->data, env);
323+
EVAL(lst->data, *env);
334324

335325
/* return error early */
336326
if (mal_error) {
@@ -385,7 +375,7 @@ MalType evaluate_hashmap(hashmap lst, Env* env) {
385375
return make_hashmap(evlst);
386376
}
387377

388-
MalType eval_fnstar(list lst, const Env* env) {
378+
MalType eval_fnstar(list lst, Env** env) {
389379

390380
if (!lst || !lst->next || lst->next->next) {
391381
bad_arg_count("fn*", "two parameters", lst);
@@ -419,8 +409,9 @@ MalType eval_fnstar(list lst, const Env* env) {
419409
break;
420410
}
421411
}
422-
423-
return make_closure(env, lst);
412+
Env* fn_env = *env;
413+
*env = NULL; // no TCO
414+
return make_closure(fn_env, lst);
424415
}
425416

426417
/* used by core functions but not EVAL as doesn't do TCE */

0 commit comments

Comments
 (0)