Use malloc'd strings. Add filter function
This commit is contained in:
parent
ba2cf83759
commit
44c9c7a8a1
26
src/env.c
26
src/env.c
|
@ -19,12 +19,15 @@ Object fetchFromEnvironment(const char *name, struct Environment *env)
|
||||||
return errorObject(EMPTY_ENV);
|
return errorObject(EMPTY_ENV);
|
||||||
|
|
||||||
printd("Fetching '%s' from env\n", name);
|
printd("Fetching '%s' from env\n", name);
|
||||||
// printEnv(env);
|
|
||||||
for(int i = 0; i < env->size; i++) {
|
for(int i = 0; i < env->size; i++) {
|
||||||
printd("Try %d\n", i);
|
if(env->strings[i] == NULL) {
|
||||||
if(env->strings[i] == NULL)
|
printd("Try %d (NULL)\n", i);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
printd("Try %d (%s)\n", i, env->strings[i]);
|
||||||
|
debugObj(&env->objects[i]);
|
||||||
if(strcmp(name, env->strings[i]) == 0) {
|
if(strcmp(name, env->strings[i]) == 0) {
|
||||||
|
printd("Returning!\n");
|
||||||
return env->objects[i];
|
return env->objects[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +61,7 @@ struct Environment envForLambda(const Object *params, const Object *arg_forms,
|
||||||
|
|
||||||
const Object *march = arg_forms;
|
const Object *march = arg_forms;
|
||||||
for(int i = 0; i < paramCount; i++) {
|
for(int i = 0; i < paramCount; i++) {
|
||||||
const char *newObjName = itemAt(params, i)->name;
|
const char *newObjName = itemAt(params, i)->string;
|
||||||
const Object newEnvObj = eval(march, outer);
|
const Object newEnvObj = eval(march, outer);
|
||||||
addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms?
|
addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms?
|
||||||
march = march->forward;
|
march = march->forward;
|
||||||
|
@ -76,16 +79,12 @@ void addToEnv(struct Environment *env, const char *name, const Object obj)
|
||||||
if(env->strings[i] == NULL) {
|
if(env->strings[i] == NULL) {
|
||||||
env->strings[i] = calloc(sizeof(char), strlen(name) + 1);
|
env->strings[i] = calloc(sizeof(char), strlen(name) + 1);
|
||||||
strncpy(env->strings[i], name, strlen(name));
|
strncpy(env->strings[i], name, strlen(name));
|
||||||
env->objects[i] = obj;
|
env->objects[i] = cloneObject(obj);
|
||||||
// if(obj.type == TYPE_LIST)
|
|
||||||
// copyList(&env->objects[i], &obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(strcmp(env->strings[i], name) == 0) {
|
if(strcmp(env->strings[i], name) == 0) {
|
||||||
cleanObject(&env->objects[i]);
|
cleanObject(&env->objects[i]);
|
||||||
env->objects[i] = obj;
|
env->objects[i] = cloneObject(obj);
|
||||||
// if(obj.type == TYPE_LIST)
|
|
||||||
// copyList(&env->objects[i], &obj);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +101,7 @@ void addToEnv(struct Environment *env, const char *name, const Object obj)
|
||||||
|
|
||||||
env->strings[i] = malloc(strlen(name) + 1);
|
env->strings[i] = malloc(strlen(name) + 1);
|
||||||
strncpy(env->strings[i], name, strlen(name) + 1);
|
strncpy(env->strings[i], name, strlen(name) + 1);
|
||||||
env->objects[i] = obj;
|
env->objects[i] = cloneObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printEnv(struct Environment *env)
|
void printEnv(struct Environment *env)
|
||||||
|
@ -152,7 +151,7 @@ const char *codes[] = {
|
||||||
"))",
|
"))",
|
||||||
|
|
||||||
// Square a
|
// Square a
|
||||||
"(def sq (fn (a) (exp a 2)))",
|
"(def sq (fn (a) (* a a)))",
|
||||||
|
|
||||||
// Cube a
|
// Cube a
|
||||||
"(def cube (fn (a) (exp a 3)))",
|
"(def cube (fn (a) (exp a 3)))",
|
||||||
|
@ -168,7 +167,7 @@ const char *codes[] = {
|
||||||
|
|
||||||
// A demo tip calculator
|
// A demo tip calculator
|
||||||
"(def spent (fn (a) \
|
"(def spent (fn (a) \
|
||||||
(cat \"Tip: $\" \"\" \"\" (/ a 5) \".\" \
|
(cat \"Tip: $\" (/ a 5) \".\" \
|
||||||
(/ (* 100 (% a 5)) 5) \
|
(/ (* 100 (% a 5)) 5) \
|
||||||
) \
|
) \
|
||||||
))",
|
))",
|
||||||
|
@ -194,6 +193,7 @@ struct Environment defaultEnv()
|
||||||
addFunc("<", <h, &e);
|
addFunc("<", <h, &e);
|
||||||
addFunc("len", &len, &e);
|
addFunc("len", &len, &e);
|
||||||
addFunc("cat", &catObjects, &e);
|
addFunc("cat", &catObjects, &e);
|
||||||
|
addFunc("fil", &filter, &e);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(codes[i]) {
|
while(codes[i]) {
|
||||||
|
|
94
src/object.c
94
src/object.c
|
@ -95,7 +95,7 @@ inline int isEmpty(const Object *obj)
|
||||||
case TYPE_LAMBDA:
|
case TYPE_LAMBDA:
|
||||||
return obj->lambda == NULL;
|
return obj->lambda == NULL;
|
||||||
case TYPE_SYMBOL:
|
case TYPE_SYMBOL:
|
||||||
return obj->name[0] == '\0';
|
return obj->string == NULL;
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
return obj->func == NULL;
|
return obj->func == NULL;
|
||||||
case TYPE_ERROR:
|
case TYPE_ERROR:
|
||||||
|
@ -251,11 +251,9 @@ char* stringObj(char *dest, const Object *obj)
|
||||||
|
|
||||||
if(t == TYPE_NUMBER) {
|
if(t == TYPE_NUMBER) {
|
||||||
snprintf(dest, RESULT_LENGTH, "%d", obj->number);
|
snprintf(dest, RESULT_LENGTH, "%d", obj->number);
|
||||||
} else if(t == TYPE_SYMBOL) {
|
|
||||||
snprintf(dest, RESULT_LENGTH, "%s", obj->name);
|
|
||||||
} else if(t == TYPE_BOOL) {
|
} else if(t == TYPE_BOOL) {
|
||||||
snprintf(dest, RESULT_LENGTH, "%s", obj->number ? "T" : "F");
|
snprintf(dest, RESULT_LENGTH, "%s", obj->number ? "T" : "F");
|
||||||
} else if(t == TYPE_STRING) {
|
} else if(t == TYPE_STRING || t == TYPE_SYMBOL) {
|
||||||
snprintf(dest, RESULT_LENGTH, "%s", obj->string);
|
snprintf(dest, RESULT_LENGTH, "%s", obj->string);
|
||||||
} else if(t == TYPE_LIST) {
|
} else if(t == TYPE_LIST) {
|
||||||
stringList(dest, obj);
|
stringList(dest, obj);
|
||||||
|
@ -358,11 +356,12 @@ void printList(const Object *list)
|
||||||
*/
|
*/
|
||||||
void cleanObject(Object *target)
|
void cleanObject(Object *target)
|
||||||
{
|
{
|
||||||
|
//printf("CLEANING:");
|
||||||
if(target == NULL)
|
if(target == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const Type t = target->type;
|
const Type t = target->type;
|
||||||
if(t == TYPE_STRING) {
|
if(t == TYPE_STRING || t == TYPE_SYMBOL) {
|
||||||
free(target->string);
|
free(target->string);
|
||||||
target->string = NULL;
|
target->string = NULL;
|
||||||
} else if(t == TYPE_LIST) {
|
} else if(t == TYPE_LIST) {
|
||||||
|
@ -430,9 +429,8 @@ void _copyList(Object *dest, const Object *src, int delete)
|
||||||
nf_addToList(dest, *POINTER);
|
nf_addToList(dest, *POINTER);
|
||||||
tail(dest)->list = NULL;
|
tail(dest)->list = NULL;
|
||||||
_copyList(tail(dest), POINTER, 0);
|
_copyList(tail(dest), POINTER, 0);
|
||||||
} else if (POINTER->type == TYPE_STRING) {
|
} else if (isStringy(*POINTER)) {
|
||||||
Object t = copyString(*POINTER);
|
nf_addToList(dest, cloneString(*POINTER));
|
||||||
nf_addToList(dest, t);
|
|
||||||
} else {
|
} else {
|
||||||
nf_addToList(dest, *POINTER);
|
nf_addToList(dest, *POINTER);
|
||||||
}
|
}
|
||||||
|
@ -495,6 +493,28 @@ inline Object startList(const Object start)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int isStringy(const Object src)
|
||||||
|
{
|
||||||
|
return src.type == TYPE_STRING || src.type == TYPE_SYMBOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the given lambda with new allocations
|
||||||
|
* Will behave unexpectedly if given something other than a lambda object!
|
||||||
|
*/
|
||||||
|
inline Object cloneLambda(const Object old)
|
||||||
|
{
|
||||||
|
return constructLambda(&old.lambda->params, &old.lambda->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object cloneString(Object obj)
|
||||||
|
{
|
||||||
|
const char* string = obj.string;
|
||||||
|
obj.string = malloc(sizeof(char) * (strlen(string) + 1));
|
||||||
|
strcpy(obj.string, string);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns an Object with a deep copy of the given Object
|
// Returns an Object with a deep copy of the given Object
|
||||||
inline Object cloneList(const Object src)
|
inline Object cloneList(const Object src)
|
||||||
{
|
{
|
||||||
|
@ -505,7 +525,10 @@ inline Object cloneList(const Object src)
|
||||||
|
|
||||||
inline Object cloneObject(const Object src)
|
inline Object cloneObject(const Object src)
|
||||||
{
|
{
|
||||||
return src.type == TYPE_LIST? cloneList(src) : src;
|
return src.type == TYPE_LIST? cloneList(src) :
|
||||||
|
src.type == TYPE_LAMBDA? cloneLambda(src) :
|
||||||
|
isStringy(src)? cloneString(src) :
|
||||||
|
src;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object numberObject(int num)
|
inline Object numberObject(int num)
|
||||||
|
@ -518,44 +541,25 @@ inline Object numberObject(int num)
|
||||||
inline Object boolObject(int b)
|
inline Object boolObject(int b)
|
||||||
{
|
{
|
||||||
Object o = newObject(TYPE_BOOL);
|
Object o = newObject(TYPE_BOOL);
|
||||||
o.number = b;
|
o.number = !!b;
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object symbolObject()
|
// Skips first and last chars! Assumed to be '"'
|
||||||
{
|
|
||||||
return newObject(TYPE_SYMBOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Object lambdaObject()
|
|
||||||
{
|
|
||||||
Object o = newObject(TYPE_LAMBDA);
|
|
||||||
o.lambda = malloc(sizeof(struct Lambda));
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skips first char! Assumed to be '"'
|
|
||||||
inline Object objFromSlice(const char *string, int len)
|
inline Object objFromSlice(const char *string, int len)
|
||||||
{
|
{
|
||||||
Object o = newObject(TYPE_STRING);
|
Object o = symFromSlice(&string[1], len - 1);
|
||||||
o.string = calloc(sizeof(char), len);
|
o.type = TYPE_STRING;
|
||||||
for(int i = 0; i < len - 1; i++) {
|
|
||||||
o.string[i] = string[i + 1];
|
|
||||||
}
|
|
||||||
o.string[len - 1] = '\0';
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
// inline Object objFromString(const char *string)
|
inline Object symFromSlice(const char *string, int len)
|
||||||
// {
|
{
|
||||||
// Object o = newObject(TYPE_STRING);
|
Object o = newObject(TYPE_SYMBOL);
|
||||||
// o.string = calloc(strlen(string) + 1);
|
o.string = calloc(sizeof(char), len + 1);
|
||||||
// for(int i = 0; i < len - 1; i++) {
|
strncpy(o.string, string, len);
|
||||||
// o.string[i] = string[i];
|
return o;
|
||||||
// }
|
}
|
||||||
// o.string[len - 1] = '\0';
|
|
||||||
// return o;
|
|
||||||
// }
|
|
||||||
|
|
||||||
inline Object constructLambda(const Object *params, const Object *body)
|
inline Object constructLambda(const Object *params, const Object *body)
|
||||||
{
|
{
|
||||||
|
@ -565,7 +569,8 @@ inline Object constructLambda(const Object *params, const Object *body)
|
||||||
if(params->type != TYPE_LIST || body->type != TYPE_LIST)
|
if(params->type != TYPE_LIST || body->type != TYPE_LIST)
|
||||||
return errorObject(LAMBDA_ARGS_NOT_LIST);
|
return errorObject(LAMBDA_ARGS_NOT_LIST);
|
||||||
|
|
||||||
Object o = lambdaObject();
|
Object o = newObject(TYPE_LAMBDA);
|
||||||
|
o.lambda = malloc(sizeof(struct Lambda));
|
||||||
o.lambda->params = listObject();
|
o.lambda->params = listObject();
|
||||||
o.lambda->body = listObject();
|
o.lambda->body = listObject();
|
||||||
copyList(&o.lambda->params, params);
|
copyList(&o.lambda->params, params);
|
||||||
|
@ -580,16 +585,9 @@ inline Object errorObject(enum errorCode err)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object copyString(Object obj)
|
|
||||||
{
|
|
||||||
const char* string = obj.string;
|
|
||||||
obj.string = malloc(sizeof(char) * (strlen(string) + 1));
|
|
||||||
strcpy(obj.string, string);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Object toBool(const Object test)
|
inline Object toBool(const Object test)
|
||||||
{
|
{
|
||||||
if(test.number == 0)
|
if(test.number == 0)
|
||||||
return boolObject(0);
|
return boolObject(0);
|
||||||
|
return boolObject(1);
|
||||||
}
|
}
|
||||||
|
|
21
src/object.h
21
src/object.h
|
@ -1,9 +1,8 @@
|
||||||
#ifndef OBJECT_H
|
#ifndef OBJECT_H
|
||||||
#define OBJECT_H
|
#define OBJECT_H
|
||||||
|
|
||||||
#define MAX_TOK_LEN 10 // 11
|
|
||||||
#define MAX_TOK_CNT 128 // 128
|
#define MAX_TOK_CNT 128 // 128
|
||||||
#define MAX_ENV_ELM 25 // 50
|
#define MAX_ENV_ELM 50 // 50
|
||||||
|
|
||||||
#define FOR_POINTER_IN_LIST(_list) \
|
#define FOR_POINTER_IN_LIST(_list) \
|
||||||
for(Object *_element = _list->list; \
|
for(Object *_element = _list->list; \
|
||||||
|
@ -36,7 +35,8 @@ enum errorCode {
|
||||||
UNEXPECTED_FORM,
|
UNEXPECTED_FORM,
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
//#ifdef STANDALONE
|
//#ifdef STANDALONE
|
||||||
|
@ -56,7 +56,8 @@ static const char *errorText[] = {
|
||||||
"UNEXPECTED_FORM",
|
"UNEXPECTED_FORM",
|
||||||
"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"
|
||||||
};
|
};
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
|
@ -84,7 +85,6 @@ struct Object {
|
||||||
union {
|
union {
|
||||||
int number;
|
int number;
|
||||||
Object *list;
|
Object *list;
|
||||||
char name[MAX_TOK_LEN];
|
|
||||||
char *string;
|
char *string;
|
||||||
Object (*func)(Object, Object, struct Environment *);
|
Object (*func)(Object, Object, struct Environment *);
|
||||||
struct Lambda *lambda; // Maybe better as not a pointer?
|
struct Lambda *lambda; // Maybe better as not a pointer?
|
||||||
|
@ -121,20 +121,25 @@ void printAndClean(Object *target);
|
||||||
void allocObject(Object **spot, const Object src);
|
void allocObject(Object **spot, const Object src);
|
||||||
void appendList(Object *dest, const Object *src);
|
void appendList(Object *dest, const Object *src);
|
||||||
|
|
||||||
|
int isStringy(const Object src);
|
||||||
|
|
||||||
|
Object cloneList(const Object src);
|
||||||
|
Object cloneString(Object obj);
|
||||||
|
Object cloneLambda(const Object old);
|
||||||
|
Object cloneObject(const Object src);
|
||||||
|
|
||||||
Object newObject(Type type);
|
Object newObject(Type type);
|
||||||
Object listObject();
|
Object listObject();
|
||||||
Object startList(const Object start);
|
Object startList(const Object start);
|
||||||
Object cloneList(const Object src);
|
|
||||||
Object cloneObject(const Object src);
|
|
||||||
Object lambdaObject();
|
Object lambdaObject();
|
||||||
Object symbolObject();
|
Object symbolObject();
|
||||||
Object objFromSlice(const char *string, int len);
|
Object objFromSlice(const char *string, int len);
|
||||||
|
Object symFromSlice(const char *string, int len);
|
||||||
Object boolObject(int b);
|
Object boolObject(int b);
|
||||||
Object numberObject(int num);
|
Object numberObject(int num);
|
||||||
Object errorObject(enum errorCode err);
|
Object errorObject(enum errorCode err);
|
||||||
Object constructLambda(const Object *params, const Object *body);
|
Object constructLambda(const Object *params, const Object *body);
|
||||||
|
|
||||||
Object copyString(Object obj);
|
|
||||||
// Object version of listLength()
|
// Object version of listLength()
|
||||||
Object len(Object obj1, Object, struct Environment *);
|
Object len(Object obj1, Object, struct Environment *);
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,14 @@
|
||||||
Object evalDefArgs(const Object *argForms, struct Environment *env)
|
Object evalDefArgs(const Object *argForms, struct Environment *env)
|
||||||
{
|
{
|
||||||
const Object *newSymbol = argForms;
|
const Object *newSymbol = argForms;
|
||||||
const char *name = newSymbol->name;
|
const char *name = newSymbol->string;
|
||||||
|
|
||||||
const Object newValue = eval(newSymbol->forward, env);
|
Object newValue = eval(newSymbol->forward, env);
|
||||||
|
|
||||||
addToEnv(env, name, newValue);
|
addToEnv(env, name, newValue);
|
||||||
|
cleanObject(&newValue);
|
||||||
|
|
||||||
return *newSymbol;
|
return cloneObject(*newSymbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalIfArgs(const Object *argForms, struct Environment *env)
|
Object evalIfArgs(const Object *argForms, struct Environment *env)
|
||||||
|
@ -67,13 +68,16 @@ Object evalMapArgs(const Object *argForms, struct Environment *env)
|
||||||
Object evalBuiltIns(const Object *first, const Object *rest,
|
Object evalBuiltIns(const Object *first, const Object *rest,
|
||||||
struct Environment *env)
|
struct Environment *env)
|
||||||
{
|
{
|
||||||
if(strcmp(first->name, "def") == 0) {
|
if(first->type != TYPE_SYMBOL) {
|
||||||
|
return errorObject(NOT_A_SYMBOL);
|
||||||
|
}
|
||||||
|
if(strcmp(first->string, "def") == 0) {
|
||||||
return evalDefArgs(rest, env);
|
return evalDefArgs(rest, env);
|
||||||
} else if(strcmp(first->name, "if") == 0) {
|
} else if(strcmp(first->string, "if") == 0) {
|
||||||
return evalIfArgs(rest, env);
|
return evalIfArgs(rest, env);
|
||||||
} else if(strcmp(first->name, "fn") == 0) {
|
} else if(strcmp(first->string, "fn") == 0) {
|
||||||
return evalLambdaArgs(rest);
|
return evalLambdaArgs(rest);
|
||||||
} else if(strcmp(first->name, "map") == 0) {
|
} else if(strcmp(first->string, "map") == 0) {
|
||||||
return evalMapArgs(rest, env);
|
return evalMapArgs(rest, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,18 +95,14 @@ void eval_forms(Object *destList, const Object *src, struct Environment *env)
|
||||||
|
|
||||||
Object eval(const Object *obj, struct Environment *env)
|
Object eval(const Object *obj, struct Environment *env)
|
||||||
{
|
{
|
||||||
// printf("eval():\n");
|
|
||||||
// printObj(obj);
|
|
||||||
switch(obj->type) {
|
switch(obj->type) {
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
return *obj; // Return as is
|
|
||||||
|
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
return copyString(*obj);
|
return cloneObject(*obj);
|
||||||
|
|
||||||
case TYPE_SYMBOL:
|
case TYPE_SYMBOL:
|
||||||
return fetchFromEnvironment(obj->name, env);
|
return fetchFromEnvironment(obj->string, env);
|
||||||
|
|
||||||
case TYPE_LIST:
|
case TYPE_LIST:
|
||||||
{
|
{
|
||||||
|
@ -138,6 +138,10 @@ Object eval(const Object *obj, struct Environment *env)
|
||||||
cleanObject(&rest[i]);
|
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) {
|
||||||
|
@ -155,6 +159,7 @@ Object eval(const Object *obj, struct Environment *env)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case TYPE_LAMBDA:
|
case TYPE_LAMBDA:
|
||||||
return errorObject(UNEXPECTED_FORM);
|
return errorObject(UNEXPECTED_FORM);
|
||||||
|
|
||||||
|
@ -213,6 +218,8 @@ Object _basicOp(const Object *obj1, const Object *obj2, const char op,
|
||||||
return numberObject(n1 % n2);
|
return numberObject(n1 % n2);
|
||||||
|
|
||||||
case '=':
|
case '=':
|
||||||
|
if(obj1->type == TYPE_STRING || obj2->type == TYPE_STRING)
|
||||||
|
return boolObject(!strcmp(obj1->string, obj2->string));
|
||||||
return boolObject(n1 == n2);
|
return boolObject(n1 == n2);
|
||||||
case '>':
|
case '>':
|
||||||
return boolObject(n1 > n2);
|
return boolObject(n1 > n2);
|
||||||
|
@ -271,6 +278,21 @@ BASIC_OP(lth, '<');
|
||||||
|
|
||||||
#undef BASIC_OP
|
#undef BASIC_OP
|
||||||
|
|
||||||
|
Object filter(Object obj1, Object obj2, struct Environment *env)
|
||||||
|
{
|
||||||
|
Object filteredList = listObject();
|
||||||
|
Object *filteringList = &obj2;
|
||||||
|
FOR_POINTER_IN_LIST(filteringList) {
|
||||||
|
Object conditional = cloneObject(obj1);
|
||||||
|
nf_addToList(&conditional, *POINTER); // cloneObject()?
|
||||||
|
conditional = eval(&conditional, env);
|
||||||
|
if(conditional.number == 1) {
|
||||||
|
nf_addToList(&filteredList, *POINTER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredList;
|
||||||
|
}
|
||||||
|
|
||||||
void copySlice(char * dest, struct Slice *src)
|
void copySlice(char * dest, struct Slice *src)
|
||||||
{
|
{
|
||||||
if(!dest || !src)
|
if(!dest || !src)
|
||||||
|
@ -321,8 +343,9 @@ Result readSeq(struct Slice *tokens)
|
||||||
return result(res, rest);
|
return result(res, rest);
|
||||||
}
|
}
|
||||||
Result r = parse(tokens);
|
Result r = parse(tokens);
|
||||||
nf_addToList(&res, r.obj);
|
nf_addToList(&res, cloneObject(r.obj));
|
||||||
tokens = r.slices;
|
tokens = r.slices;
|
||||||
|
cleanObject(&r.obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,9 +380,7 @@ Object parseAtom(struct Slice *s)
|
||||||
} else if (s->text[0] == '"') {
|
} else if (s->text[0] == '"') {
|
||||||
return objFromSlice(s->text, s->length);
|
return objFromSlice(s->text, s->length);
|
||||||
} else {
|
} else {
|
||||||
Object o = symbolObject();
|
return symFromSlice(s->text, s->length);
|
||||||
copySlice(o.name, s);
|
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,9 +389,12 @@ Object parseEval(const char *input, struct Environment *env)
|
||||||
struct Slice *tokens = nf_tokenize(input);
|
struct Slice *tokens = nf_tokenize(input);
|
||||||
if(!tokens)
|
if(!tokens)
|
||||||
return errorObject(MISMATCHED_PARENS);
|
return errorObject(MISMATCHED_PARENS);
|
||||||
|
if(!tokens->text)
|
||||||
|
return symFromSlice(" ", 1);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
struct Slice *debug = tokens;
|
struct Slice *debug = tokens;
|
||||||
|
printd("start slice\n");
|
||||||
if(debug) {
|
if(debug) {
|
||||||
while(debug->text) {
|
while(debug->text) {
|
||||||
char tok[MAX_TOK_LEN];
|
char tok[MAX_TOK_LEN];
|
||||||
|
@ -400,6 +424,7 @@ Object parseEval(const char *input, struct Environment *env)
|
||||||
Object parsed = parse(tok).obj;
|
Object parsed = parse(tok).obj;
|
||||||
tok = &tok[i + 1];
|
tok = &tok[i + 1];
|
||||||
i = -1;
|
i = -1;
|
||||||
|
//printObj(&parsed);
|
||||||
obj = eval(&parsed, env);
|
obj = eval(&parsed, env);
|
||||||
cleanObject(&parsed);
|
cleanObject(&parsed);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,14 +35,6 @@ void eval_forms(Object *destList, const Object *src, struct Environment *env);
|
||||||
|
|
||||||
Object evalLambdaArgs(const Object *arg_forms);
|
Object evalLambdaArgs(const Object *arg_forms);
|
||||||
|
|
||||||
struct Environment defaultEnv();
|
|
||||||
void deleteEnv(struct Environment *e);
|
|
||||||
void addToEnv(struct Environment *env, const char *name, const Object obj);
|
|
||||||
Object fetchFromEnvironment(const char *name, struct Environment *env);
|
|
||||||
void printEnv(struct Environment *env);
|
|
||||||
struct Environment envForLambda(const Object *params, const Object *arg_forms,
|
|
||||||
struct Environment *outer);
|
|
||||||
|
|
||||||
Result result(Object obj, struct Slice *slices);
|
Result result(Object obj, struct Slice *slices);
|
||||||
|
|
||||||
// Slices
|
// Slices
|
||||||
|
@ -57,5 +49,6 @@ BASIC_OP(mod); BASIC_OP(equ);
|
||||||
BASIC_OP(gth); BASIC_OP(lth);
|
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);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
29
src/tests.sh
29
src/tests.sh
|
@ -13,7 +13,7 @@ pass() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
echo "[1;31m$1 test FAILED[0m"
|
echo "[1;31m$1 test FAILED [0;34m$2[0m"
|
||||||
((FAILS++))
|
((FAILS++))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ check() {
|
||||||
if [ "$output" == "$3" ]; then
|
if [ "$output" == "$3" ]; then
|
||||||
pass $1
|
pass $1
|
||||||
else
|
else
|
||||||
fail $1
|
fail $1 "$2"
|
||||||
echo " Expected '$3' but received '$output'"
|
echo " Expected '$3' but received '$output'"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -51,11 +51,13 @@ echo ""
|
||||||
check "GratrThn" "(> 23847123 19375933)" "T"
|
check "GratrThn" "(> 23847123 19375933)" "T"
|
||||||
check "LessThan" "(< 23847123 19375933)" "F"
|
check "LessThan" "(< 23847123 19375933)" "F"
|
||||||
check "Equality" "(= 987654321 987654321 )" "T"
|
check "Equality" "(= 987654321 987654321 )" "T"
|
||||||
|
check "StringEquality" "(= \"Bean\" \"Bean\" )" "T"
|
||||||
|
check "Stringinequality" "(= \"Beans\" \"Bean\" )" "F"
|
||||||
echo ""
|
echo ""
|
||||||
check "IfReturn" "(if (T) 123456789 987654321)" "123456789"
|
check "IfReturn" "(if (T) 123456789 987654321)" "123456789"
|
||||||
check "IfRetTwo" "(if F 123456789 987654321)" "987654321"
|
check "IfRetTwo" "(if F 123456789 987654321)" "987654321"
|
||||||
check "EmptyCnd" "(if () T F)" "F"
|
check "EmptyCnd" "(if () T F)" "F"
|
||||||
# check "EtyLstLt" "(if (()) T F)" "T"
|
check "EtyLstLt" "(if (()) T F)" "T"
|
||||||
echo ""
|
echo ""
|
||||||
check "RegLists" "(1 2 3 4 5)" "( 1 2 3 4 5 )"
|
check "RegLists" "(1 2 3 4 5)" "( 1 2 3 4 5 )"
|
||||||
check "MultiTypeList" "(10 20 \"rascals\")" "( 10 20 rascals )"
|
check "MultiTypeList" "(10 20 \"rascals\")" "( 10 20 rascals )"
|
||||||
|
@ -68,28 +70,39 @@ check "VWidwSpc" " ( + 1093 102852 ) " "103945"
|
||||||
echo ""
|
echo ""
|
||||||
check "DemoFunc" "(spent 68)" "Tip: \$13.60"
|
check "DemoFunc" "(spent 68)" "Tip: \$13.60"
|
||||||
echo ""
|
echo ""
|
||||||
check "MultStmt" "(def yee (fn (a) (* 10 a))) (yee 5)" "50"
|
check "MultStmt" "(def yee (fn (a) (* 10 a))) ; (yee 5)" "50"
|
||||||
check "DefinMap" "(def yee (fn (a) (* 10 a))) (map yee (5 10 2 (+ 12 0)))" "( 50 100 20 120 )"
|
check "DefinMap" "(def yee (fn (a) (* 10 a))) ; (map yee (5 10 2 (+ 12 0)))" "( 50 100 20 120 )"
|
||||||
check "FbnciSeq" "(def fib (fn (a) \
|
check "FbnciSeq" "(def fib (fn (a) \
|
||||||
(if (< a 2) \
|
(if (< a 2) \
|
||||||
a \
|
a \
|
||||||
(+ (fib (- a 1)) (fib (- a 2))) \
|
(+ (fib (- a 1)) (fib (- a 2))) \
|
||||||
))) \
|
)));\
|
||||||
(fib 20)" "6765"
|
(fib 20)" "6765"
|
||||||
|
check "Factorial" "(def fac (fn (a) \
|
||||||
|
(if (= a 1) \
|
||||||
|
1 \
|
||||||
|
(* a (fac (- a 1)) ) \
|
||||||
|
)));\
|
||||||
|
(fac 11)" "39916800"
|
||||||
echo ""
|
echo ""
|
||||||
check "ExplicitCat" "(cat \"Big\" \" Kitty\")" "Big Kitty"
|
check "ExplicitCat" "(cat \"Big\" \" Kitty\")" "Big Kitty"
|
||||||
check "CatNums" "(cat \"There are \" (+ 2 3) \" kitties\")" "There are 5 kitties"
|
check "CatNums" "(cat \"There are \" (+ 2 3) \" kitties\")" "There are 5 kitties"
|
||||||
check "ImplicitCat" "(+ \"There are \" (* 5 4) \" bonks\")" "There are 20 bonks"
|
check "ImplicitCat" "(+ \"There are \" (* 5 4) \" bonks\")" "There are 20 bonks"
|
||||||
# Not recommended
|
# Mixing of `+` and implicit cat not recommended:
|
||||||
check "CatAssocLeft" "(+ 10 20 \" rascals\")" "30 rascals"
|
check "CatAssocLeft" "(+ 10 20 \" rascals\")" "30 rascals"
|
||||||
echo ""
|
echo ""
|
||||||
|
check "LambdaClone" "(def y (fn (a) (* 10 a))) (def b y) (def y 12345) ((b 5) y)" "( 50 12345 )"
|
||||||
|
echo ""
|
||||||
check "EvalElems" "((* 10 10) 7)" "( 100 7 )"
|
check "EvalElems" "((* 10 10) 7)" "( 100 7 )"
|
||||||
check "Duplicate" "(def dupe (fn (a) (a a a))) (dupe (*10 10))" "( 100 100 100 )"
|
check "Duplicate" "(def dupe (fn (a) (a a a)));(dupe (*10 10))" "( 100 100 100 )"
|
||||||
echo ""
|
echo ""
|
||||||
check "Squaring" "(sq 9876)" "97535376"
|
check "Squaring" "(sq 9876)" "97535376"
|
||||||
check "Cubing" "(cube 81)" "531441"
|
check "Cubing" "(cube 81)" "531441"
|
||||||
check "Exponent" "(exp 9 9)" "387420489"
|
check "Exponent" "(exp 9 9)" "387420489"
|
||||||
echo ""
|
echo ""
|
||||||
|
check "Filtering" "(fil (< 321) (30 300 90 1200 135 801))" "( 1200 801 )"
|
||||||
|
check "MapFilter" "(fil (< 50) (map sq (1 2 3 4 5 6 7 8 9 10 11 12)))" "( 64 81 100 121 144 )"
|
||||||
|
echo ""
|
||||||
|
|
||||||
if [ "$FAILS" -ne "0" ]; then
|
if [ "$FAILS" -ne "0" ]; then
|
||||||
echo "[1;31m$FAILS Tests Failed[0m"
|
echo "[1;31m$FAILS Tests Failed[0m"
|
||||||
|
|
Loading…
Reference in New Issue