Cat with `+`; Related tests. Reordered pebblisp.c
This commit is contained in:
parent
4c228f8fb1
commit
58705b4aa9
171
src/pebblisp.c
171
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);
|
||||
|
|
|
@ -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 "[1;31m$FAILS Tests Failed[0m"
|
||||
|
|
Loading…
Reference in New Issue