#include "env.h" #include #include #include #include "pebblisp.h" Object fetchFromEnvironment(const char* name, struct Environment* env) { if (!env) { return errorObject(NULL_ENV); } if (env->size == 0) { if (env->outer) { return fetchFromEnvironment(name, env->outer); } else { return errorObject(EMPTY_ENV); } } for (int i = 0; i < env->size; i++) { if (env->strings[i] == NULL) { printd("Try %d (NULL)\n", i); break; } printd("Try %d (%s)\n", i, env->strings[i]); debugObj(&env->objects[i]); if (strcmp(name, env->strings[i]) == 0) { printd("Returning!\n"); return cloneObject(env->objects[i]); } } printd("Trying outer %p\n", env->outer); if (env->outer) { return fetchFromEnvironment(name, env->outer); } return errorWithContext(DID_NOT_FIND_SYMBOL, name); } struct Environment envForLambda(const Object* params, const Object* arg_forms, struct Environment* outer) { int paramCount = listLength(params); struct Environment env = {.outer = outer, .strings = NULL, .objects = NULL, .structCount = 0, .size = paramCount}; if (paramCount == 0) { return env; } env.strings = calloc(sizeof(char*), paramCount + 1); env.objects = malloc(sizeof(Object) * (paramCount + 1)); const Object* march = arg_forms; for (int i = 0; i < paramCount; i++) { const char* newObjName = itemAt(params, i)->string; // Eval the `march` list Object newEnvObj = eval(march, outer); addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms? cleanObject(&newEnvObj); march = march->forward; } return env; } // Determine if a given symbol exists in the given environment chain // // Modifies `env` to the environment that the symbol was found in, only if the // symbol was found // // Returns the index of the symbol in the environment, if found. Otherwise, -1 int findInEnv(struct Environment** env, const char* name) { struct Environment* temp_env = *env; while (temp_env) { for (int i = 0; i < temp_env->size; i++) { if (temp_env->strings[i] == NULL) { break; } if (strcmp(temp_env->strings[i], name) == 0) { *env = temp_env; return i; } } temp_env = temp_env->outer; } return -1; } // TODO Maybe extend environment using a new outer, instead of realloc void addToEnv(struct Environment* env, const char* name, const Object obj) { // int sym_pos = findInEnv(&env, name); // if(sym_pos != -1) { // Object o = cloneObject(obj); // cleanObject(&env->objects[sym_pos]); // env->objects[sym_pos] = o; // return; // } int i; struct Environment* temp_env = env; int is_local = 1; while (temp_env) { for (i = 0; i < temp_env->size; i++) { // Add *new* item to env only if we're in the local scope if (temp_env->strings[i] == NULL) { if (is_local) { temp_env->strings[i] = calloc(sizeof(char), strlen(name) + 1); strncpy(temp_env->strings[i], name, strlen(name)); temp_env->objects[i] = cloneObject(obj); return; } break; } else if (strcmp(temp_env->strings[i], name) == 0) { Object o = cloneObject(obj); cleanObject(&temp_env->objects[i]); temp_env->objects[i] = o; return; } } temp_env = temp_env->outer; is_local = 0; } printd("Reallocating environment\n"); const int inc = 5; const int old_size = env->size; env->size += inc; env->strings = realloc(env->strings, sizeof(char*) * env->size); env->objects = realloc(env->objects, sizeof(Object) * env->size); for (int j = 0; j < inc; j++) { env->strings[old_size + j] = NULL; } env->strings[old_size] = malloc(strlen(name) + 1); strncpy(env->strings[old_size], name, strlen(name) + 1); env->objects[old_size] = cloneObject(obj); } void printEnv(struct Environment* env) { if (!env) { printf("NULL env\n"); return; } for (int i = 0; i < env->size; i++) { if (env->strings[i] == NULL) { printf("env[%d]: NULL %p\n", i, env->strings[i]); break; } printf("env[%d]: '%s' %p\n", i, env->strings[i], env->strings[i]); printf(" "); printObj(&env->objects[i]); printf(""); } } void addFunc(const char* name, Object (* func)(Object, Object, struct Environment*), struct Environment* env) { Object o = newObject(TYPE_FUNC); o.func = func; addToEnv(env, name, o); } void deleteEnv(struct Environment* e) { if (e->strings) { int i = 0; while (e->strings[i]) { free(e->strings[i]); cleanObject(&e->objects[i]); i++; } free(e->strings); e->strings = NULL; free(e->objects); e->objects = NULL; } } struct symFunc { const char* sym; Object (* func)(Object, Object, struct Environment*); }; struct Environment defaultEnv() { char** strings = calloc(sizeof(char*), MAX_ENV_ELM); Object* objects = malloc(sizeof(Object) * MAX_ENV_ELM); char size = MAX_ENV_ELM; struct Environment e = { .outer = NULL, .strings = strings, .objects = objects, .size = size, .structCount = 0, }; struct symFunc symFuncs[] = { {"+", &add}, {"-", &sub}, {"*", &mul}, {"/", &dvi}, {"%", &mod}, {"=", &equ}, {">", >h}, {"<", <h}, {"&", &and}, {"|", &or}, {"cat", &catObjects}, {"fil", &filter}, {"len", &len}, {"ap", &append}, {"pre", &prepend}, {"at", &at}, {"rest", &rest}, {"chat", &charAt}, #ifndef LOW_MEM {"rev", &reverse}, #endif {"isnum", &isNum}, {"isstr", &isString}, {"iserr", &isErr}, {"char", &charVal}, {"eval", &parseEvalO}, #ifdef STANDALONE {"prn", &print}, {"pch", &pChar}, {"penv", &printEnvO}, //{"sys", &systemCall}, {"loadfile", &loadFile}, {"inp", &takeInput}, #endif }; for (unsigned i = 0; i < sizeof(symFuncs) / sizeof(symFuncs[0]); i++) { addFunc(symFuncs[i].sym, symFuncs[i].func, &e); } return e; }