typedef struct EnvEntry { Object *symbol; Object *value; } EnvEntry; typedef struct Environment { struct Environment *parent; EnvEntry *buf; size_t size; size_t cap; } Environment; static Environment *global_env; #define ENV_BUF_CAP 8 Environment * env_create(Environment *parent) { Environment *env = malloc(sizeof(Environment)); env->parent = parent; env->buf = NULL; env->size = 0; env->cap = ENV_BUF_CAP; return env; } void env_add_symbol(Environment *env, Object *symbol, Object *value) { if (symbol->type != OBJ_TYPE_SYMBOL) { error_push((Error){ .type = ERR_TYPE_RUNTIME, .value = ERR_NOT_A_SYMBOL, .line = 0, .col = 0, }); return; } if (env->buf == NULL) { env->size = 0; env->cap = ENV_BUF_CAP; env->buf = malloc(env->cap * sizeof(EnvEntry)); } else if (env->size == env->cap) { env->cap *= 2; env->buf = realloc(env->buf, env->cap * sizeof(EnvEntry)); } env->buf[env->size++] = (EnvEntry){symbol, value}; } Object * env_lookup(Environment *env, Object *symbol) { while (env != NULL) { for (size_t i = 0; i < env->size; i++) { EnvEntry entry = env->buf[i]; if (obj_eq(symbol, entry.symbol)) { return entry.value; } } env = env->parent; } return obj_err; } Object * env_update(Environment *env, Object *symbol, Object *value) { while (env != NULL) { for (size_t i = 0; i < env->size; i++) { EnvEntry entry = env->buf[i]; if (obj_eq(symbol, entry.symbol)) { env->buf[i].value = obj_duplicate(value); return obj_nil; } } env = env->parent; } error_push((Error){ .type = ERR_TYPE_RUNTIME, .value = ERR_SYMBOL_NOT_FOUND, }); return obj_err; } ssize_t env_index_current(Environment *env, Object *symbol) { for (size_t i = 0; i < env->size; i++) { EnvEntry entry = env->buf[i]; if (obj_eq(symbol, entry.symbol)) { return i; } } return -1; } void env_add_or_update_current(Environment *env, Object *symbol, Object *value) { ssize_t index = env_index_current(env, symbol); if (index == -1) { env_add_symbol(env, obj_duplicate(symbol), obj_duplicate(value)); } else { env->buf[index].value = obj_duplicate(value); } } Environment * env_extend(Environment *parent, Environment *extra) { Environment *env = env_create(parent); for (size_t i = 0; i < extra->size; i++) { EnvEntry entry = extra->buf[i]; Environment *tmp = env; ssize_t idx = -1; while (tmp != NULL) { idx = env_index_current(tmp, entry.symbol); if (idx != -1) { break; } tmp = tmp->parent; } if (idx == -1) { env_add_symbol(env, obj_duplicate(entry.symbol), obj_duplicate(entry.value)); } } return env; }