Finished implementing the environment
This commit is contained in:
parent
e5d5aee39e
commit
faf8a22331
7 changed files with 211 additions and 55 deletions
|
@ -1,4 +1,64 @@
|
|||
#include "environment.h"
|
||||
#include <stdlib.h>
|
||||
#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));
|
||||
|
@ -6,3 +66,31 @@ lval* lval_fun(lbuiltin func) {
|
|||
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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
38
prompt.c
38
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("<stdin>", 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!");
|
||||
|
|
Reference in a new issue