diff --git a/src/pebblisp.c b/src/pebblisp.c index 2699a4e..4255110 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -9,86 +9,6 @@ #define printf(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__) #endif -void copySlice(char * dest, struct Slice *src) -{ - if(!dest || !src) - return; - strncpy(dest, src->text, src->length); - dest[(int)src->length] = '\0'; -} - -void debugSlice(struct Slice *s) -{ - if(!s) { - printf("NULL SLICE\n"); - return; - } - printf("Debug Slice\n text:'"); - for(int i = 0; i < s->length; i++) { - printf("%c", s->text[i]); - if(s->text[i] == '\0') - printf("NULLCHAR\n"); - } - printf("'\n"); - printf(" length: %d\n", s->length); -} - -Result parse(struct Slice *slices) -{ - struct Slice *token = slices; - if(token && token->text) { - struct Slice *rest = &slices[1]; - if(token->text[0] == '(') { - // todo check for null rest - return readSeq(rest); - } else { // todo error on missing close paren - return result(parseAtom(token), rest); - } - } else { - return result(errorObject(NULL_PARSE), NULL); - } -} - -Result readSeq(struct Slice *tokens) -{ - Object res = listObject(); - for(;;) { - struct Slice *next = tokens; - struct Slice *rest = next->text? &next[1] : NULL; - if(next->text[0] == ')') { - return result(res, rest); - } - Result r = parse(tokens); - nf_addToList(&res, r.obj); - tokens = r.slices; - } -} - -Object parseAtom(struct Slice *s) -{ - if(isDigit(s->text[0])) { - int num = 0; - for(int i = 0; i < s->length; i++) { - num *= 10; - num += s->text[i] - '0'; - } - return numberObject(num); - - } else if (s->text[0] == 'T' && s->length == 1) { - return boolObject(1); - - } else if (s->text[0] == 'F' && s->length == 1) { - return boolObject(0); - - } else if (s->text[0] == '"') { - return objFromSlice(s->text, s->length); - } else { - Object o = symbolObject(); - copySlice(o.name, s); - return o; - } -} - Object evalDefArgs(const Object *arg_forms, struct Environment *env) { const Object *newSymbol = arg_forms; @@ -261,13 +181,16 @@ Object catObjects(const Object obj1, const Object obj2, struct Environment *env) return o; } -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) { const int n1 = obj1->number; const int n2 = obj2->number; switch(op){ case '+': + if(obj1->type == TYPE_STRING || obj2->type == TYPE_STRING) + return catObjects(*obj1, *obj2, env); return numberObject(n1 + n2); case '-': return numberObject(n1 - n2); @@ -294,7 +217,7 @@ Object basicOp(const Object *obj1, const Object *obj2, const char op, { int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST); if(lists == 0) { - return _basicOp(obj1, obj2, op); + return _basicOp(obj1, obj2, op, env); } else if(lists == 1) { // Single operand is applied to each element in list const Object *listObj = (obj1->type == TYPE_LIST)? obj1 : obj2; @@ -303,7 +226,7 @@ Object basicOp(const Object *obj1, const Object *obj2, const char op, Object newList = listObject(); FOR_POINTER_IN_LIST(listObj) { Object adding = eval(POINTER, env); - nf_addToList(&newList, _basicOp(&adding, singleObj, op)); + nf_addToList(&newList, _basicOp(&adding, singleObj, op, env)); } return newList; @@ -313,7 +236,7 @@ Object basicOp(const Object *obj1, const Object *obj2, const char op, FOR_POINTERS_IN_LISTS(obj1, obj2) { const Object ev1 = eval(P1, env); const Object ev2 = eval(P2, env); - nf_addToList(&newList, _basicOp(&ev1, &ev2, op)); + nf_addToList(&newList, _basicOp(&ev1, &ev2, op, env)); } return newList; } else { @@ -337,6 +260,86 @@ BASIC_OP(lth, '<'); #undef BASIC_OP +void copySlice(char * dest, struct Slice *src) +{ + if(!dest || !src) + return; + strncpy(dest, src->text, src->length); + dest[(int)src->length] = '\0'; +} + +void debugSlice(struct Slice *s) +{ + if(!s) { + printf("NULL SLICE\n"); + return; + } + printf("Debug Slice\n text:'"); + for(int i = 0; i < s->length; i++) { + printf("%c", s->text[i]); + if(s->text[i] == '\0') + printf("NULLCHAR\n"); + } + printf("'\n"); + printf(" length: %d\n", s->length); +} + +Result parse(struct Slice *slices) +{ + struct Slice *token = slices; + if(token && token->text) { + struct Slice *rest = &slices[1]; + if(token->text[0] == '(') { + // todo check for null rest + return readSeq(rest); + } else { // todo error on missing close paren + return result(parseAtom(token), rest); + } + } else { + return result(errorObject(NULL_PARSE), NULL); + } +} + +Result readSeq(struct Slice *tokens) +{ + Object res = listObject(); + for(;;) { + struct Slice *next = tokens; + struct Slice *rest = next->text? &next[1] : NULL; + if(next->text[0] == ')') { + return result(res, rest); + } + Result r = parse(tokens); + nf_addToList(&res, r.obj); + tokens = r.slices; + } +} + +Object parseAtom(struct Slice *s) +{ + if(isDigit(s->text[0])) { + int num = 0; + for(int i = 0; i < s->length; i++) { + num *= 10; + num += s->text[i] - '0'; + } + return numberObject(num); + + } else if (s->text[0] == 'T' && s->length == 1) { + return boolObject(1); + + } else if (s->text[0] == 'F' && s->length == 1) { + return boolObject(0); + + } else if (s->text[0] == '"') { + return objFromSlice(s->text, s->length); + } else { + Object o = symbolObject(); + copySlice(o.name, s); + return o; + } +} + Object parseEval(const char *input, struct Environment *env) { struct Slice *tokens = nf_tokenize(input); diff --git a/src/tests.sh b/src/tests.sh index 5ba1a63..cea3b16 100755 --- a/src/tests.sh +++ b/src/tests.sh @@ -76,6 +76,10 @@ check "FbnciSeq" "(def fib (fn (a) \ ))) \ (fib 20)" "6765" 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" +check "CatAssocLeft" "(+ 10 20 \" rascals\")" "30 rascals" if [ "$FAILS" -ne "0" ]; then echo "$FAILS Tests Failed"