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:
parent
80967b9275
commit
95762976c5
|
@ -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
|
||||
|
|
35
src/env.c
35
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
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
27
src/object.c
27
src/object.c
|
@ -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 {
|
||||
|
|
11
src/object.h
11
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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 "[1;31m$FAILS Tests Failed[0m"
|
||||
|
|
Loading…
Reference in New Issue