Use malloc'd strings. Add filter function

This commit is contained in:
= 2020-05-22 06:16:45 +01:00
parent ba2cf83759
commit 44c9c7a8a1
6 changed files with 146 additions and 112 deletions

View File

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

View File

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

View File

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

View File

@ -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];
@ -379,7 +403,7 @@ Object parseEval(const char *input, struct Environment *env)
debug++; debug++;
} }
} }
#endif #endif
int i = 0; int i = 0;
int parens = 0; int parens = 0;
@ -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);
} }

View File

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

View File

@ -13,7 +13,7 @@ pass() {
} }
fail() { fail() {
echo "$1 test FAILED" echo "$1 test FAILED $2"
((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 "$FAILS Tests Failed" echo "$FAILS Tests Failed"