Cat with `+`; Related tests. Reordered pebblisp.c

This commit is contained in:
= 2020-05-15 05:43:08 +01:00
parent 4c228f8fb1
commit 58705b4aa9
2 changed files with 91 additions and 84 deletions

View File

@ -9,86 +9,6 @@
#define printf(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__) #define printf(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__)
#endif #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) Object evalDefArgs(const Object *arg_forms, struct Environment *env)
{ {
const Object *newSymbol = arg_forms; const Object *newSymbol = arg_forms;
@ -261,13 +181,16 @@ Object catObjects(const Object obj1, const Object obj2, struct Environment *env)
return o; 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 n1 = obj1->number;
const int n2 = obj2->number; const int n2 = obj2->number;
switch(op){ switch(op){
case '+': case '+':
if(obj1->type == TYPE_STRING || obj2->type == TYPE_STRING)
return catObjects(*obj1, *obj2, env);
return numberObject(n1 + n2); return numberObject(n1 + n2);
case '-': case '-':
return numberObject(n1 - n2); 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); int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
if(lists == 0) { 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 } else if(lists == 1) { // Single operand is applied to each element in list
const Object *listObj = (obj1->type == TYPE_LIST)? obj1 : obj2; 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(); Object newList = listObject();
FOR_POINTER_IN_LIST(listObj) { FOR_POINTER_IN_LIST(listObj) {
Object adding = eval(POINTER, env); Object adding = eval(POINTER, env);
nf_addToList(&newList, _basicOp(&adding, singleObj, op)); nf_addToList(&newList, _basicOp(&adding, singleObj, op, env));
} }
return newList; return newList;
@ -313,7 +236,7 @@ Object basicOp(const Object *obj1, const Object *obj2, const char op,
FOR_POINTERS_IN_LISTS(obj1, obj2) { FOR_POINTERS_IN_LISTS(obj1, obj2) {
const Object ev1 = eval(P1, env); const Object ev1 = eval(P1, env);
const Object ev2 = eval(P2, env); const Object ev2 = eval(P2, env);
nf_addToList(&newList, _basicOp(&ev1, &ev2, op)); nf_addToList(&newList, _basicOp(&ev1, &ev2, op, env));
} }
return newList; return newList;
} else { } else {
@ -337,6 +260,86 @@ BASIC_OP(lth, '<');
#undef BASIC_OP #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) Object parseEval(const char *input, struct Environment *env)
{ {
struct Slice *tokens = nf_tokenize(input); struct Slice *tokens = nf_tokenize(input);

View File

@ -76,6 +76,10 @@ check "FbnciSeq" "(def fib (fn (a) \
))) \ ))) \
(fib 20)" "6765" (fib 20)" "6765"
echo "" 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 if [ "$FAILS" -ne "0" ]; then
echo "$FAILS Tests Failed" echo "$FAILS Tests Failed"