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:
= 2020-05-28 15:28:28 +01:00
parent d041e7c5bb
commit 81d5a545cf
6 changed files with 109 additions and 25 deletions

View File

@ -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(">", &gth, &e); addFunc(">", &gth, &e);
addFunc("<", &lth, &e); addFunc("<", &lth, &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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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++;