diff --git a/src/Makefile b/src/Makefile index 92cff3d..ff3b590 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,6 +3,8 @@ exe = pl BINPREFIX ?= /usr/bin SCRIPTDIR ?= /usr/local/share/pebblisp +mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) +mkfile_dir := $(dir $(mkfile_path)) GCC_COM ?= gcc -g -O0 -Wall -o $(exe) -D STANDALONE -DSCRIPTDIR=\"$(SCRIPTDIR)\" @@ -12,6 +14,9 @@ all: notest: $(GCC_COM) $(files) +local: + gcc -g -O0 -Wall -o $(exe) -D STANDALONE -DSCRIPTDIR=\"$(mkfile_dir)/examples\" $(files) + val: $(GCC_COM) $(files) && ./tests.sh -val diff --git a/src/env.c b/src/env.c index 3e83497..5e53099 100644 --- a/src/env.c +++ b/src/env.c @@ -50,6 +50,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms, struct Environment env = {.outer = outer, .strings = NULL, .objects = NULL, + .structCount = 0, .size = paramCount}; if (paramCount == 0) { @@ -210,6 +211,7 @@ struct Environment defaultEnv() .strings = strings, .objects = objects, .size = size, + .structCount = 0, }; struct symFunc symFuncs[] = { @@ -243,7 +245,7 @@ struct Environment defaultEnv() {"prn", &print}, {"pch", &pChar}, {"penv", &printEnvO}, - {"sys", &systemCall}, + //{"sys", &systemCall}, {"loadfile", &loadFile}, {"inp", &takeInput}, #endif diff --git a/src/env.h b/src/env.h index 90dfe67..e7b661a 100644 --- a/src/env.h +++ b/src/env.h @@ -9,6 +9,9 @@ struct Environment { Object* objects; struct Environment* outer; int size; + + int structCount; + struct StructDef* structDefs; }; Object fetchFromEnvironment(const char* name, struct Environment* env); diff --git a/src/object.c b/src/object.c index cf641b7..917a840 100644 --- a/src/object.c +++ b/src/object.c @@ -95,6 +95,8 @@ inline int isEmpty(const Object* obj) return obj->list == NULL; case TYPE_LAMBDA: return obj->lambda == NULL; + case TYPE_STRUCT: + return obj->structObject == NULL; case TYPE_SYMBOL: case TYPE_STRING: return obj->string == NULL || obj->string[0] == '\0'; @@ -109,6 +111,7 @@ inline int isEmpty(const Object* obj) return 0; } +int allocations = 0; /** * Allocate a copy of a given object into the given pointer. * Does nothing if `spot` is NULL @@ -117,6 +120,12 @@ inline int isEmpty(const Object* obj) */ void allocObject(Object** spot, const Object src) { + if (allocations >= 10000) { + printf("MAX ALLOCATIONS EXCEEDED\n"); + *spot = NULL; + return; + } + allocations++; *spot = malloc(sizeof(struct Object)); **spot = src; (*spot)->forward = NULL; @@ -247,6 +256,42 @@ void stringList(char* dest, const Object* obj) strcat(dest, " )"); } +/** + * Creates a string from a given struct Object + * Blocks out with curly braces + */ +void stringStruct(char* dest, const Object* obj) +{ + struct StructObject* so = obj->structObject; + dest[0] = '{'; + dest[1] = '\0'; + + for (int i = 0; i < so->definition->fieldCount; i++) { + strcat(dest, " "); + strcat(dest, so->definition->names[i]); + strcat(dest, ": "); + int isString = so->fields[i].type == TYPE_STRING; + if (isString) { + strcat(dest, "\""); + } + + char tok[90] = ""; + stringObj(tok, &so->fields[i]); + strcat(dest, tok); + + if (isString) { + strcat(dest, "\""); + } + strcat(dest, ","); + } + int i = 0; + while (dest[i]) { + i++; + } + dest[i - 1] = ' '; + dest[i + 0] = '}'; + dest[i + 1] = '\0'; +} /** * Creates a string from a given Object * Returns NULL if either param is NULL @@ -282,6 +327,10 @@ char* stringNObj(char* dest, const Object* obj, const size_t len) case TYPE_SYMBOL: snprintf(dest, len, "`%s`", obj->string); break; + case TYPE_STRUCT: + //snprintf(dest, len, "{%s}", obj->structObject->definition->names[0]); + stringStruct(dest, obj); + break; case TYPE_LIST: case TYPE_SLIST: stringList(dest, obj); @@ -335,38 +384,26 @@ void debugObj(const Object* obj) #if defined(DEBUG) || defined(STANDALONE) +#define SIMPLE_TYPE(_type) case _type:\ + printf(#_type);\ + return + void printType(const Object* obj) { switch (obj->type) { - case TYPE_NUMBER: - printf("TYPE_NUMBER"); - return; - case TYPE_BOOL: - printf("TYPE_BOOL"); - return; - case TYPE_LIST: - printf("TYPE_LIST"); - return; - case TYPE_SLIST: - printf("TYPE_SLIST"); - return; - case TYPE_FUNC: - printf("TYPE_FUNC"); - return; - case TYPE_SYMBOL: - printf("TYPE_SYMBOL"); - return; - case TYPE_STRING: - printf("TYPE_STRING"); - return; + SIMPLE_TYPE(TYPE_NUMBER); + SIMPLE_TYPE(TYPE_STRUCT); + SIMPLE_TYPE(TYPE_BOOL); + SIMPLE_TYPE(TYPE_LIST); + SIMPLE_TYPE(TYPE_SLIST); + SIMPLE_TYPE(TYPE_FUNC); + SIMPLE_TYPE(TYPE_SYMBOL); + SIMPLE_TYPE(TYPE_STRING); + SIMPLE_TYPE(TYPE_OTHER); + SIMPLE_TYPE(TYPE_ERROR); case TYPE_LAMBDA: printf("TYPE_LAMBDA Params:\n"); return; - case TYPE_OTHER: - printf("TYPE_OTHER: "); - case TYPE_ERROR: - printf("TYPE_ERROR: "); - return; } if (!isValidType(*obj)) { @@ -467,10 +504,18 @@ void cleanObject(Object* target) cleanObject(&target->lambda->body); free(target->lambda); break; + case TYPE_STRUCT: + for (int i = 0; i < target->structObject->definition->fieldCount; i++) { + cleanObject(&target->structObject->fields[i]); + } + free(target->structObject->fields); + free(target->structObject); + target->structObject = NULL; + break; case TYPE_ERROR: #ifndef SIMPLE_ERRORS - free(target->error->context); - free(target->error); + //free(target->error->context); + //free(target->error); target->error = NULL; #endif break; @@ -605,6 +650,16 @@ inline Object listObject() return list; } +// Returns an empty struct Object +inline Object structObject(struct StructDef *definition) +{ + Object structo = newObject(TYPE_STRUCT); + structo.structObject = malloc(sizeof(struct StructObject)); + structo.structObject->definition = definition; + structo.structObject->fields = malloc(sizeof(Object) * definition->fieldCount); + return structo; +} + // Returns a list Object starting with the given Object inline Object startList(const Object start) { @@ -629,6 +684,7 @@ inline int isValidType(const Object test) case TYPE_NUMBER: case TYPE_BOOL: case TYPE_LIST: + case TYPE_STRUCT: case TYPE_SLIST: case TYPE_FUNC: case TYPE_SYMBOL: @@ -673,6 +729,8 @@ inline Object cloneOther(const Object src) return src.other->clone ? src.other->clone(src.other) : src; } +Object cloneStruct(const Object src); + inline Object cloneObject(const Object src) { switch (src.type) { @@ -681,6 +739,8 @@ inline Object cloneObject(const Object src) return cloneList(src); case TYPE_LAMBDA: return cloneLambda(src); + case TYPE_STRUCT: + return cloneStruct(src); case TYPE_STRING: case TYPE_SYMBOL: return cloneString(src); @@ -696,6 +756,16 @@ inline Object cloneObject(const Object src) return src; } +Object cloneStruct(const Object src) +{ + Object structo = structObject(src.structObject->definition); + struct StructObject* so = structo.structObject; + for (int i = 0; i < so->definition->fieldCount; i++) { + so->fields[i] = cloneObject(src.structObject->fields[i]); + } + return structo; +} + inline Object numberObject(int num) { Object o = newObject(TYPE_NUMBER); diff --git a/src/object.h b/src/object.h index 9eb1d1d..3ee96aa 100644 --- a/src/object.h +++ b/src/object.h @@ -72,6 +72,7 @@ typedef enum Type { TYPE_BOOL, TYPE_LIST, TYPE_SLIST, + TYPE_STRUCT, TYPE_FUNC, TYPE_SYMBOL, TYPE_LAMBDA, @@ -81,6 +82,7 @@ typedef enum Type { } Type; typedef struct Object Object; + struct Lambda; struct Environment; struct Slice; @@ -101,6 +103,7 @@ struct Object { Object (*func)(Object, Object, struct Environment *); + struct StructObject *structObject; struct Lambda *lambda; struct Other *other; #ifdef SIMPLE_ERRORS @@ -111,6 +114,17 @@ struct Object { }; }; +struct StructDef { + int fieldCount; + char* name; + const char** names; +}; + +struct StructObject { + struct StructDef *definition; + struct Object* fields; // Order should match that in the definition. +}; + struct Lambda { Object params; Object body; @@ -204,6 +218,8 @@ Object boolObject(int b); Object numberObject(int num); +Object structObject(struct StructDef *definition); + Object otherObject(); Object errorObject(enum errorCode err); diff --git a/src/pebblisp.c b/src/pebblisp.c index 7529e53..8b8caf1 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -43,6 +43,52 @@ Object evalDefArgs(const Object* symbol, const Object* value, return cloneObject(*symbol); } +void printStructDef(const struct StructDef *def) +{ + printf("%s: {\n", def->name); + for (int i = 0; i < def->fieldCount; i++) { + printf(" %s,\n", def->names[i]); + } + printf("}\n"); +} + +/** + * Add a struct to the environment with a given name and fields. + * + * (struct point (x y)) + */ +Object evalStructArgs(const Object* symbol, const Object* fields, struct Environment* env) +{ + const char* name = symbol->string; + + if (!isListy(*fields)) { + return errorObject(NOT_A_LIST); + } + + struct StructDef def; + //def.name = name; + def.name = malloc(sizeof(char) * (strlen(name) + 1)); + strcpy(def.name, name); + def.fieldCount = listLength(fields); + def.names = malloc(sizeof(char*) * def.fieldCount); + + int i = 0; + FOR_POINTER_IN_LIST(fields) { + def.names[i] = POINTER->string; + i++; + } + + while (env->outer) { + env = env->outer; + } + env->structDefs = malloc(sizeof(struct StructDef) * 1); + env->structCount = 1; + env->structDefs[0] = def; + printStructDef(&env->structDefs[0]); + + return boolObject(1); +} + Object evalIfArgs(const Object* argForms, struct Environment* env) { Object condition = eval(argForms, env); @@ -118,6 +164,8 @@ Object evalBuiltIns(const Object* first, const Object* rest, return evalLambdaArgs(rest); } else if (strcmp(first->string, "map") == 0) { return evalMapArgs(rest, env); + } else if (strcmp(first->string, "struct") == 0) { + return evalStructArgs(rest, rest->forward, env); } return errorObject(BUILT_IN_NOT_FOUND); @@ -246,7 +294,6 @@ Object evalList(const Object* obj, struct Environment* env) } Object* first_form = obj->list; - { // Try to eval built-ins Object builtIn = evalBuiltIns(first_form, first_form->forward, env); @@ -257,6 +304,36 @@ Object evalList(const Object* obj, struct Environment* env) cleanObject(&builtIn); } + struct StructDef *def = NULL; + if (first_form->type == TYPE_SYMBOL) { + struct Environment* outerEnv = env; + while (outerEnv->outer) { + outerEnv = outerEnv->outer; + } + //printf("evalList firstElementName: %s\n", first_form->string); + //printf("checking for struct `%s`\n", first_form->string); + //printf("%d structs available\n", outerEnv->structCount); + for (int i = 0; i < outerEnv->structCount; i++) { + //printf("struct[%d] - `%s`\n", i, outerEnv->structDefs[i].name); + if (strcmp(first_form->string, outerEnv->structDefs[i].name) == 0) { + def = &outerEnv->structDefs[i]; + printf("Found struct definition for %s!\n", first_form->string); + break; + } + } + } + if (def) { + Object structo = structObject(def); + int i = 0; + FOR_POINTER_IN_LIST(obj) { + if (i != 0) { + structo.structObject->fields[i - 1] = eval(POINTER, env); + } + i++; + } + return structo; + } + // Evaluate the list based on the first element's type Object first_eval = eval(first_form, env); switch (first_eval.type) { @@ -273,6 +350,9 @@ Object evalList(const Object* obj, struct Environment* env) nf_addToList(&list, first_eval); FOR_POINTER_IN_LIST(obj) { if (i != 0) { + if (isStringy(*POINTER)) { + printf("evalList elementName: %s\n", POINTER->string); + } nf_addToList(&list, eval(POINTER, env)); } i++; @@ -291,6 +371,7 @@ Object eval(const Object* obj, struct Environment* env) case TYPE_NUMBER: case TYPE_BOOL: case TYPE_STRING: + case TYPE_STRUCT: return cloneObject(*obj); case TYPE_SYMBOL: @@ -924,4 +1005,4 @@ int main(int argc, const char* argv[]) deleteEnv(&env); } -#endif \ No newline at end of file +#endif