Add Object helpers (less redundancy). Add new errs
This commit is contained in:
parent
f2c09c0818
commit
80ca6e1960
95
src/object.c
95
src/object.c
|
@ -52,23 +52,87 @@ Object *tail(const Object *listObj)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given object is empty
|
||||||
|
* BOOL, NUMBER, and ERROR types return true only when 0
|
||||||
|
* LIST, LAMBDA, and FUNC types return true only when NULL
|
||||||
|
* SYMBOL returns true only when it begins with a nullchar
|
||||||
|
* Returns false if obj is NULL
|
||||||
|
*/
|
||||||
|
inline int isEmpty(const Object *obj)
|
||||||
|
{
|
||||||
|
if(obj == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch(obj->type) {
|
||||||
|
case TYPE_NUMBER:
|
||||||
|
case TYPE_BOOL:
|
||||||
|
return obj->number == 0;
|
||||||
|
case TYPE_LIST:
|
||||||
|
return obj->list == NULL;
|
||||||
|
case TYPE_LAMBDA:
|
||||||
|
return obj->lambda == NULL;
|
||||||
|
case TYPE_SYMBOL:
|
||||||
|
return obj->name[0] == '\0';
|
||||||
|
case TYPE_FUNC:
|
||||||
|
return obj->func == NULL;
|
||||||
|
case TYPE_ERROR:
|
||||||
|
return obj->err == 0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void allocObject(Object **spot, const Object src)
|
||||||
|
{
|
||||||
|
*spot = malloc(sizeof(struct Object));
|
||||||
|
**spot = src;
|
||||||
|
(*spot)->forward = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert `src` into list `dest` before index `ind`
|
||||||
|
// Adds to the end if the index is too high.
|
||||||
|
void insertIntoList(Object *dest, int ind, const Object src)
|
||||||
|
{
|
||||||
|
// Only work with non-null list types
|
||||||
|
if(!dest || dest->type != TYPE_LIST || ind < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(isEmpty(dest)) {
|
||||||
|
allocObject(&dest->list, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Check for off-by-one errors
|
||||||
|
// ensure pointers connect old and new
|
||||||
|
Object *march = dest->list;
|
||||||
|
for(int i = 1; i < ind; i++) {
|
||||||
|
if(march->forward == NULL) {
|
||||||
|
allocObject(&march->forward, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
march = march->forward;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save and re-apply current march->forward
|
||||||
|
Object *oldForward = march->forward;
|
||||||
|
allocObject(&march->forward, src);
|
||||||
|
march->forward->forward = oldForward;
|
||||||
|
}
|
||||||
|
|
||||||
// Adds an object to the end of a list object
|
// Adds an object to the end of a list object
|
||||||
void addToList(Object *dest, const Object src)
|
void addToList(Object *dest, const Object src)
|
||||||
{
|
{
|
||||||
if(!dest || dest->type != TYPE_LIST)
|
if(!dest || dest->type != TYPE_LIST)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(dest->list == NULL) {
|
if(isEmpty(dest)) {
|
||||||
dest->list = malloc(sizeof(struct Object));
|
allocObject(&dest->list, src);
|
||||||
*dest->list = src;
|
|
||||||
dest->list->forward = NULL;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *end = tail(dest);
|
Object *end = tail(dest);
|
||||||
end->forward = malloc(sizeof(struct Object));
|
allocObject(&end->forward, src);
|
||||||
*end->forward = src;
|
|
||||||
end->forward->forward = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void printErr(const Object *obj)
|
void printErr(const Object *obj)
|
||||||
|
@ -200,6 +264,11 @@ void deleteList(const Object *dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all items from `src` to `dest`
|
||||||
|
* Does nothing if either is NULL, or neither are lists
|
||||||
|
* First deletes all items from `dest`
|
||||||
|
*/
|
||||||
void copyList(Object *dest, const Object *src)
|
void copyList(Object *dest, const Object *src)
|
||||||
{
|
{
|
||||||
if(!dest || !src || dest->type != TYPE_LIST || src->type != TYPE_LIST)
|
if(!dest || !src || dest->type != TYPE_LIST || src->type != TYPE_LIST)
|
||||||
|
@ -213,6 +282,7 @@ void copyList(Object *dest, const Object *src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a basic object with NULL forward and the given `type`
|
||||||
inline Object newObject(Type type)
|
inline Object newObject(Type type)
|
||||||
{
|
{
|
||||||
Object no;
|
Object no;
|
||||||
|
@ -221,6 +291,7 @@ inline Object newObject(Type type)
|
||||||
return no;
|
return no;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns an empty list object
|
||||||
inline Object listObject()
|
inline Object listObject()
|
||||||
{
|
{
|
||||||
Object list = newObject(TYPE_LIST);
|
Object list = newObject(TYPE_LIST);
|
||||||
|
@ -235,10 +306,16 @@ inline Object numberObject(int num)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Object boolObject(int b)
|
||||||
|
{
|
||||||
|
Object o = newObject(TYPE_BOOL);
|
||||||
|
o.number = b;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
inline Object symbolObject()
|
inline Object symbolObject()
|
||||||
{
|
{
|
||||||
Object o = newObject(TYPE_SYMBOL);
|
return newObject(TYPE_SYMBOL);
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object lambdaObject()
|
inline Object lambdaObject()
|
||||||
|
|
18
src/object.h
18
src/object.h
|
@ -13,7 +13,8 @@ enum errorCode {
|
||||||
NULL_PARSE,
|
NULL_PARSE,
|
||||||
NULL_LAMBDA_LIST,
|
NULL_LAMBDA_LIST,
|
||||||
LAMBDA_ARGS_NOT_LIST,
|
LAMBDA_ARGS_NOT_LIST,
|
||||||
DID_NOT_FIND_SYMBOL
|
DID_NOT_FIND_SYMBOL,
|
||||||
|
UNEXPECTED_FORM
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
|
@ -25,7 +26,8 @@ enum errorCode {
|
||||||
"NULL_PARSE",
|
"NULL_PARSE",
|
||||||
"NULL_LAMBDA_LIST",
|
"NULL_LAMBDA_LIST",
|
||||||
"LAMBDA_ARGS_NOT_LIST",
|
"LAMBDA_ARGS_NOT_LIST",
|
||||||
"DID_NOT_FIND_SYMBOL"
|
"DID_NOT_FIND_SYMBOL",
|
||||||
|
"UNEXPECTED_FORM"
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -50,12 +52,12 @@ struct Object {
|
||||||
Object *list;
|
Object *list;
|
||||||
char name[MAX_TOK_LEN];
|
char name[MAX_TOK_LEN];
|
||||||
Object (*func)(Object, Object);
|
Object (*func)(Object, Object);
|
||||||
struct Lambda *lambda; // Maybe better as not a pointer
|
struct Lambda *lambda; // Maybe better as not a pointer?
|
||||||
enum errorCode err;
|
enum errorCode err;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Maybe better as pointers
|
// Maybe better as pointers?
|
||||||
struct Lambda {
|
struct Lambda {
|
||||||
Object params;
|
Object params;
|
||||||
Object body;
|
Object body;
|
||||||
|
@ -66,6 +68,7 @@ void printList(const Object *list);
|
||||||
void printObj(const Object *obj);
|
void printObj(const Object *obj);
|
||||||
void debugObj(const Object *obj);
|
void debugObj(const Object *obj);
|
||||||
|
|
||||||
|
int isEmpty(const Object *obj);
|
||||||
Object *tail(const Object *listObj);
|
Object *tail(const Object *listObj);
|
||||||
void addToList(Object *dest, Object src);
|
void addToList(Object *dest, Object src);
|
||||||
void deleteList(const Object *dest);
|
void deleteList(const Object *dest);
|
||||||
|
@ -74,12 +77,15 @@ Object *itemAt(const Object *listObj, int n);
|
||||||
void copyList(Object *dest, const Object *src);
|
void copyList(Object *dest, const Object *src);
|
||||||
|
|
||||||
void cleanObject(Object *target);
|
void cleanObject(Object *target);
|
||||||
|
void allocObject(Object **spot, const Object src);
|
||||||
|
|
||||||
Object newObject(Type type);
|
Object newObject(Type type);
|
||||||
Object listObject();
|
Object listObject();
|
||||||
Object numberObject(int num);
|
|
||||||
Object lambdaObject();
|
Object lambdaObject();
|
||||||
Object constructLambda(const Object *params, const Object *body);
|
Object symbolObject();
|
||||||
|
Object boolObject(int b);
|
||||||
|
Object numberObject(int num);
|
||||||
Object errorObject(enum errorCode err);
|
Object errorObject(enum errorCode err);
|
||||||
|
Object constructLambda(const Object *params, const Object *body);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -80,26 +80,25 @@ Result readSeq(struct Slice *tokens)
|
||||||
|
|
||||||
Object parseAtom(struct Slice *s)
|
Object parseAtom(struct Slice *s)
|
||||||
{
|
{
|
||||||
Object o;
|
|
||||||
o.forward = NULL;
|
|
||||||
if(isDigit(s->text[0])) {
|
if(isDigit(s->text[0])) {
|
||||||
o.type = TYPE_NUMBER;
|
int num = 0;
|
||||||
o.number = 0;
|
|
||||||
for(int i = 0; i < s->length; i++) {
|
for(int i = 0; i < s->length; i++) {
|
||||||
o.number *= 10;
|
num *= 10;
|
||||||
o.number += s->text[i] - '0';
|
num += s->text[i] - '0';
|
||||||
}
|
}
|
||||||
|
return numberObject(num);
|
||||||
|
|
||||||
} else if (s->text[0] == 'T' && s->text[1] == '\0') {
|
} else if (s->text[0] == 'T' && s->text[1] == '\0') {
|
||||||
o.type = TYPE_BOOL;
|
return boolObject(1);
|
||||||
o.number = 1;
|
|
||||||
} else if (s->text[0] == 'F' && s->text[1] == '\0') {
|
} else if (s->text[0] == 'F' && s->text[1] == '\0') {
|
||||||
o.type = TYPE_BOOL;
|
return boolObject(0);
|
||||||
o.number = 0;
|
|
||||||
} else {
|
} else {
|
||||||
o.type = TYPE_SYMBOL;
|
Object o = symbolObject();
|
||||||
copySlice(o.name, s);
|
copySlice(o.name, s);
|
||||||
}
|
|
||||||
return o;
|
return o;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalDefArgs(const Object *arg_forms, struct Environment *env)
|
Object evalDefArgs(const Object *arg_forms, struct Environment *env)
|
||||||
|
@ -242,12 +241,8 @@ Object eval(const Object *obj, struct Environment *env)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case TYPE_LAMBDA:
|
case TYPE_LAMBDA:
|
||||||
{
|
return errorObject(UNEXPECTED_FORM);
|
||||||
Object o;
|
|
||||||
o.type = TYPE_ERROR;
|
|
||||||
printf("UNEXPECTED FORM\n");
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -292,50 +287,33 @@ void printEnv(struct Environment *env)
|
||||||
|
|
||||||
Object basicOp(Object *obj1, Object *obj2, const char op)
|
Object basicOp(Object *obj1, Object *obj2, const char op)
|
||||||
{
|
{
|
||||||
Object o;
|
|
||||||
o.forward = NULL;
|
|
||||||
|
|
||||||
o.type = TYPE_NUMBER;
|
|
||||||
const int n1 = obj1->number;
|
const int n1 = obj1->number;
|
||||||
const int n2 = obj2->number;
|
const int n2 = obj2->number;
|
||||||
|
|
||||||
switch(op){
|
switch(op){
|
||||||
case '+':
|
case '+':
|
||||||
o.number = n1 + n2;
|
return numberObject(n1 + n2);
|
||||||
return o;
|
|
||||||
case '-':
|
case '-':
|
||||||
o.number = n1 - n2;
|
return numberObject(n1 - n2);
|
||||||
return o;
|
|
||||||
case '*':
|
case '*':
|
||||||
o.number = n1 * n2;
|
return numberObject(n1 * n2);
|
||||||
return o;
|
|
||||||
case '/':
|
case '/':
|
||||||
o.number = n1 / n2;
|
return numberObject(n1 / n2);
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
o.type = TYPE_BOOL;
|
|
||||||
switch(op) {
|
|
||||||
case '=':
|
case '=':
|
||||||
o.number = n1 == n2;
|
return boolObject(n1 == n2);
|
||||||
return o;
|
|
||||||
case '>':
|
case '>':
|
||||||
o.number = n1 > n2;
|
return boolObject(n1 > n2);
|
||||||
return o;
|
|
||||||
case '<':
|
case '<':
|
||||||
o.number = n1 < n2;
|
return boolObject(n1 < n2);
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
o = *obj1;
|
return *obj1;
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define bopf(_name, _char) \
|
#define bopf(_name, _char) \
|
||||||
Object _name(Object obj1, Object obj2) \
|
Object _name(Object obj1, Object obj2) \
|
||||||
{ \
|
{ return basicOp(&obj1, &obj2, _char); }
|
||||||
return basicOp(&obj1, &obj2, _char); \
|
|
||||||
}
|
|
||||||
|
|
||||||
bopf(add, '+');
|
bopf(add, '+');
|
||||||
bopf(sub, '-');
|
bopf(sub, '-');
|
||||||
|
@ -405,9 +383,6 @@ Object parseEval(const char *input, struct Environment *env)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Object parsed = parse(tokens).obj;
|
Object parsed = parse(tokens).obj;
|
||||||
// printf("PARSEEVAL() PRINTLIST():\n");
|
|
||||||
// debugObject(&parsed);
|
|
||||||
// printf("end PARSEEVAL() PRINTLIST():\n\n");
|
|
||||||
free(tokens);
|
free(tokens);
|
||||||
return eval(&parsed, env);
|
return eval(&parsed, env);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue