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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
void addToList(Object *dest, const Object src)
|
||||
{
|
||||
if(!dest || dest->type != TYPE_LIST)
|
||||
return;
|
||||
|
||||
if(dest->list == NULL) {
|
||||
dest->list = malloc(sizeof(struct Object));
|
||||
*dest->list = src;
|
||||
dest->list->forward = NULL;
|
||||
if(isEmpty(dest)) {
|
||||
allocObject(&dest->list, src);
|
||||
return;
|
||||
}
|
||||
|
||||
Object *end = tail(dest);
|
||||
end->forward = malloc(sizeof(struct Object));
|
||||
*end->forward = src;
|
||||
end->forward->forward = NULL;
|
||||
allocObject(&end->forward, src);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Object no;
|
||||
|
@ -221,6 +291,7 @@ inline Object newObject(Type type)
|
|||
return no;
|
||||
}
|
||||
|
||||
// Returns an empty list object
|
||||
inline Object listObject()
|
||||
{
|
||||
Object list = newObject(TYPE_LIST);
|
||||
|
@ -235,10 +306,16 @@ inline Object numberObject(int num)
|
|||
return o;
|
||||
}
|
||||
|
||||
inline Object boolObject(int b)
|
||||
{
|
||||
Object o = newObject(TYPE_BOOL);
|
||||
o.number = b;
|
||||
return o;
|
||||
}
|
||||
|
||||
inline Object symbolObject()
|
||||
{
|
||||
Object o = newObject(TYPE_SYMBOL);
|
||||
return o;
|
||||
return newObject(TYPE_SYMBOL);
|
||||
}
|
||||
|
||||
inline Object lambdaObject()
|
||||
|
|
18
src/object.h
18
src/object.h
|
@ -13,7 +13,8 @@ enum errorCode {
|
|||
NULL_PARSE,
|
||||
NULL_LAMBDA_LIST,
|
||||
LAMBDA_ARGS_NOT_LIST,
|
||||
DID_NOT_FIND_SYMBOL
|
||||
DID_NOT_FIND_SYMBOL,
|
||||
UNEXPECTED_FORM
|
||||
};
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
@ -25,7 +26,8 @@ enum errorCode {
|
|||
"NULL_PARSE",
|
||||
"NULL_LAMBDA_LIST",
|
||||
"LAMBDA_ARGS_NOT_LIST",
|
||||
"DID_NOT_FIND_SYMBOL"
|
||||
"DID_NOT_FIND_SYMBOL",
|
||||
"UNEXPECTED_FORM"
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -50,12 +52,12 @@ struct Object {
|
|||
Object *list;
|
||||
char name[MAX_TOK_LEN];
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
// Maybe better as pointers
|
||||
// Maybe better as pointers?
|
||||
struct Lambda {
|
||||
Object params;
|
||||
Object body;
|
||||
|
@ -66,6 +68,7 @@ void printList(const Object *list);
|
|||
void printObj(const Object *obj);
|
||||
void debugObj(const Object *obj);
|
||||
|
||||
int isEmpty(const Object *obj);
|
||||
Object *tail(const Object *listObj);
|
||||
void addToList(Object *dest, Object src);
|
||||
void deleteList(const Object *dest);
|
||||
|
@ -74,12 +77,15 @@ Object *itemAt(const Object *listObj, int n);
|
|||
void copyList(Object *dest, const Object *src);
|
||||
|
||||
void cleanObject(Object *target);
|
||||
void allocObject(Object **spot, const Object src);
|
||||
|
||||
Object newObject(Type type);
|
||||
Object listObject();
|
||||
Object numberObject(int num);
|
||||
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 constructLambda(const Object *params, const Object *body);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -80,26 +80,25 @@ Result readSeq(struct Slice *tokens)
|
|||
|
||||
Object parseAtom(struct Slice *s)
|
||||
{
|
||||
Object o;
|
||||
o.forward = NULL;
|
||||
if(isDigit(s->text[0])) {
|
||||
o.type = TYPE_NUMBER;
|
||||
o.number = 0;
|
||||
int num = 0;
|
||||
for(int i = 0; i < s->length; i++) {
|
||||
o.number *= 10;
|
||||
o.number += s->text[i] - '0';
|
||||
num *= 10;
|
||||
num += s->text[i] - '0';
|
||||
}
|
||||
return numberObject(num);
|
||||
|
||||
} else if (s->text[0] == 'T' && s->text[1] == '\0') {
|
||||
o.type = TYPE_BOOL;
|
||||
o.number = 1;
|
||||
return boolObject(1);
|
||||
|
||||
} else if (s->text[0] == 'F' && s->text[1] == '\0') {
|
||||
o.type = TYPE_BOOL;
|
||||
o.number = 0;
|
||||
return boolObject(0);
|
||||
|
||||
} else {
|
||||
o.type = TYPE_SYMBOL;
|
||||
Object o = symbolObject();
|
||||
copySlice(o.name, s);
|
||||
return o;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
Object evalDefArgs(const Object *arg_forms, struct Environment *env)
|
||||
|
@ -242,12 +241,8 @@ Object eval(const Object *obj, struct Environment *env)
|
|||
}
|
||||
}
|
||||
case TYPE_LAMBDA:
|
||||
{
|
||||
Object o;
|
||||
o.type = TYPE_ERROR;
|
||||
printf("UNEXPECTED FORM\n");
|
||||
return o;
|
||||
}
|
||||
return errorObject(UNEXPECTED_FORM);
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
@ -292,50 +287,33 @@ void printEnv(struct Environment *env)
|
|||
|
||||
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 n2 = obj2->number;
|
||||
|
||||
switch(op){
|
||||
case '+':
|
||||
o.number = n1 + n2;
|
||||
return o;
|
||||
return numberObject(n1 + n2);
|
||||
case '-':
|
||||
o.number = n1 - n2;
|
||||
return o;
|
||||
return numberObject(n1 - n2);
|
||||
case '*':
|
||||
o.number = n1 * n2;
|
||||
return o;
|
||||
return numberObject(n1 * n2);
|
||||
case '/':
|
||||
o.number = n1 / n2;
|
||||
return o;
|
||||
}
|
||||
return numberObject(n1 / n2);
|
||||
|
||||
o.type = TYPE_BOOL;
|
||||
switch(op) {
|
||||
case '=':
|
||||
o.number = n1 == n2;
|
||||
return o;
|
||||
return boolObject(n1 == n2);
|
||||
case '>':
|
||||
o.number = n1 > n2;
|
||||
return o;
|
||||
return boolObject(n1 > n2);
|
||||
case '<':
|
||||
o.number = n1 < n2;
|
||||
return o;
|
||||
return boolObject(n1 < n2);
|
||||
}
|
||||
|
||||
o = *obj1;
|
||||
return o;
|
||||
return *obj1;
|
||||
}
|
||||
|
||||
#define bopf(_name, _char) \
|
||||
Object _name(Object obj1, Object obj2) \
|
||||
{ \
|
||||
return basicOp(&obj1, &obj2, _char); \
|
||||
}
|
||||
{ return basicOp(&obj1, &obj2, _char); }
|
||||
|
||||
bopf(add, '+');
|
||||
bopf(sub, '-');
|
||||
|
@ -405,9 +383,6 @@ Object parseEval(const char *input, struct Environment *env)
|
|||
}
|
||||
#endif
|
||||
Object parsed = parse(tokens).obj;
|
||||
// printf("PARSEEVAL() PRINTLIST():\n");
|
||||
// debugObject(&parsed);
|
||||
// printf("end PARSEEVAL() PRINTLIST():\n\n");
|
||||
free(tokens);
|
||||
return eval(&parsed, env);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue