Some new list functions and better error handling
New list functions include (append) (at) (rest) and (reverse). Single quotes now supported for strings.
This commit is contained in:
parent
d041e7c5bb
commit
81d5a545cf
10
src/env.c
10
src/env.c
|
@ -28,7 +28,7 @@ Object fetchFromEnvironment(const char *name, struct Environment *env)
|
||||||
debugObj(&env->objects[i]);
|
debugObj(&env->objects[i]);
|
||||||
if(strcmp(name, env->strings[i]) == 0) {
|
if(strcmp(name, env->strings[i]) == 0) {
|
||||||
printd("Returning!\n");
|
printd("Returning!\n");
|
||||||
return env->objects[i];
|
return cloneObject(env->objects[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,10 +191,16 @@ struct Environment defaultEnv()
|
||||||
addFunc("=", &equ, &e);
|
addFunc("=", &equ, &e);
|
||||||
addFunc(">", >h, &e);
|
addFunc(">", >h, &e);
|
||||||
addFunc("<", <h, &e);
|
addFunc("<", <h, &e);
|
||||||
addFunc("len", &len, &e);
|
|
||||||
addFunc("cat", &catObjects, &e);
|
addFunc("cat", &catObjects, &e);
|
||||||
addFunc("fil", &filter, &e);
|
addFunc("fil", &filter, &e);
|
||||||
|
|
||||||
|
addFunc("len", &len, &e);
|
||||||
|
addFunc("ap", &append, &e);
|
||||||
|
addFunc("at", &at, &e);
|
||||||
|
addFunc("rest", &rest, &e);
|
||||||
|
addFunc("rev", &reverse, &e);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(codes[i]) {
|
while(codes[i]) {
|
||||||
parseEval(codes[i++], &e);
|
parseEval(codes[i++], &e);
|
||||||
|
|
24
src/object.c
24
src/object.c
|
@ -33,7 +33,13 @@ int listLength(const Object *listObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
Object len(Object obj1, Object o_ignore, struct Environment *e_ignore)
|
Object len(Object obj1, Object o_ignore, struct Environment *e_ignore)
|
||||||
{ return numberObject(listLength(&obj1)); }
|
{
|
||||||
|
Object o = numberObject(listLength(&obj1));
|
||||||
|
if(o.number < 0) {
|
||||||
|
return errorObject(NOT_A_LIST);
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a pointer to the Object at the given index in a given list
|
* Returns a pointer to the Object at the given index in a given list
|
||||||
|
@ -207,7 +213,9 @@ static const char *errorText[] = {
|
||||||
"LISTS_NOT_SAME_SIZE",
|
"LISTS_NOT_SAME_SIZE",
|
||||||
"SYMBOLS_CANT_START_WITH_DIGITS",
|
"SYMBOLS_CANT_START_WITH_DIGITS",
|
||||||
"UNSUPPORTED_NUMBER_TYPE",
|
"UNSUPPORTED_NUMBER_TYPE",
|
||||||
"NOT_A_SYMBOL"
|
"NOT_A_SYMBOL",
|
||||||
|
"ONLY_ONE_ARGUMENT",
|
||||||
|
"NOT_A_LIST"
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -285,7 +293,11 @@ char* stringObj(char *dest, const Object *obj)
|
||||||
stringList(dest, obj);
|
stringList(dest, obj);
|
||||||
break;
|
break;
|
||||||
case TYPE_ERROR:
|
case TYPE_ERROR:
|
||||||
|
#ifdef STANDALONE
|
||||||
|
snprintf(dest, RESULT_LENGTH, "%s", errorText[(int)(obj->err)]);
|
||||||
|
#else
|
||||||
snprintf(dest, RESULT_LENGTH, "E%d", obj->err);
|
snprintf(dest, RESULT_LENGTH, "E%d", obj->err);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_LAMBDA:
|
case TYPE_LAMBDA:
|
||||||
|
@ -352,7 +364,6 @@ void _printObj(const Object *obj, int newline)
|
||||||
printf("%s\n", temp);
|
printf("%s\n", temp);
|
||||||
else
|
else
|
||||||
printf("%s", temp);
|
printf("%s", temp);
|
||||||
printErr(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -361,7 +372,7 @@ void _printObj(const Object *obj, int newline)
|
||||||
* If the DEBUG flag is set, the Object's type will be printed first
|
* If the DEBUG flag is set, the Object's type will be printed first
|
||||||
* @param obj The Object to print
|
* @param obj The Object to print
|
||||||
*/
|
*/
|
||||||
void printObj(const Object *obj)
|
inline void printObj(const Object *obj)
|
||||||
{
|
{
|
||||||
_printObj(obj, 1);
|
_printObj(obj, 1);
|
||||||
}
|
}
|
||||||
|
@ -661,6 +672,11 @@ inline Object constructLambda(const Object *params, const Object *body)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int isError(const Object obj, const enum errorCode err)
|
||||||
|
{
|
||||||
|
return obj.type == TYPE_ERROR && obj.err == err;
|
||||||
|
}
|
||||||
|
|
||||||
inline Object errorObject(enum errorCode err)
|
inline Object errorObject(enum errorCode err)
|
||||||
{
|
{
|
||||||
Object o = newObject(TYPE_ERROR);
|
Object o = newObject(TYPE_ERROR);
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
#define P1 POINTER
|
#define P1 POINTER
|
||||||
#define P2 _element2
|
#define P2 _element2
|
||||||
|
|
||||||
#define SKIP_FIRST() if(_element == _list->list) {continue;}
|
|
||||||
|
|
||||||
enum errorCode {
|
enum errorCode {
|
||||||
MISMATCHED_PARENS,
|
MISMATCHED_PARENS,
|
||||||
BAD_LIST_OF_SYMBOL_STRINGS,
|
BAD_LIST_OF_SYMBOL_STRINGS,
|
||||||
|
@ -36,7 +34,9 @@ enum errorCode {
|
||||||
LISTS_NOT_SAME_SIZE,
|
LISTS_NOT_SAME_SIZE,
|
||||||
SYMBOLS_CANT_START_WITH_DIGITS,
|
SYMBOLS_CANT_START_WITH_DIGITS,
|
||||||
UNSUPPORTED_NUMBER_TYPE,
|
UNSUPPORTED_NUMBER_TYPE,
|
||||||
NOT_A_SYMBOL
|
NOT_A_SYMBOL,
|
||||||
|
ONLY_ONE_ARGUMENT,
|
||||||
|
NOT_A_LIST
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MALLOC_FLAG 64
|
#define MALLOC_FLAG 64
|
||||||
|
@ -101,6 +101,7 @@ void appendList(Object *dest, const Object *src);
|
||||||
|
|
||||||
int isStringy(const Object test);
|
int isStringy(const Object test);
|
||||||
int isValidType(const Object test);
|
int isValidType(const Object test);
|
||||||
|
int isError(const Object obj, const enum errorCode err);
|
||||||
|
|
||||||
Object cloneList(const Object src);
|
Object cloneList(const Object src);
|
||||||
Object cloneString(Object obj);
|
Object cloneString(Object obj);
|
||||||
|
|
|
@ -40,7 +40,7 @@ Object evalMapArgs(const Object *argForms, struct Environment *env)
|
||||||
if(!argForms)
|
if(!argForms)
|
||||||
return errorObject(NULL_MAP_ARGS);
|
return errorObject(NULL_MAP_ARGS);
|
||||||
|
|
||||||
const Object lambda = eval(argForms, env);
|
Object lambda = eval(argForms, env);
|
||||||
const Object *inputList = argForms->forward;
|
const Object *inputList = argForms->forward;
|
||||||
|
|
||||||
if(lambda.type != TYPE_LAMBDA || inputList->type != TYPE_LIST)
|
if(lambda.type != TYPE_LAMBDA || inputList->type != TYPE_LIST)
|
||||||
|
@ -61,6 +61,7 @@ Object evalMapArgs(const Object *argForms, struct Environment *env)
|
||||||
deleteEnv(&newEnv);
|
deleteEnv(&newEnv);
|
||||||
cleanObject(&tempList);
|
cleanObject(&tempList);
|
||||||
}
|
}
|
||||||
|
cleanObject(&lambda);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -130,18 +131,21 @@ Object eval(const Object *obj, struct Environment *env)
|
||||||
eval_forms(rest, obj, env);
|
eval_forms(rest, obj, env);
|
||||||
|
|
||||||
Object func_eval = rest[0];
|
Object func_eval = rest[0];
|
||||||
for(int i = 1; i < length; i++) {
|
if(length == 1) {
|
||||||
Object toClean = func_eval;
|
func_eval = first_eval.func(
|
||||||
func_eval = first_eval.func(func_eval, rest[i], env);
|
func_eval, errorObject(ONLY_ONE_ARGUMENT), env);
|
||||||
//if(i != length - 1)
|
if(isError(func_eval, ONLY_ONE_ARGUMENT)) // Consider it a partial function
|
||||||
cleanObject(&toClean);
|
return cloneObject(*obj);
|
||||||
cleanObject(&rest[i]);
|
} else {
|
||||||
|
for(int i = 1; i < length; i++) {
|
||||||
|
Object toClean = func_eval;
|
||||||
|
func_eval = first_eval.func(func_eval, rest[i], env);
|
||||||
|
//if(i != length - 1)
|
||||||
|
cleanObject(&toClean);
|
||||||
|
cleanObject(&rest[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consider the object a partial function
|
|
||||||
if(length == 1)
|
|
||||||
return cloneObject(*obj);
|
|
||||||
|
|
||||||
return func_eval;
|
return func_eval;
|
||||||
|
|
||||||
} else if (first_eval.type == TYPE_LAMBDA) {
|
} else if (first_eval.type == TYPE_LAMBDA) {
|
||||||
|
@ -149,6 +153,7 @@ Object eval(const Object *obj, struct Environment *env)
|
||||||
envForLambda(&first_eval.lambda->params, first_form->forward, env);
|
envForLambda(&first_eval.lambda->params, first_form->forward, env);
|
||||||
Object ret = eval(&first_eval.lambda->body, &newEnv);
|
Object ret = eval(&first_eval.lambda->body, &newEnv);
|
||||||
deleteEnv(&newEnv);
|
deleteEnv(&newEnv);
|
||||||
|
cleanObject(&first_eval);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -233,6 +238,9 @@ Object _basicOp(const Object *obj1, const Object *obj2, const char op,
|
||||||
Object basicOp(const Object *obj1, const Object *obj2, const char op,
|
Object basicOp(const Object *obj1, const Object *obj2, const char op,
|
||||||
struct Environment *env)
|
struct Environment *env)
|
||||||
{
|
{
|
||||||
|
if(isError(*obj2, ONLY_ONE_ARGUMENT))
|
||||||
|
return *obj2;
|
||||||
|
|
||||||
int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
|
int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
|
||||||
if(lists == 0) {
|
if(lists == 0) {
|
||||||
return _basicOp(obj1, obj2, op, env);
|
return _basicOp(obj1, obj2, op, env);
|
||||||
|
@ -285,14 +293,56 @@ Object filter(Object obj1, Object obj2, struct Environment *env)
|
||||||
FOR_POINTER_IN_LIST(filteringList) {
|
FOR_POINTER_IN_LIST(filteringList) {
|
||||||
Object conditional = cloneObject(obj1);
|
Object conditional = cloneObject(obj1);
|
||||||
nf_addToList(&conditional, *POINTER); // cloneObject()?
|
nf_addToList(&conditional, *POINTER); // cloneObject()?
|
||||||
conditional = eval(&conditional, env);
|
Object result = eval(&conditional, env);
|
||||||
if(conditional.number == 1) {
|
cleanObject(&conditional);
|
||||||
|
if(result.number == 1) {
|
||||||
nf_addToList(&filteredList, *POINTER);
|
nf_addToList(&filteredList, *POINTER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return filteredList;
|
return filteredList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object append(Object list, Object newElement, struct Environment *env)
|
||||||
|
{
|
||||||
|
Object newList = cloneObject(list);
|
||||||
|
nf_addToList(&newList, newElement);
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object at(Object index, Object list, struct Environment *env)
|
||||||
|
{
|
||||||
|
return cloneObject(*itemAt(&list, index.number));
|
||||||
|
}
|
||||||
|
|
||||||
|
Object rest(Object list, Object ignore, struct Environment *env)
|
||||||
|
{
|
||||||
|
Object ret = listObject();
|
||||||
|
Object *l = &list;
|
||||||
|
FOR_POINTER_IN_LIST(l) {
|
||||||
|
if(POINTER == l->list)
|
||||||
|
continue;
|
||||||
|
nf_addToList(&ret, *POINTER);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object reverse(Object _list, Object ignore, struct Environment *ignore2)
|
||||||
|
{
|
||||||
|
const Object *list = &_list;
|
||||||
|
Object rev = listObject();
|
||||||
|
|
||||||
|
Object *tail = NULL;
|
||||||
|
FOR_POINTER_IN_LIST(list) {
|
||||||
|
Object *oldTail = tail;
|
||||||
|
allocObject(&tail, cloneObject(*POINTER));
|
||||||
|
if(oldTail)
|
||||||
|
tail->forward = oldTail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rev.list = tail;
|
||||||
|
return rev;
|
||||||
|
}
|
||||||
|
|
||||||
void copySlice(char * dest, struct Slice *src)
|
void copySlice(char * dest, struct Slice *src)
|
||||||
{
|
{
|
||||||
if(!dest || !src)
|
if(!dest || !src)
|
||||||
|
@ -343,6 +393,8 @@ Result readSeq(struct Slice *tokens)
|
||||||
return result(res, rest);
|
return result(res, rest);
|
||||||
}
|
}
|
||||||
Result r = parse(tokens);
|
Result r = parse(tokens);
|
||||||
|
if(r.obj.type == TYPE_ERROR)
|
||||||
|
return r;
|
||||||
nf_addToList(&res, cloneObject(r.obj));
|
nf_addToList(&res, cloneObject(r.obj));
|
||||||
tokens = r.slices;
|
tokens = r.slices;
|
||||||
cleanObject(&r.obj);
|
cleanObject(&r.obj);
|
||||||
|
@ -377,7 +429,7 @@ Object parseAtom(struct Slice *s)
|
||||||
} else if (s->length == 1 && (s->text[0] == 'F' || s->text[0] == 'f')) {
|
} else if (s->length == 1 && (s->text[0] == 'F' || s->text[0] == 'f')) {
|
||||||
return boolObject(0);
|
return boolObject(0);
|
||||||
|
|
||||||
} else if (s->text[0] == '"') {
|
} else if (s->text[0] == '"' || s->text[0] == '\'') {
|
||||||
return objFromSlice(s->text, s->length);
|
return objFromSlice(s->text, s->length);
|
||||||
} else {
|
} else {
|
||||||
return symFromSlice(s->text, s->length);
|
return symFromSlice(s->text, s->length);
|
||||||
|
@ -411,6 +463,8 @@ Object parseEval(const char *input, struct Environment *env)
|
||||||
struct Slice *tok = tokens;
|
struct Slice *tok = tokens;
|
||||||
if(tok[i].text[0] != '(') {
|
if(tok[i].text[0] != '(') {
|
||||||
Object parsed = parse(tok).obj;
|
Object parsed = parse(tok).obj;
|
||||||
|
if(parsed.type == TYPE_ERROR)
|
||||||
|
return parsed;
|
||||||
obj = eval(&parsed, env);
|
obj = eval(&parsed, env);
|
||||||
cleanObject(&parsed);
|
cleanObject(&parsed);
|
||||||
} else {
|
} else {
|
||||||
|
@ -422,6 +476,8 @@ Object parseEval(const char *input, struct Environment *env)
|
||||||
if(parens == 0) {
|
if(parens == 0) {
|
||||||
cleanObject(&obj);
|
cleanObject(&obj);
|
||||||
Object parsed = parse(tok).obj;
|
Object parsed = parse(tok).obj;
|
||||||
|
if(parsed.type == TYPE_ERROR)
|
||||||
|
return parsed;
|
||||||
tok = &tok[i + 1];
|
tok = &tok[i + 1];
|
||||||
i = -1;
|
i = -1;
|
||||||
//printObj(&parsed);
|
//printObj(&parsed);
|
||||||
|
|
|
@ -50,5 +50,9 @@ BASIC_OP(gth); BASIC_OP(lth);
|
||||||
#undef BASIC_OP
|
#undef BASIC_OP
|
||||||
Object catObjects(const Object obj1, const Object obj2, struct Environment *env);
|
Object catObjects(const Object obj1, const Object obj2, struct Environment *env);
|
||||||
Object filter(Object obj1, Object obj2, struct Environment *env);
|
Object filter(Object obj1, Object obj2, struct Environment *env);
|
||||||
|
Object append(Object list, Object newElement, struct Environment *env);
|
||||||
|
Object at(Object index, Object list, struct Environment *env);
|
||||||
|
Object rest(Object list, Object ignore, struct Environment *env);
|
||||||
|
Object reverse(Object _list, Object ignore, struct Environment *ignore2);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -79,8 +79,9 @@ struct Slice *nf_tokenize(const char *input)
|
||||||
if(isSingle(input[i])) {
|
if(isSingle(input[i])) {
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
} else if(input[i] == '"') {
|
} else if(input[i] == '"' || input[i] == '\'') {
|
||||||
while(input[++i] != '"' && input[i] != '\0') {
|
const char quote = input[i];
|
||||||
|
while(input[++i] != quote && input[i] != '\0') {
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
|
|
Loading…
Reference in New Issue