diff --git a/src/Makefile b/src/Makefile index ec32124..4be8cfd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,11 +1,11 @@ all: - gcc -g -O0 -o pebblisp -D STANDALONE pebblisp.c tokens.c object.c && ./tests.sh + gcc -g -O0 -o pebblisp -D STANDALONE pebblisp.c tokens.c object.c env.c && ./tests.sh debug: - gcc -g -O0 -o pebblisp -D STANDALONE -D DEBUG pebblisp.c tokens.c object.c && ./tests.sh + gcc -g -O0 -o pebblisp -D STANDALONE -D DEBUG pebblisp.c tokens.c object.c env.c && ./tests.sh phrase: - gcc -g -O0 -o pebblisp -D STANDALONE -D DEBUG -D NO_REPL pebblisp.c tokens.c object.c && ./tests.sh + gcc -g -O0 -o pebblisp -D STANDALONE -D DEBUG -D NO_REPL pebblisp.c tokens.c object.c env.c && ./tests.sh run: ./pebblisp diff --git a/src/env.c b/src/env.c new file mode 100644 index 0000000..f5ed61d --- /dev/null +++ b/src/env.c @@ -0,0 +1,180 @@ +#include "env.h" +#include "pebblisp.h" +#include +#include +#include + +#ifndef STANDALONE +#include +#undef printf +#define printf(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__) +#endif + +Object fetchFromEnvironment(const char *name, struct Environment *env) +{ + if(!env) + return errorObject(NULL_ENV); + + if(env->size == 0) + return errorObject(EMPTY_ENV); + + printd("Fetching '%s' from env\n", name); + // printEnv(env); + for(int i = 0; i < env->size; i++) { + printd("Try %d\n", i); + if(env->strings[i] == NULL) + break; + if(strcmp(name, env->strings[i]) == 0) { + return env->objects[i]; + } + } + + printd("Trying outer %p\n", env->outer); + if(env->outer) { + // printEnv(env->outer); + return fetchFromEnvironment(name, env->outer); + } + + return errorObject(DID_NOT_FIND_SYMBOL); +} + +struct Environment envForLambda(const Object *params, const Object *arg_forms, + struct Environment *outer) +{ + printd("envForLambda()\n"); + debugObj(arg_forms); + + int paramCount = listLength(params); + + struct Environment env = { + .outer = outer, + .strings = NULL, + .objects = NULL, + .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; + printd("Param count: %d\n", paramCount); + for(int i = 0; i < paramCount; i++) { + const char *newObjName = itemAt(params, i)->name; + const Object newEnvObj = eval(march, outer); + printd("Adding new object '%s' to lambda env: ", newObjName); + debugObj(&newEnvObj); + addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms? + march = march->forward; + } + + return env; +} + +// todo could include and return a starting index for faster multi-adds +// Maybe extend existing environment using a malloc'd outer, instead of realloc +void addToEnv(struct Environment *env, const char *name, const Object obj) +{ + int i; + for(i = 0; i < env->size ; i++) { + if(env->strings[i] == NULL) { + env->strings[i] = calloc(sizeof(char), strlen(name) + 1); + strncpy(env->strings[i], name, strlen(name)); + env->objects[i] = obj; + // if(obj.type == TYPE_LIST) + // copyList(&env->objects[i], &obj); + return; + } + if(strcmp(env->strings[i], name) == 0) { + cleanObject(&env->objects[i]); + env->objects[i] = obj; + // if(obj.type == TYPE_LIST) + // copyList(&env->objects[i], &obj); + return; + } + } + + printd("Reallocating environment\n"); + const int inc = 5; + 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[i + j] = NULL; + } + + env->strings[i] = malloc(strlen(name) + 1); + strncpy(env->strings[i], name, strlen(name) + 1); + env->objects[i] = 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) + return; + printf("env[%d]: '%s'\n ", i, env->strings[i]); + printObj(&env->objects[i]); + } +} + +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) +{ + 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 Environment defaultEnv() +{ + struct Environment e; + e.outer = NULL; + e.strings = calloc(sizeof(char*), MAX_ENV_ELM); + e.objects = malloc(sizeof(Object) * MAX_ENV_ELM); + e.size = MAX_ENV_ELM; + + addFunc("+", &add, &e); + addFunc("-", &sub, &e); + addFunc("*", &mul, &e); + addFunc("/", &dvi, &e); + addFunc("%", &mod, &e); + addFunc("=", &equ, &e); + addFunc(">", >h, &e); + addFunc("<", <h, &e); + addFunc("len", &len, &e); + addFunc("cat", &catObjects, &e); + + parseEval("(def max (fn (a b) (if (> a b) a b)))", &e); + parseEval("(def min (fn (a b) (if (< a b) a b)))", &e); + parseEval("(def ad (fn (a) (if (> a 10) a (ad (* 10 a) ))))", &e); + parseEval("(def spent (fn (a) \ + (cat \"Tip: $\" (/ a 5) \".\" \ + (/ (* 100 (% a 5)) 5) \ + ) \ + ))", &e); + + return e; +} diff --git a/src/env.h b/src/env.h new file mode 100644 index 0000000..bd12972 --- /dev/null +++ b/src/env.h @@ -0,0 +1,24 @@ +#ifndef ENVIRONMENT_H +#define ENVIRONMENT_H + +#include "object.h" + +struct Environment; +struct Environment { + char **strings; + Object *objects; + struct Environment *outer; + char size; +}; + +Object fetchFromEnvironment(const char *name, struct Environment *env); +struct Environment envForLambda(const Object *params, const Object *arg_forms, + struct Environment *outer); +void addToEnv(struct Environment *env, const char *name, const Object obj); +void printEnv(struct Environment *env); +void addFunc(const char *name, Object (*func)(Object, Object, struct Environment*), + struct Environment *env); +void deleteEnv(struct Environment *e); +struct Environment defaultEnv(); + +#endif diff --git a/src/pebblisp.c b/src/pebblisp.c index 1ca155c..d4c7e04 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -29,34 +29,6 @@ void debugSlice(struct Slice *s) printd(" length: %d\n", s->length); } -Object fetchFromEnvironment(const char *name, struct Environment *env) -{ - if(!env) - return errorObject(NULL_ENV); - - if(env->size == 0) - return errorObject(EMPTY_ENV); - - printd("Fetching '%s' from env\n", name); - // printEnv(env); - for(int i = 0; i < env->size; i++) { - printd("Try %d\n", i); - if(env->strings[i] == NULL) - break; - if(strcmp(name, env->strings[i]) == 0) { - return env->objects[i]; - } - } - - printd("Trying outer %p\n", env->outer); - if(env->outer) { - // printEnv(env->outer); - return fetchFromEnvironment(name, env->outer); - } - - return errorObject(DID_NOT_FIND_SYMBOL); -} - Result parse(struct Slice *slices) { struct Slice *token = slices; @@ -170,41 +142,6 @@ Object evalMapArgs(const Object *arg_forms, struct Environment *env) return list; } -struct Environment envForLambda(const Object *params, const Object *arg_forms, - struct Environment *outer) -{ - printd("envForLambda()\n"); - debugObj(arg_forms); - - int paramCount = listLength(params); - - struct Environment env = { - .outer = outer, - .strings = NULL, - .objects = NULL, - .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; - printd("Param count: %d\n", paramCount); - for(int i = 0; i < paramCount; i++) { - const char *newObjName = itemAt(params, i)->name; - const Object newEnvObj = eval(march, outer); - printd("Adding new object '%s' to lambda env: ", newObjName); - debugObj(&newEnvObj); - addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms? - march = march->forward; - } - - return env; -} - Object evalBuiltIns(const Object *first, const Object *rest, struct Environment *env) { @@ -305,58 +242,6 @@ Result result(Object obj, struct Slice *slices) }; } -// todo could include and return a starting index for faster multi-adds -// Maybe extend existing environment using a malloc'd outer, instead of realloc -void addToEnv(struct Environment *env, const char *name, const Object obj) -{ - int i; - for(i = 0; i < env->size ; i++) { - if(env->strings[i] == NULL) { - env->strings[i] = calloc(sizeof(char), strlen(name) + 1); - strncpy(env->strings[i], name, strlen(name)); - env->objects[i] = obj; - // if(obj.type == TYPE_LIST) - // copyList(&env->objects[i], &obj); - return; - } - if(strcmp(env->strings[i], name) == 0) { - cleanObject(&env->objects[i]); - env->objects[i] = obj; - // if(obj.type == TYPE_LIST) - // copyList(&env->objects[i], &obj); - return; - } - } - - printd("Reallocating environment\n"); - const int inc = 5; - 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[i + j] = NULL; - } - - env->strings[i] = malloc(strlen(name) + 1); - strncpy(env->strings[i], name, strlen(name) + 1); - env->objects[i] = 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) - return; - printf("env[%d]: '%s'\n ", i, env->strings[i]); - printObj(&env->objects[i]); - } -} - Object catObjects(const Object obj1, const Object obj2, struct Environment *env) { const Object evalObj1 = eval(&obj1, env); @@ -447,58 +332,7 @@ bopf(equ, '='); bopf(gth, '>'); bopf(lth, '<'); -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) -{ - 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 Environment defaultEnv() { - struct Environment e; - e.outer = NULL; - e.strings = calloc(sizeof(char*), MAX_ENV_ELM); - e.objects = malloc(sizeof(Object) * MAX_ENV_ELM); - e.size = MAX_ENV_ELM; - - addFunc("+", &add, &e); - addFunc("-", &sub, &e); - addFunc("*", &mul, &e); - addFunc("/", &dvi, &e); - addFunc("%", &mod, &e); - addFunc("=", &equ, &e); - addFunc(">", >h, &e); - addFunc("<", <h, &e); - addFunc("len", &len, &e); - addFunc("cat", &catObjects, &e); - - parseEval("(def max (fn (a b) (if (> a b) a b)))", &e); - parseEval("(def min (fn (a b) (if (< a b) a b)))", &e); - parseEval("(def ad (fn (a) (if (> a 10) a (ad (* 10 a) ))))", &e); - parseEval("(def spent (fn (a) \ - (cat \"Tip: $\" (/ a 5) \".\" \ - (/ (* 100 (% a 5)) 5) \ - ) \ - ))", &e); - - return e; -} +#undef bopf Object parseEval(const char *input, struct Environment *env) { @@ -516,9 +350,35 @@ Object parseEval(const char *input, struct Environment *env) } } #endif - Object parsed = parse(tokens).obj; + // int statements = 0; + int i = 0; + int parens = 0; + Object obj; + struct Slice *tok = tokens; + while(tok[i].text != NULL) { + //printf("tok[%d].text[0]: '%c'\n", i, tok[i].text[0]); + if(tok[i].text[0] == '(') { + parens++; + } else if(tok[i].text[0] == ')') { + parens--; + if(parens == 0) { + Object parsed = parse(tok).obj; + tok = &tok[i + 1]; + i = -1; + obj = eval(&parsed, env); + //printf("End statement:\n"); + //printObj(&obj); + } + } + i++; + } + // for(int i = 0; i < statements; i++) { + // Object parsed = parse(tokens).obj; + // } + // Object parsed = parse(tokens).obj; free(tokens); - return eval(&parsed, env); + // return eval(&parsed, env); + return obj; } #ifdef STANDALONE diff --git a/src/pebblisp.h b/src/pebblisp.h index 1ce513d..34e571f 100644 --- a/src/pebblisp.h +++ b/src/pebblisp.h @@ -2,6 +2,7 @@ #define PEBBLISP_H #include "object.h" +#include "env.h" #ifndef STANDALONE #include @@ -24,13 +25,6 @@ typedef struct Result { struct Slice *slices; } Result; -struct Environment { - char **strings; - Object *objects; - struct Environment *outer; - char size; -}; - Object eval(const Object *obj, struct Environment *env); Result parse(struct Slice *slices); Result readSeq(struct Slice *slices); @@ -55,4 +49,13 @@ Result result(Object obj, struct Slice *slices); void copySlice(char * dest, struct Slice *src); void debugSlice(struct Slice *s); +#define bopf(_name) \ +Object _name(Object obj1, Object obj2, struct Environment *env); +bopf(add); bopf(sub); +bopf(mul); bopf(dvi); +bopf(mod); bopf(equ); +bopf(gth); bopf(lth); +#undef bopf +Object catObjects(const Object obj1, const Object obj2, struct Environment *env); + #endif diff --git a/src/tokens.c b/src/tokens.c index bef850d..cc7ab1a 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -3,8 +3,12 @@ #ifdef STANDALONE #include +#undef printd +#define printd(...) fprintf(stderr, __VA_ARGS__) #else #include +#undef printd +#define printd(...) printf(__VA_ARGS__) #endif /* @@ -52,7 +56,8 @@ struct Slice *nf_tokenize(const char *input) int parens = 0; while(input[i] != '\0') { - // printf("input: '%c'\n", input[i]); + int l = 1; + // printd("input: '%c'\n", input[i]); if(isWhitespace(input[i])) { i++; @@ -69,30 +74,24 @@ struct Slice *nf_tokenize(const char *input) } } + slices[slice].text = &input[i]; + if(isSingle(input[i])) { - slices[slice].text = &input[i]; - slices[slice].length = 1; - slice++; i++; } else if(input[i] == '"') { - slices[slice].text = &input[i]; - int l = 1; while(input[++i] != '"') { l++; } i++; - slices[slice].length = l; - slice++; } else { - slices[slice].text = &input[i]; - int l = 1; while(!isWhitespace(input[++i]) && !isSingle(input[i])) { l++; } - slices[slice].length = l; - slice++; } + + slices[slice].length = l; + slice++; } if(parens){