Extremely barebones struct object implementation.

This commit is contained in:
Sage Vaillancourt 2022-03-14 16:51:45 -04:00 committed by Sage Vaillancourt
parent e2c977e95a
commit 6c8ff04711
6 changed files with 208 additions and 31 deletions

View File

@ -3,6 +3,8 @@ exe = pl
BINPREFIX ?= /usr/bin BINPREFIX ?= /usr/bin
SCRIPTDIR ?= /usr/local/share/pebblisp 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)\" GCC_COM ?= gcc -g -O0 -Wall -o $(exe) -D STANDALONE -DSCRIPTDIR=\"$(SCRIPTDIR)\"
@ -12,6 +14,9 @@ all:
notest: notest:
$(GCC_COM) $(files) $(GCC_COM) $(files)
local:
gcc -g -O0 -Wall -o $(exe) -D STANDALONE -DSCRIPTDIR=\"$(mkfile_dir)/examples\" $(files)
val: val:
$(GCC_COM) $(files) && ./tests.sh -val $(GCC_COM) $(files) && ./tests.sh -val

View File

@ -50,6 +50,7 @@ struct Environment envForLambda(const Object* params, const Object* arg_forms,
struct Environment env = {.outer = outer, struct Environment env = {.outer = outer,
.strings = NULL, .strings = NULL,
.objects = NULL, .objects = NULL,
.structCount = 0,
.size = paramCount}; .size = paramCount};
if (paramCount == 0) { if (paramCount == 0) {
@ -210,6 +211,7 @@ struct Environment defaultEnv()
.strings = strings, .strings = strings,
.objects = objects, .objects = objects,
.size = size, .size = size,
.structCount = 0,
}; };
struct symFunc symFuncs[] = { struct symFunc symFuncs[] = {
@ -243,7 +245,7 @@ struct Environment defaultEnv()
{"prn", &print}, {"prn", &print},
{"pch", &pChar}, {"pch", &pChar},
{"penv", &printEnvO}, {"penv", &printEnvO},
{"sys", &systemCall}, //{"sys", &systemCall},
{"loadfile", &loadFile}, {"loadfile", &loadFile},
{"inp", &takeInput}, {"inp", &takeInput},
#endif #endif

View File

@ -9,6 +9,9 @@ struct Environment {
Object* objects; Object* objects;
struct Environment* outer; struct Environment* outer;
int size; int size;
int structCount;
struct StructDef* structDefs;
}; };
Object fetchFromEnvironment(const char* name, struct Environment* env); Object fetchFromEnvironment(const char* name, struct Environment* env);

View File

@ -95,6 +95,8 @@ inline int isEmpty(const Object* obj)
return obj->list == NULL; return obj->list == NULL;
case TYPE_LAMBDA: case TYPE_LAMBDA:
return obj->lambda == NULL; return obj->lambda == NULL;
case TYPE_STRUCT:
return obj->structObject == NULL;
case TYPE_SYMBOL: case TYPE_SYMBOL:
case TYPE_STRING: case TYPE_STRING:
return obj->string == NULL || obj->string[0] == '\0'; return obj->string == NULL || obj->string[0] == '\0';
@ -109,6 +111,7 @@ inline int isEmpty(const Object* obj)
return 0; return 0;
} }
int allocations = 0;
/** /**
* Allocate a copy of a given object into the given pointer. * Allocate a copy of a given object into the given pointer.
* Does nothing if `spot` is NULL * Does nothing if `spot` is NULL
@ -117,6 +120,12 @@ inline int isEmpty(const Object* obj)
*/ */
void allocObject(Object** spot, const Object src) 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 = malloc(sizeof(struct Object));
**spot = src; **spot = src;
(*spot)->forward = NULL; (*spot)->forward = NULL;
@ -247,6 +256,42 @@ void stringList(char* dest, const Object* obj)
strcat(dest, " )"); 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 * Creates a string from a given Object
* Returns NULL if either param is NULL * 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: case TYPE_SYMBOL:
snprintf(dest, len, "`%s`", obj->string); snprintf(dest, len, "`%s`", obj->string);
break; break;
case TYPE_STRUCT:
//snprintf(dest, len, "{%s}", obj->structObject->definition->names[0]);
stringStruct(dest, obj);
break;
case TYPE_LIST: case TYPE_LIST:
case TYPE_SLIST: case TYPE_SLIST:
stringList(dest, obj); stringList(dest, obj);
@ -335,38 +384,26 @@ void debugObj(const Object* obj)
#if defined(DEBUG) || defined(STANDALONE) #if defined(DEBUG) || defined(STANDALONE)
#define SIMPLE_TYPE(_type) case _type:\
printf(#_type);\
return
void printType(const Object* obj) void printType(const Object* obj)
{ {
switch (obj->type) { switch (obj->type) {
case TYPE_NUMBER: SIMPLE_TYPE(TYPE_NUMBER);
printf("TYPE_NUMBER"); SIMPLE_TYPE(TYPE_STRUCT);
return; SIMPLE_TYPE(TYPE_BOOL);
case TYPE_BOOL: SIMPLE_TYPE(TYPE_LIST);
printf("TYPE_BOOL"); SIMPLE_TYPE(TYPE_SLIST);
return; SIMPLE_TYPE(TYPE_FUNC);
case TYPE_LIST: SIMPLE_TYPE(TYPE_SYMBOL);
printf("TYPE_LIST"); SIMPLE_TYPE(TYPE_STRING);
return; SIMPLE_TYPE(TYPE_OTHER);
case TYPE_SLIST: SIMPLE_TYPE(TYPE_ERROR);
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;
case TYPE_LAMBDA: case TYPE_LAMBDA:
printf("TYPE_LAMBDA Params:\n"); printf("TYPE_LAMBDA Params:\n");
return; return;
case TYPE_OTHER:
printf("TYPE_OTHER: ");
case TYPE_ERROR:
printf("TYPE_ERROR: ");
return;
} }
if (!isValidType(*obj)) { if (!isValidType(*obj)) {
@ -467,10 +504,18 @@ void cleanObject(Object* target)
cleanObject(&target->lambda->body); cleanObject(&target->lambda->body);
free(target->lambda); free(target->lambda);
break; 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: case TYPE_ERROR:
#ifndef SIMPLE_ERRORS #ifndef SIMPLE_ERRORS
free(target->error->context); //free(target->error->context);
free(target->error); //free(target->error);
target->error = NULL; target->error = NULL;
#endif #endif
break; break;
@ -605,6 +650,16 @@ inline Object listObject()
return list; 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 // Returns a list Object starting with the given Object
inline Object startList(const Object start) inline Object startList(const Object start)
{ {
@ -629,6 +684,7 @@ inline int isValidType(const Object test)
case TYPE_NUMBER: case TYPE_NUMBER:
case TYPE_BOOL: case TYPE_BOOL:
case TYPE_LIST: case TYPE_LIST:
case TYPE_STRUCT:
case TYPE_SLIST: case TYPE_SLIST:
case TYPE_FUNC: case TYPE_FUNC:
case TYPE_SYMBOL: case TYPE_SYMBOL:
@ -673,6 +729,8 @@ inline Object cloneOther(const Object src)
return src.other->clone ? src.other->clone(src.other) : src; return src.other->clone ? src.other->clone(src.other) : src;
} }
Object cloneStruct(const Object src);
inline Object cloneObject(const Object src) inline Object cloneObject(const Object src)
{ {
switch (src.type) { switch (src.type) {
@ -681,6 +739,8 @@ inline Object cloneObject(const Object src)
return cloneList(src); return cloneList(src);
case TYPE_LAMBDA: case TYPE_LAMBDA:
return cloneLambda(src); return cloneLambda(src);
case TYPE_STRUCT:
return cloneStruct(src);
case TYPE_STRING: case TYPE_STRING:
case TYPE_SYMBOL: case TYPE_SYMBOL:
return cloneString(src); return cloneString(src);
@ -696,6 +756,16 @@ inline Object cloneObject(const Object src)
return 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) inline Object numberObject(int num)
{ {
Object o = newObject(TYPE_NUMBER); Object o = newObject(TYPE_NUMBER);

View File

@ -72,6 +72,7 @@ typedef enum Type {
TYPE_BOOL, TYPE_BOOL,
TYPE_LIST, TYPE_LIST,
TYPE_SLIST, TYPE_SLIST,
TYPE_STRUCT,
TYPE_FUNC, TYPE_FUNC,
TYPE_SYMBOL, TYPE_SYMBOL,
TYPE_LAMBDA, TYPE_LAMBDA,
@ -81,6 +82,7 @@ typedef enum Type {
} Type; } Type;
typedef struct Object Object; typedef struct Object Object;
struct Lambda; struct Lambda;
struct Environment; struct Environment;
struct Slice; struct Slice;
@ -101,6 +103,7 @@ struct Object {
Object (*func)(Object, Object, struct Environment *); Object (*func)(Object, Object, struct Environment *);
struct StructObject *structObject;
struct Lambda *lambda; struct Lambda *lambda;
struct Other *other; struct Other *other;
#ifdef SIMPLE_ERRORS #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 { struct Lambda {
Object params; Object params;
Object body; Object body;
@ -204,6 +218,8 @@ Object boolObject(int b);
Object numberObject(int num); Object numberObject(int num);
Object structObject(struct StructDef *definition);
Object otherObject(); Object otherObject();
Object errorObject(enum errorCode err); Object errorObject(enum errorCode err);

View File

@ -43,6 +43,52 @@ Object evalDefArgs(const Object* symbol, const Object* value,
return cloneObject(*symbol); 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 evalIfArgs(const Object* argForms, struct Environment* env)
{ {
Object condition = eval(argForms, env); Object condition = eval(argForms, env);
@ -118,6 +164,8 @@ Object evalBuiltIns(const Object* first, const Object* rest,
return evalLambdaArgs(rest); return evalLambdaArgs(rest);
} else if (strcmp(first->string, "map") == 0) { } else if (strcmp(first->string, "map") == 0) {
return evalMapArgs(rest, env); return evalMapArgs(rest, env);
} else if (strcmp(first->string, "struct") == 0) {
return evalStructArgs(rest, rest->forward, env);
} }
return errorObject(BUILT_IN_NOT_FOUND); return errorObject(BUILT_IN_NOT_FOUND);
@ -246,7 +294,6 @@ Object evalList(const Object* obj, struct Environment* env)
} }
Object* first_form = obj->list; Object* first_form = obj->list;
{ // Try to eval built-ins { // Try to eval built-ins
Object builtIn = evalBuiltIns(first_form, first_form->forward, env); Object builtIn = evalBuiltIns(first_form, first_form->forward, env);
@ -257,6 +304,36 @@ Object evalList(const Object* obj, struct Environment* env)
cleanObject(&builtIn); 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 // Evaluate the list based on the first element's type
Object first_eval = eval(first_form, env); Object first_eval = eval(first_form, env);
switch (first_eval.type) { switch (first_eval.type) {
@ -273,6 +350,9 @@ Object evalList(const Object* obj, struct Environment* env)
nf_addToList(&list, first_eval); nf_addToList(&list, first_eval);
FOR_POINTER_IN_LIST(obj) { FOR_POINTER_IN_LIST(obj) {
if (i != 0) { if (i != 0) {
if (isStringy(*POINTER)) {
printf("evalList elementName: %s\n", POINTER->string);
}
nf_addToList(&list, eval(POINTER, env)); nf_addToList(&list, eval(POINTER, env));
} }
i++; i++;
@ -291,6 +371,7 @@ Object eval(const Object* obj, struct Environment* env)
case TYPE_NUMBER: case TYPE_NUMBER:
case TYPE_BOOL: case TYPE_BOOL:
case TYPE_STRING: case TYPE_STRING:
case TYPE_STRUCT:
return cloneObject(*obj); return cloneObject(*obj);
case TYPE_SYMBOL: case TYPE_SYMBOL: