From d38ae947933fe26773a810d91fba3b23766d4d92 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 13 Oct 2021 20:46:26 +0200 Subject: Add set! and eval procedures --- src/bootstrap/environment.c | 13 +++------ src/bootstrap/main.c | 2 ++ src/bootstrap/primitives.c | 68 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/environment.c b/src/bootstrap/environment.c index d4e9f86..99dd7fd 100644 --- a/src/bootstrap/environment.c +++ b/src/bootstrap/environment.c @@ -60,18 +60,13 @@ env_lookup(Environment *env, Object *symbol) { return obj_err; } -void -env_update_symbol(Environment *env, Object *symbol, Object *value) { - // Try to find an existing symbol in the current environment. +ssize_t +env_symbol_index_in_current_env(Environment *env, Object *symbol) { for (size_t i = 0; i < env->size; i++) { EnvEntry entry = env->buf[i]; if (obj_eq(symbol, entry.symbol)) { - env->buf[i].value = value; - return; + return i; } } - // If we don't find the symbol, add a new entry. - env_add_symbol(env, symbol, value); + return -1; } - -// TODO: Free env function. diff --git a/src/bootstrap/main.c b/src/bootstrap/main.c index e8e530d..052f1c0 100755 --- a/src/bootstrap/main.c +++ b/src/bootstrap/main.c @@ -40,6 +40,7 @@ init(void) { MAKE_ENV_VAR(global_env, "nil", obj_nil); // Primitive procedures. + MAKE_ENV_PROC(global_env, "eval", proc_eval); MAKE_ENV_PROC(global_env, "quote", proc_quote); MAKE_ENV_PROC(global_env, "car", proc_car); MAKE_ENV_PROC(global_env, "cdr", proc_cdr); @@ -72,6 +73,7 @@ init(void) { MAKE_ENV_PROC(global_env, "=", proc_num_equal); MAKE_ENV_PROC(global_env, "eq?", proc_equal); MAKE_ENV_PROC(global_env, "def", proc_define); + MAKE_ENV_PROC(global_env, "set!", proc_set); } void diff --git a/src/bootstrap/primitives.c b/src/bootstrap/primitives.c index af8e9da..a3b69f6 100644 --- a/src/bootstrap/primitives.c +++ b/src/bootstrap/primitives.c @@ -630,15 +630,75 @@ proc_define(Environment *env, Object *obj) { } // Make a copy of the symbol and to make them permanent in the environment. - env_update_symbol(env, obj_duplicate(symbol), obj_duplicate(value)); + ssize_t index = env_symbol_index_in_current_env(env, symbol); + if (index == -1) { + env_add_symbol(env, obj_duplicate(symbol), obj_duplicate(value)); + } else { + env->buf[index].value = obj_duplicate(value); + } + return obj_nil; +} + +Object * +proc_set(Environment *env, Object *obj) { + if (obj == obj_nil || obj->cdr == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + + Object *symbol = obj->car; + if (symbol->type != OBJ_TYPE_SYMBOL) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_WRONG_ARG_TYPE, + }); + return obj_err; + } + + Object *value = eval(env, obj->cdr->car); + if (value == obj_err) { + return obj_err; + } + + ssize_t index = env_symbol_index_in_current_env(env, symbol); + if (index == -1) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_SYMBOL_NOT_FOUND, + }); + return obj_err; + } + + env->buf[index].value = obj_duplicate(value); return obj_nil; } + +// +// Evaluation. +// + +Object * +proc_eval(Environment *env, Object *obj) { + if (obj == obj_nil) { + error_push((Error){ + .type = ERR_TYPE_RUNTIME, + .value = ERR_NOT_ENOUGH_ARGS, + }); + return obj_err; + } + return eval(env, eval(env, obj->car)); +} + +// TODO: map +// TODO: apply +// TODO: filter + // TODO: fixnum left/right shift, mask, invert // TODO: add primitives for type transforms: string->symbol, symbol->string, etc // TODO: implement support for semi-quotes // TODO: LAMBDA // TODO: let -// TODO: Revise all instances where we are returning an object, since currently -// we may be returning a pointer to an object instead of a new one. Check also -// on eval function and everytime we do make_xxx(obj). -- cgit v1.2.1