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]);
|
||||
if(strcmp(name, env->strings[i]) == 0) {
|
||||
printd("Returning!\n");
|
||||
return env->objects[i];
|
||||
return cloneObject(env->objects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,10 +191,16 @@ struct Environment defaultEnv()
|
|||
addFunc("=", &equ, &e);
|
||||
addFunc(">", >h, &e);
|
||||
addFunc("<", <h, &e);
|
||||
addFunc("len", &len, &e);
|
||||
|
||||
addFunc("cat", &catObjects, &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;
|
||||
while(codes[i]) {
|
||||
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)
|
||||
{ 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
|
||||
|
@ -207,7 +213,9 @@ static const char *errorText[] = {
|
|||
"LISTS_NOT_SAME_SIZE",
|
||||
"SYMBOLS_CANT_START_WITH_DIGITS",
|
||||
"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);
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
#ifdef STANDALONE
|
||||
snprintf(dest, RESULT_LENGTH, "%s", errorText[(int)(obj->err)]);
|
||||
#else
|
||||
snprintf(dest, RESULT_LENGTH, "E%d", obj->err);
|
||||
#endif
|
||||
break;
|
||||
case TYPE_FUNC:
|
||||
case TYPE_LAMBDA:
|
||||
|
@ -352,7 +364,6 @@ void _printObj(const Object *obj, int newline)
|
|||
printf("%s\n", temp);
|
||||
else
|
||||
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
|
||||
* @param obj The Object to print
|
||||
*/
|
||||
void printObj(const Object *obj)
|
||||
inline void printObj(const Object *obj)
|
||||
{
|
||||
_printObj(obj, 1);
|
||||
}
|
||||
|
@ -661,6 +672,11 @@ inline Object constructLambda(const Object *params, const Object *body)
|
|||
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)
|
||||
{
|
||||
Object o = newObject(TYPE_ERROR);
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#define P1 POINTER
|
||||
#define P2 _element2
|
||||
|
||||
#define SKIP_FIRST() if(_element == _list->list) {continue;}
|
||||
|
||||
enum errorCode {
|
||||
MISMATCHED_PARENS,
|
||||
BAD_LIST_OF_SYMBOL_STRINGS,
|
||||
|
@ -36,7 +34,9 @@ enum errorCode {
|
|||
LISTS_NOT_SAME_SIZE,
|
||||
SYMBOLS_CANT_START_WITH_DIGITS,
|
||||
UNSUPPORTED_NUMBER_TYPE,
|
||||
NOT_A_SYMBOL
|
||||
NOT_A_SYMBOL,
|
||||
ONLY_ONE_ARGUMENT,
|
||||
NOT_A_LIST
|
||||
};
|
||||
|
||||
#define MALLOC_FLAG 64
|
||||
|
@ -101,6 +101,7 @@ void appendList(Object *dest, const Object *src);
|
|||
|
||||
int isStringy(const Object test);
|
||||
int isValidType(const Object test);
|
||||
int isError(const Object obj, const enum errorCode err);
|
||||
|
||||
Object cloneList(const Object src);
|
||||
Object cloneString(Object obj);
|
||||
|
|
|
@ -40,7 +40,7 @@ Object evalMapArgs(const Object *argForms, struct Environment *env)
|
|||
if(!argForms)
|
||||
return errorObject(NULL_MAP_ARGS);
|
||||
|
||||
const Object lambda = eval(argForms, env);
|
||||
Object lambda = eval(argForms, env);
|
||||
const Object *inputList = argForms->forward;
|
||||
|
||||
if(lambda.type != TYPE_LAMBDA || inputList->type != TYPE_LIST)
|
||||
|
@ -61,6 +61,7 @@ Object evalMapArgs(const Object *argForms, struct Environment *env)
|
|||
deleteEnv(&newEnv);
|
||||
cleanObject(&tempList);
|
||||
}
|
||||
cleanObject(&lambda);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
@ -130,18 +131,21 @@ Object eval(const Object *obj, struct Environment *env)
|
|||
eval_forms(rest, obj, env);
|
||||
|
||||
Object func_eval = rest[0];
|
||||
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]);
|
||||
if(length == 1) {
|
||||
func_eval = first_eval.func(
|
||||
func_eval, errorObject(ONLY_ONE_ARGUMENT), env);
|
||||
if(isError(func_eval, ONLY_ONE_ARGUMENT)) // Consider it a partial function
|
||||
return cloneObject(*obj);
|
||||
} 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;
|
||||
|
||||
} 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);
|
||||
Object ret = eval(&first_eval.lambda->body, &newEnv);
|
||||
deleteEnv(&newEnv);
|
||||
cleanObject(&first_eval);
|
||||
return ret;
|
||||
|
||||
} 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,
|
||||
struct Environment *env)
|
||||
{
|
||||
if(isError(*obj2, ONLY_ONE_ARGUMENT))
|
||||
return *obj2;
|
||||
|
||||
int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
|
||||
if(lists == 0) {
|
||||
return _basicOp(obj1, obj2, op, env);
|
||||
|
@ -285,14 +293,56 @@ Object filter(Object obj1, Object obj2, struct Environment *env)
|
|||
FOR_POINTER_IN_LIST(filteringList) {
|
||||
Object conditional = cloneObject(obj1);
|
||||
nf_addToList(&conditional, *POINTER); // cloneObject()?
|
||||
conditional = eval(&conditional, env);
|
||||
if(conditional.number == 1) {
|
||||
Object result = eval(&conditional, env);
|
||||
cleanObject(&conditional);
|
||||
if(result.number == 1) {
|
||||
nf_addToList(&filteredList, *POINTER);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if(!dest || !src)
|
||||
|
@ -343,6 +393,8 @@ Result readSeq(struct Slice *tokens)
|
|||
return result(res, rest);
|
||||
}
|
||||
Result r = parse(tokens);
|
||||
if(r.obj.type == TYPE_ERROR)
|
||||
return r;
|
||||
nf_addToList(&res, cloneObject(r.obj));
|
||||
tokens = r.slices;
|
||||
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')) {
|
||||
return boolObject(0);
|
||||
|
||||
} else if (s->text[0] == '"') {
|
||||
} else if (s->text[0] == '"' || s->text[0] == '\'') {
|
||||
return objFromSlice(s->text, s->length);
|
||||
} else {
|
||||
return symFromSlice(s->text, s->length);
|
||||
|
@ -411,6 +463,8 @@ Object parseEval(const char *input, struct Environment *env)
|
|||
struct Slice *tok = tokens;
|
||||
if(tok[i].text[0] != '(') {
|
||||
Object parsed = parse(tok).obj;
|
||||
if(parsed.type == TYPE_ERROR)
|
||||
return parsed;
|
||||
obj = eval(&parsed, env);
|
||||
cleanObject(&parsed);
|
||||
} else {
|
||||
|
@ -422,6 +476,8 @@ Object parseEval(const char *input, struct Environment *env)
|
|||
if(parens == 0) {
|
||||
cleanObject(&obj);
|
||||
Object parsed = parse(tok).obj;
|
||||
if(parsed.type == TYPE_ERROR)
|
||||
return parsed;
|
||||
tok = &tok[i + 1];
|
||||
i = -1;
|
||||
//printObj(&parsed);
|
||||
|
|
|
@ -50,5 +50,9 @@ BASIC_OP(gth); BASIC_OP(lth);
|
|||
#undef BASIC_OP
|
||||
Object catObjects(const Object obj1, const 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
|
||||
|
|
|
@ -79,8 +79,9 @@ struct Slice *nf_tokenize(const char *input)
|
|||
if(isSingle(input[i])) {
|
||||
i++;
|
||||
|
||||
} else if(input[i] == '"') {
|
||||
while(input[++i] != '"' && input[i] != '\0') {
|
||||
} else if(input[i] == '"' || input[i] == '\'') {
|
||||
const char quote = input[i];
|
||||
while(input[++i] != quote && input[i] != '\0') {
|
||||
l++;
|
||||
}
|
||||
i++;
|
||||
|
|
Loading…
Reference in New Issue