Extremely barebones struct object implementation.
This commit is contained in:
parent
e2c977e95a
commit
6c8ff04711
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
126
src/object.c
126
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);
|
||||
|
|
16
src/object.h
16
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);
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue