All: split types into types, env, printer, core.
[jackhill/mal.git] / c / env.c
1 /*
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <string.h>
5 */
6 #include <stdlib.h>
7 #include "types.h"
8
9 // Env
10
11 Env *new_env(Env *outer, MalVal* binds, MalVal *exprs) {
12 Env *e = malloc(sizeof(Env));
13 e->table = g_hash_table_new(g_str_hash, g_str_equal);
14 e->outer = outer;
15
16 if (binds && exprs) {
17 assert_type(binds, MAL_LIST|MAL_VECTOR,
18 "new_env called with non-sequential bindings");
19 assert_type(exprs, MAL_LIST|MAL_VECTOR,
20 "new_env called with non-sequential expressions");
21 int binds_len = _count(binds),
22 exprs_len = _count(exprs),
23 varargs = 0, i;
24 for (i=0; i<binds_len; i++) {
25 if (i > exprs_len) { break; }
26 if (_nth(binds, i)->val.string[0] == '&') {
27 varargs = 1;
28 env_set(e, _nth(binds, i+1)->val.string, _slice(exprs, i, _count(exprs)));
29 break;
30 } else {
31 env_set(e, _nth(binds, i)->val.string, _nth(exprs, i));
32 }
33 }
34 assert(varargs || (binds_len == exprs_len),
35 "Arity mismatch: %d formal params vs %d actual params",
36 binds_len, exprs_len);
37
38 }
39 return e;
40 }
41
42 Env *env_find(Env *env, char *key) {
43 void *val = g_hash_table_lookup(env->table, key);
44 if (val) {
45 return env;
46 } else if (env->outer) {
47 return env_find(env->outer, key);
48 } else {
49 return NULL;
50 }
51 }
52
53 MalVal *env_get(Env *env, char *key) {
54 Env *e = env_find(env, key);
55 assert(e, "'%s' not found", key);
56 return g_hash_table_lookup(e->table, key);
57 }
58
59 Env *env_set(Env *env, char *key, MalVal *val) {
60 g_hash_table_insert(env->table, key, val);
61 return env;
62 }