From 95762976c5a9fec010182a6aa6518082aa7d895b Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 18 May 2020 00:00:19 +0100 Subject: [PATCH] Add basic struct notion and tests. Don't auto-run tests in debug mode. Some new tests fail for list-related reasons (some work in the REPL). --- src/Makefile | 2 +- src/env.c | 35 +++++++++++++++++++++++++++++++++++ src/env.h | 1 + src/object.c | 27 ++++++++++++++++++++++++++- src/object.h | 11 +++++++---- src/pebblisp.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/tests.sh | 6 ++++++ 7 files changed, 123 insertions(+), 6 deletions(-) diff --git a/src/Makefile b/src/Makefile index 4c0e1de..80500ac 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,7 +10,7 @@ val: gcc -g -O0 -o pebblisp -D STANDALONE $(files) && ./tests.sh -val debug: - gcc -g -O0 -o pebblisp -D STANDALONE -D DEBUG $(files) && ./tests.sh + gcc -g -O0 -o pebblisp -D STANDALONE -D DEBUG $(files) run: ./pebblisp diff --git a/src/env.c b/src/env.c index 7ccb3b8..fcbbbf7 100644 --- a/src/env.c +++ b/src/env.c @@ -38,6 +38,38 @@ Object fetchFromEnvironment(const char *name, struct Environment *env) return errorObject(DID_NOT_FIND_SYMBOL); } +Object* pointerFromEnvironment(const char *name, struct Environment *env) +{ + if(!env) { + printf("env not found\n"); + return NULL; + } + + if(env->size == 0) { + printf("empty env\n"); + return NULL; + } + + 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 pointerFromEnvironment(name, env->outer); + } + + return NULL; +} + struct Environment envForLambda(const Object *params, const Object *arg_forms, struct Environment *outer) { @@ -173,6 +205,9 @@ const char *codes[] = { ) \ ))", + // A demo struct + "(stct kitty (name age))", + NULL }; diff --git a/src/env.h b/src/env.h index bd12972..d52c547 100644 --- a/src/env.h +++ b/src/env.h @@ -12,6 +12,7 @@ struct Environment { }; Object fetchFromEnvironment(const char *name, struct Environment *env); +Object* pointerFromEnvironment(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); diff --git a/src/object.c b/src/object.c index f737dd3..d08f793 100644 --- a/src/object.c +++ b/src/object.c @@ -3,7 +3,7 @@ #include #include -#define RESULT_LENGTH 20 +#define RESULT_LENGTH 40 #ifdef DEBUG #define printd(...) printf(__VA_ARGS__) @@ -226,6 +226,29 @@ void stringList(char *dest, const Object *obj) strcat(dest, " )"); } +void stringStruct(char *dest, const Object *obj) +{ + dest[0] = '\0'; + + Object *march = obj->list->forward; + Object *structMarch = obj->list->list; + while(march && structMarch) { + char tok[90] = ""; + stringObj(tok, structMarch); + strcat(dest, tok); + strcat(dest, ": "); + + tok[0] = '\0'; + stringObj(tok, march); + strcat(dest, tok); + + if(march->forward) + strcat(dest, " "); + march = march->forward; + structMarch = structMarch->forward; + } +} + /** * Creates a string from a given Object * Returns NULL if either param is NULL @@ -259,6 +282,8 @@ char* stringObj(char *dest, const Object *obj) snprintf(dest, RESULT_LENGTH, "%s", obj->string); } else if(t == TYPE_LIST) { stringList(dest, obj); + } else if(t == TYPE_STRUCT) { + stringStruct(dest, obj); } else if(t == TYPE_ERROR) { snprintf(dest, RESULT_LENGTH, "E%d", obj->err); } else { diff --git a/src/object.h b/src/object.h index 86bd048..357b132 100644 --- a/src/object.h +++ b/src/object.h @@ -28,13 +28,15 @@ enum errorCode { NULL_PARSE, NULL_LAMBDA_LIST, NULL_MAP_ARGS, + NULL_STRUCT_ARGS, LAMBDA_ARGS_NOT_LIST, DID_NOT_FIND_SYMBOL, BAD_TYPE, UNEXPECTED_FORM, LISTS_NOT_SAME_SIZE, SYMBOLS_CANT_START_WITH_DIGITS, - UNSUPPORTED_NUMBER_TYPE + UNSUPPORTED_NUMBER_TYPE, + MISMATCHED_PARAM_COUNT }; //#ifdef STANDALONE @@ -48,18 +50,18 @@ static const char *errorText[] = { "NULL_PARSE", "NULL_LAMBDA_LIST", "NULL_MAP_ARGS", + "NULL_STRUCT_ARGS", "LAMBDA_ARGS_NOT_LIST", "DID_NOT_FIND_SYMBOL", "BAD_TYPE", "UNEXPECTED_FORM", "LISTS_NOT_SAME_SIZE", "SYMBOLS_CANT_START_WITH_DIGITS", - "UNSUPPORTED_NUMBER_TYPE" + "UNSUPPORTED_NUMBER_TYPE", + "MISMATCHED_PARAM_COUNT" }; //#endif -#define MALLOC_FLAG 64 - typedef enum Type { TYPE_NUMBER, TYPE_BOOL, @@ -68,6 +70,7 @@ typedef enum Type { TYPE_SYMBOL, TYPE_LAMBDA, TYPE_STRING, + TYPE_STRUCT, TYPE_ERROR } Type; diff --git a/src/pebblisp.c b/src/pebblisp.c index 2f7d7b7..6d6bdef 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -64,6 +64,48 @@ Object evalMapArgs(const Object *argForms, struct Environment *env) return list; } +Object evalStructArgs(const Object *name, const Object *argForms, + struct Environment *env) +{ + if(!argForms) + return errorObject(NULL_STRUCT_ARGS); + + Object strct = cloneList(*argForms); + // strct.type = TYPE_STRUCT; + + addToEnv(env, name->name, strct); + return strct; +} + +/** + *(def herm (make cat ("Hermione" 10))) + * Stores a STRUCT named herm in the environment + * String in env is "herm" + * Object in env is a TYPE_STRUCT with + * ->forward = NULL + * ->list = pointer to cat in env + * ->forward = "Hermione" + * ->forward = 2 + */ + +Object evalMakeArgs(const Object *structName, const Object *argForms, + struct Environment *env) +{ + Object *structure = pointerFromEnvironment(structName->name, env); + if(listLength(structure) != listLength(argForms)) + return errorObject(MISMATCHED_PARAM_COUNT); + + // Could be made to re-use the string pointer in `structure` + Object newStruct = startList(*structure); + + FOR_POINTER_IN_LIST(argForms) { + nf_addToList(&newStruct, eval(POINTER, env)); + } + + newStruct.type = TYPE_STRUCT; + return newStruct; +} + Object evalBuiltIns(const Object *first, const Object *rest, struct Environment *env) { @@ -75,6 +117,10 @@ Object evalBuiltIns(const Object *first, const Object *rest, return evalLambdaArgs(rest); } else if(strcmp(first->name, "map") == 0) { return evalMapArgs(rest, env); + } else if(strcmp(first->name, "stct") == 0) { + return evalStructArgs(rest, rest->forward, env); + } else if(strcmp(first->name, "make") == 0) { + return evalMakeArgs(rest, rest->forward, env); } return errorObject(BUILT_IN_NOT_FOUND); @@ -158,6 +204,7 @@ Object eval(const Object *obj, struct Environment *env) return errorObject(UNEXPECTED_FORM); default: + printf("RETURN OBJECT OF TYPE %d\n", obj->type); return *obj; } } diff --git a/src/tests.sh b/src/tests.sh index 7871e87..e038eaf 100755 --- a/src/tests.sh +++ b/src/tests.sh @@ -34,6 +34,7 @@ check() { } check "PlainRet" "10" "10" +check "ListRet" "(10)" "(10)" check "StrRetrn" "\"hey\"" "hey" echo "" check "Addition" "(+ 1093 102852)" "103945" @@ -90,6 +91,11 @@ check "Squaring" "(sq 9876)" "97535376" check "Cubing" "(cube 81)" "531441" check "Exponent" "(exp 9 9)" "387420489" echo "" +check "BasicStruct" "(def h (make kitty (\"Hermione\" 2))) h" "name: Hermione age: 2" +check "BasicStruct" "(def h (make kitty (\"Hermione\" 2))) (h)" "(name: Hermione age: 2)" +check "StructAccess" "(def pet (fn (a) (cat \"You petted \" a))) (def h (make kitty (\"Hermione\" 2))) (pet h)" "You petted Hermione 2" +echo "" + if [ "$FAILS" -ne "0" ]; then echo "$FAILS Tests Failed"