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).
This commit is contained in:
= 2020-05-18 00:00:19 +01:00
parent 80967b9275
commit 95762976c5
7 changed files with 123 additions and 6 deletions

View File

@ -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

View File

@ -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
};

View File

@ -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);

View File

@ -3,7 +3,7 @@
#include <string.h>
#include <stdio.h>
#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 {

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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"