From faf8a22331cf02a92ea811809bd4037e3db3f90a Mon Sep 17 00:00:00 2001 From: Brandon Rozek Date: Sat, 9 Jun 2018 19:30:24 -0400 Subject: [PATCH] Finished implementing the environment --- lval/environment.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ lval/environment.h | 18 ++++++++++ lval/expressions.c | 42 +++++++++++----------- lval/expressions.h | 23 ++++++------ lval/operations.c | 42 ++++++++++++++++++++-- lval/operations.h | 15 +++++++- prompt.c | 38 ++++++++++---------- 7 files changed, 211 insertions(+), 55 deletions(-) diff --git a/lval/environment.c b/lval/environment.c index ebc513c..86a5b22 100644 --- a/lval/environment.c +++ b/lval/environment.c @@ -1,8 +1,96 @@ #include "environment.h" +#include +#include "error.h" +#include "expressions.h" +#include "operations.h" + +lenv* lenv_new(void) { + lenv* e = (lenv*) malloc(sizeof(lenv)); + e->count = 0; + e->syms = NULL; + e->vals = NULL; + return e; +} + +void lenv_del(lenv* e) { + for (int i = 0; i < e->count; i++) { + free(e->syms[i]); + lval_del(e->vals[i]); + } + free(e->syms); + free(e->vals); + free(e); +} + +lval* lenv_get(lenv* e, lval* k) { + // Iterate over all items in environment + for (int i = 0; i < e->count; i++) { + // Check if the stored string matches the symbol string + // If it does, return a copy of hte value + if (strcmp(e->syms[i], k->sym) == 0) { + return lval_copy(e->vals[i]); + } + } + + // If no symbol found return error + return lval_err("unbounded symbol!"); +} + +void lenv_put(lenv* e, lval* k, lval* v) { + // Iterate over all items in the environment + // This is to see if the variables already exist + for (int i = 0; i < e->count; i++) { + // If a variable is found, delete the item at that position + // Then replace it with the data provided by the user + if (strcmp(e->syms[i], k->sym) == 0) { + lval_del(e->vals[i]); + e->vals[i] = lval_copy(v); + return; + } + } + + // If no existing entry is found, allocate space for new entry + e->count++; + e->vals = realloc(e->vals, sizeof(lval*) * e->count); + e->syms = realloc(e->syms, sizeof(char*) * e->count); + + // Copy contents of lval and symbol string + e->vals[e->count - 1] = lval_copy(v); + e->syms[e->count - 1] = (char*) malloc(strlen(k->sym) + 1); + strcpy(e->syms[e->count - 1], k->sym); +} lval* lval_fun(lbuiltin func) { lval* v = malloc(sizeof(lval)); v->type = LVAL_FUN; v->fun = func; return v; +} + +void lenv_add_builtin(lenv* e, char* name, lbuiltin func) { + lval* k = lval_sym(name); + lval* v = lval_fun(func); + lenv_put(e, k, v); + lval_del(k); lval_del(v); +} + +void lenv_add_builtins(lenv* e) { + // List functions + lenv_add_builtin(e, "list", builtin_list); + lenv_add_builtin(e, "head", builtin_head); + lenv_add_builtin(e, "tail", builtin_tail); + lenv_add_builtin(e, "eval", builtin_eval); + lenv_add_builtin(e, "join", builtin_join); + lenv_add_builtin(e, "len", builtin_len); + lenv_add_builtin(e, "cons", builtin_cons); + + // Mathematical Functions + lenv_add_builtin(e, "+", builtin_add); + lenv_add_builtin(e, "-", builtin_sub); + lenv_add_builtin(e, "*", builtin_mul); + lenv_add_builtin(e, "/", builtin_div); + lenv_add_builtin(e, "^", builtin_pow); + lenv_add_builtin(e, "%", builtin_mod); + lenv_add_builtin(e, "min", builtin_min); + lenv_add_builtin(e, "max", builtin_max); } \ No newline at end of file diff --git a/lval/environment.h b/lval/environment.h index 5a8eced..6845af3 100644 --- a/lval/environment.h +++ b/lval/environment.h @@ -2,6 +2,24 @@ #define LVAL_ENVIRONMENT #include "base.h" +struct lenv { + int count; + char** syms; + lval** vals; +}; + +lenv* lenv_new(void); +void lenv_del(lenv* e); +// Obtain a variable from the environment +// e is the environment +// k is the symbol +lval* lenv_get(lenv* e, lval* k); +void lenv_put(lenv* e, lval* k, lval* v); + lval* lval_fun(lbuiltin func); +void lenv_add_builtin(lenv* e, char* name, lbuiltin func); +void lenv_add_builtins(lenv* e); + + #endif diff --git a/lval/expressions.c b/lval/expressions.c index 0400984..44d5644 100644 --- a/lval/expressions.c +++ b/lval/expressions.c @@ -54,10 +54,10 @@ lval* lval_take(lval* v, int i) { return x; } -lval* lval_eval_sexpr(lval* v) { +lval* lval_eval_sexpr(lenv* e, lval* v) { // Evaluate children for (int i = 0; i < v->count; i++) { - v->cell[i] = lval_eval(v->cell[i]); + v->cell[i] = lval_eval(e, v->cell[i]); } // Error checking [If there's an error, return it] @@ -73,19 +73,19 @@ lval* lval_eval_sexpr(lval* v) { // Ensure first element is a symbol otherwise lval* f = lval_pop(v, 0); - if (f->type != LVAL_SYM) { - printf("The type of f is %d\n", f->type); + if (f->type != LVAL_FUN) { lval_del(f); lval_del(v); - return lval_err("S-expression does not start with symbol"); + return lval_err("S-expression does not start with function"); } - lval* result = builtin(v, f->sym); + // If so call the function and return result + lval* result = f->fun(e, v); lval_del(f); return result; } -lval* builtin_headn(lval* a, int n) { +lval* builtin_headn(lenv* e, lval* a, int n) { LASSERT(a, a->count == 1, "Function 'head' passed too many arguments") LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'head' passed incorrect type") LASSERT(a, a->cell[0]->count != 0, "Function 'head' passed {}") @@ -95,20 +95,20 @@ lval* builtin_headn(lval* a, int n) { return v; } -lval* builtin_head(lval* a) { - return builtin_headn(a, 1); +lval* builtin_head(lenv* e, lval* a) { + return builtin_headn(e, a, 1); } -lval* builtin_init(lval* a) { +lval* builtin_init(lenv* e, lval* a) { LASSERT(a, a->count == 1, "Function 'init' passed too many arguments") LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'init' passed incorrect type") LASSERT(a, a->cell[0]->count != 0, "Function 'init' passed {}") - return builtin_headn(a, a->cell[0]->count - 1); + return builtin_headn(e, a, a->cell[0]->count - 1); } -lval* builtin_tail(lval* a) { +lval* builtin_tail(lenv* e, lval* a) { LASSERT(a, a->count == 1, "Function 'tail' passed too many arguments") LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'tail' passed incorrect type") LASSERT(a, a->cell[0]->count != 0, "Function 'tail' passed {}") @@ -118,21 +118,21 @@ lval* builtin_tail(lval* a) { return v; } -lval* builtin_list(lval* a) { +lval* builtin_list(lenv* e, lval* a) { a->type = LVAL_QEXPR; return a; } -lval* builtin_eval(lval* a) { +lval* builtin_eval(lenv* e, lval* a) { LASSERT(a, a->count == 1, "Function 'eval' passed too many arguments") LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'eval' passed incorrect type") lval* x = lval_take(a, 0); x->type = LVAL_SEXPR; - return lval_eval(x); + return lval_eval(e, x); } -lval* lval_join(lval* x, lval* y) { +lval* lval_join(lenv* e, lval* x, lval* y) { // For each cell in 'y' add it to 'x' while (y->count) { x = lval_add(x, lval_pop(y, 0)); @@ -143,7 +143,7 @@ lval* lval_join(lval* x, lval* y) { return x; } -lval* builtin_join(lval* a) { +lval* builtin_join(lenv* e, lval* a) { for (int i = 0 ; i < a->count; i++) { LASSERT(a, a->cell[i]->type == LVAL_QEXPR, "Function 'join' passed incorrect type") } @@ -151,14 +151,14 @@ lval* builtin_join(lval* a) { lval* x = lval_pop(a, 0); while (a->count) { - x = lval_join(x, lval_pop(a, 0)); + x = lval_join(e, x, lval_pop(a, 0)); } lval_del(a); return x; } -lval* builtin_len(lval* a) { +lval* builtin_len(lenv* e, lval* a) { LASSERT(a, a->cell[0]->type == LVAL_QEXPR, "Function 'len' passed incorrect type") lval* x = lval_long(a->cell[0]->count); @@ -166,14 +166,14 @@ lval* builtin_len(lval* a) { return x; } -lval* builtin_cons(lval* a) { +lval* builtin_cons(lenv* e, lval* a) { LASSERT(a, a->cell[0]->type != LVAL_QEXPR, "Function 'cons' passed incorrect type on first argument") LASSERT(a, a->cell[1]->type == LVAL_QEXPR, "Function 'cons' passed incorrect type on second argument") LASSERT(a, a->count == 2, "Function 'cons' passed an incorrect number of arguments") lval* x = lval_qexpr(); x = lval_add(x, lval_pop(a, 0)); - x = lval_join(x, lval_pop(a, 0)); + x = lval_join(e, x, lval_pop(a, 0)); lval_del(a); diff --git a/lval/expressions.h b/lval/expressions.h index 8cc2a59..78668f9 100644 --- a/lval/expressions.h +++ b/lval/expressions.h @@ -1,6 +1,7 @@ #ifndef LVAL_EXPRESSIONS #define LVAL_EXPRESSIONS #include "base.h" +#include "environment.h" // Constructors for the SEXPR and QEXPR data type lval* lval_sexpr(void); @@ -20,7 +21,7 @@ lval* lval_take(lval* v, int i); /* ----------------------------------------------------*/ // Adds the ability to evalutate each expression in the group -lval* lval_eval_sexpr(lval* v); +lval* lval_eval_sexpr(lenv* e, lval* v); /* QEXPR Operations @@ -32,15 +33,15 @@ lval* lval_eval_sexpr(lval* v); Len: Takes a Q-Expression and returns the length of the Q-Expression Init: Takes a Q-Expression and returns a Q-Expression with only the last element removed */ -lval* builtin_headn(lval* a, int n); -lval* builtin_head(lval* a); -lval* builtin_init(lval* a); -lval* builtin_tail(lval* a); -lval* builtin_list(lval* a); -lval* builtin_eval(lval* a); -lval* lval_join(lval* x, lval* y); -lval* builtin_join(lval* a); -lval* builtin_len(lval* a); -lval* builtin_cons(lval* a); +lval* builtin_headn(lenv* e, lval* a, int n); +lval* builtin_head(lenv* e, lval* a); +lval* builtin_init(lenv* e, lval* a); +lval* builtin_tail(lenv* e, lval* a); +lval* builtin_list(lenv* e, lval* a); +lval* builtin_eval(lenv* e, lval* a); +lval* lval_join(lenv* e, lval* x, lval* y); +lval* builtin_join(lenv* e, lval* a); +lval* builtin_len(lenv* e, lval* a); +lval* builtin_cons(lenv* e, lval* a); #endif diff --git a/lval/operations.c b/lval/operations.c index cf8a122..549a06a 100644 --- a/lval/operations.c +++ b/lval/operations.c @@ -4,6 +4,8 @@ #include "expressions.h" #include "operations.h" +lval* builtin_op(lenv* e, lval* v, char* sym); + lval* lval_sym(char* s) { lval* v = (lval *) malloc(sizeof(lval)); v->type = LVAL_SYM; @@ -42,9 +44,15 @@ lval* lval_read(mpc_ast_t* t) { } -lval* lval_eval(lval* v) { +lval* lval_eval(lenv* e, lval* v) { + if (v->type == LVAL_SYM) { + lval* x = lenv_get(e, v); + lval_del(v); + return x; + } + // Evauluate sexpressions - if (v->type == LVAL_SEXPR) { return lval_eval_sexpr(v); } + if (v->type == LVAL_SEXPR) { return lval_eval_sexpr(e, v); } // All other lval types remail the same return v; @@ -108,4 +116,34 @@ lval* lval_copy(lval* v) { return x; } +lval* builtin_add(lenv* e, lval* a) { + return builtin_op(e, a, "+"); +} +lval* builtin_sub(lenv* e, lval* a) { + return builtin_op(e, a, "-"); +} + +lval* builtin_mul(lenv* e, lval* a) { + return builtin_op(e, a, "*"); +} + +lval* builtin_div(lenv* e, lval* a) { + return builtin_op(e, a, "/"); +} + +lval* builtin_pow(lenv* e, lval* a) { + return builtin_op(e, a, "^"); +} + +lval* builtin_mod(lenv* e, lval* a) { + return builtin_op(e, a, "%"); +} + +lval* builtin_min(lenv* e, lval* a) { + return builtin_op(e, a, "min"); +} + +lval* builtin_max(lenv* e, lval* a) { + return builtin_op(e, a, "max"); +} diff --git a/lval/operations.h b/lval/operations.h index 64f56e4..2536bf6 100644 --- a/lval/operations.h +++ b/lval/operations.h @@ -3,6 +3,7 @@ #include "../mpc.h" #include "base.h" +#include "environment.h" // Constructor for symbol data type lval* lval_sym(char* s); @@ -12,8 +13,20 @@ lval* lval_sym(char* s); copy, and delete lval structures */ lval* lval_read(mpc_ast_t* t); -lval* lval_eval(lval* v); +lval* lval_eval(lenv* e, lval* v); void lval_del(lval* v); lval* lval_copy(lval* v); +// Math libraries +lval* builtin_add(lenv* e, lval* a); +lval* builtin_sub(lenv* e, lval* a); +lval* builtin_mul(lenv* e, lval* a); +lval* builtin_div(lenv* e, lval* a); +lval* builtin_pow(lenv* e, lval* a); +lval* builtin_mod(lenv* e, lval* a); +lval* builtin_min(lenv* e, lval* a); +lval* builtin_max(lenv* e, lval* a); + + + #endif diff --git a/prompt.c b/prompt.c index bf813b4..f56c269 100644 --- a/prompt.c +++ b/prompt.c @@ -33,7 +33,7 @@ void add_history(char* unused) {} double max(double x, double y); double min(double x, double y); -lval* builtin_op(lval* v, char* op); +lval* builtin_op(lenv* e, lval* v, char* op); int main (int argc, char** argv) { @@ -65,6 +65,9 @@ int main (int argc, char** argv) { puts("Lispy Version 0.0.0.0.1"); puts("Press Ctrl+c to Exit\n"); + lenv* e = lenv_new(); + lenv_add_builtins(e); + // In a never ending loop while (1) { // Output prompt and query @@ -78,7 +81,7 @@ int main (int argc, char** argv) { if (mpc_parse("", input, Lispy, &r)) { // Evualuate the expression and print its output // lval result = eval(r.output); - lval* result = lval_eval(lval_read(r.output)); + lval* result = lval_eval(e, lval_read(r.output)); lval_println(result); lval_del(result); // mpc_ast_print(r.output); @@ -112,12 +115,7 @@ double min(double x, double y) { return y; } - - - - - -lval* builtin_op(lval* a, char* op) { +lval* builtin_op(lenv* e, lval* a, char* op) { // Ensure all arguments are numbers for (int i = 0; i < a->count; i++) { if (a->cell[i]->type != LVAL_LONG && a->cell[i]->type != LVAL_DOUBLE) { @@ -157,18 +155,18 @@ lval* builtin_op(lval* a, char* op) { return x; } -lval* builtin(lval* a, char* func) { - if (strcmp("list", func) == 0) { return builtin_list(a); } - if (strcmp("head", func) == 0) { return builtin_head(a); } - if (strcmp("tail", func) == 0) { return builtin_tail(a); } - if (strcmp("join", func) == 0) { return builtin_join(a); } - if (strcmp("eval", func) == 0) { return builtin_eval(a); } - if (strcmp("len", func) == 0) { return builtin_len(a); } - if (strcmp("init", func) == 0) { return builtin_init(a); } - if (strcmp("cons", func) == 0) { return builtin_cons(a); } - if (strstr("+-/*^%", func)) { return builtin_op(a, func); } - if (strcmp("min", func) == 0) { return builtin_op(a, func); } - if (strcmp("max", func) == 0) { return builtin_op(a, func); } +lval* builtin(lenv* e, lval* a, char* func) { + if (strcmp("list", func) == 0) { return builtin_list(e, a); } + if (strcmp("head", func) == 0) { return builtin_head(e, a); } + if (strcmp("tail", func) == 0) { return builtin_tail(e, a); } + if (strcmp("join", func) == 0) { return builtin_join(e, a); } + if (strcmp("eval", func) == 0) { return builtin_eval(e, a); } + if (strcmp("len", func) == 0) { return builtin_len(e, a); } + if (strcmp("init", func) == 0) { return builtin_init(e, a); } + if (strcmp("cons", func) == 0) { return builtin_cons(e, a); } + if (strstr("+-/*^%", func)) { return builtin_op(e, a, func); } + if (strcmp("min", func) == 0) { return builtin_op(e, a, func); } + if (strcmp("max", func) == 0) { return builtin_op(e, a, func); } lval_del(a); return lval_err("Unknown Function!");