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