Added TODO. Text size adjusts with code length

Can handle hex and binary. Other cleanup

All tests pass
This commit is contained in:
= 2020-08-02 21:16:26 +01:00
parent 796a4cdc91
commit a5ecb1b3aa
11 changed files with 232 additions and 140 deletions

View File

@ -1,6 +1,11 @@
# PebbLisp # PebbLisp
A very basic LISP implementation with an interpreter and editor written for the Pebble. A very basic LISP implementation with an interpreter and editor written for the Pebble.
# TODO
- Call scripts from scripts
- Call more pebble functions
- Maybe hard-code more built-in functions to ease up on memory use
# Writing in PebbLisp # Writing in PebbLisp
PebbLisp includes several built-ins functionalities. PebbLisp includes several built-ins functionalities.

View File

@ -52,6 +52,27 @@ static void cycle_tokens(ClickRecognizerRef recognizer, void *context)
updateText(); updateText();
} }
static const char *fonts[] = {
FONT_KEY_GOTHIC_28_BOLD,
FONT_KEY_GOTHIC_24_BOLD,
FONT_KEY_GOTHIC_18_BOLD,
FONT_KEY_GOTHIC_14_BOLD
};
static const int smallestFont = 3;
static void adjustFont()
{
int i = 0;
while(temptext[i++]) {}
int f = i < 50 ? smallestFont - 3 :
i < 100 ? smallestFont - 2 :
i < 130 ? smallestFont - 1 :
smallestFont;
text_layer_set_font(s_input_text_layer,
fonts_get_system_font(fonts[f]));
}
/** /**
* In normal token list, backspace if possible, otherwise return to script list * In normal token list, backspace if possible, otherwise return to script list
* In function token list, return to normal token list * In function token list, return to normal token list
@ -69,6 +90,7 @@ static void click_backspace(ClickRecognizerRef recognizer, void *context)
using_func_tokens = false; using_func_tokens = false;
updateText(); updateText();
} }
adjustFont();
} }
// Adds the current string to the main string // Adds the current string to the main string
@ -79,7 +101,9 @@ static void add_token()
if(using_func_tokens) { if(using_func_tokens) {
using_func_tokens = false; using_func_tokens = false;
} }
updateText(); updateText();
adjustFont();
} }
/** Code running and saving **/ /** Code running and saving **/
@ -160,6 +184,7 @@ static void code_window_load(Window *window)
if(persist_exists(current_code)) { if(persist_exists(current_code)) {
persist_read_string(current_code, mytext, SMAX_LENGTH); persist_read_string(current_code, mytext, SMAX_LENGTH);
updateText(); updateText();
adjustFont();
} }
} }

View File

@ -31,7 +31,6 @@ int current_code;
// Currently selected button, starts on '(' // Currently selected button, starts on '('
static int8_t selected_token = 1; static int8_t selected_token = 1;
// PebbLisp environment // PebbLisp environment
static struct Environment env; static struct Environment env;
@ -49,7 +48,7 @@ const char *tokens[] = {
"+ ", "- ", "* ", "/ ", "+ ", "- ", "* ", "/ ",
"1","2","3", "1","2","3",
"4","5","6", "4","5","6",
"7","8","9", "0", "7","8","9", "0", "x",
"a", "b", "c", "d", "e", "a", "b", "c", "d", "e",
"= ", "< ", "> ", "= ", "< ", "> ",
"\"", "\"",
@ -63,7 +62,6 @@ const char *func_tokens[] = {
"spent ", "window ", "spent ", "window ",
"max ", "min ", "max ", "min ",
"sq ", "cube ", "exp " "sq ", "cube ", "exp "
}; };
bool using_func_tokens = false; bool using_func_tokens = false;

View File

@ -62,6 +62,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)->string; const char *newObjName = itemAt(params, i)->string;
// Eval the `march` list
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;
@ -172,6 +173,10 @@ const char *codes[] = {
) \ ) \
))", ))",
"(def r (fn (L) \
(if (= L () \
",
NULL NULL
}; };

View File

@ -3,7 +3,7 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#define RESULT_LENGTH 20 #define RESULT_LENGTH 30
#ifdef DEBUG #ifdef DEBUG
#define printd(...) printf(__VA_ARGS__) #define printd(...) printf(__VA_ARGS__)
@ -211,7 +211,7 @@ static const char *errorText[] = {
"BAD_TYPE", "BAD_TYPE",
"UNEXPECTED_FORM", "UNEXPECTED_FORM",
"LISTS_NOT_SAME_SIZE", "LISTS_NOT_SAME_SIZE",
"SYMBOLS_CANT_START_WITH_DIGITS", "BAD_NUMBER",
"UNSUPPORTED_NUMBER_TYPE", "UNSUPPORTED_NUMBER_TYPE",
"NOT_A_SYMBOL", "NOT_A_SYMBOL",
"ONLY_ONE_ARGUMENT", "ONLY_ONE_ARGUMENT",

View File

@ -5,6 +5,7 @@
#define MAX_ENV_ELM 50 // 50 #define MAX_ENV_ELM 50 // 50
#define FOR_POINTER_IN_LIST(_list) \ #define FOR_POINTER_IN_LIST(_list) \
if(_list && _list->type == TYPE_LIST) \
for(Object *_element = _list->list; \ for(Object *_element = _list->list; \
_element != NULL;\ _element != NULL;\
_element = _element->forward) _element = _element->forward)
@ -32,7 +33,7 @@ enum errorCode {
BAD_TYPE, BAD_TYPE,
UNEXPECTED_FORM, UNEXPECTED_FORM,
LISTS_NOT_SAME_SIZE, LISTS_NOT_SAME_SIZE,
SYMBOLS_CANT_START_WITH_DIGITS, BAD_NUMBER,
UNSUPPORTED_NUMBER_TYPE, UNSUPPORTED_NUMBER_TYPE,
NOT_A_SYMBOL, NOT_A_SYMBOL,
ONLY_ONE_ARGUMENT, ONLY_ONE_ARGUMENT,
@ -65,12 +66,11 @@ struct Object {
Object *list; Object *list;
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;
enum errorCode err; enum errorCode err;
}; };
}; };
// Maybe better as pointers?
struct Lambda { struct Lambda {
Object params; Object params;
Object body; Object body;
@ -81,7 +81,6 @@ void printList(const Object *list);
void printObj(const Object *obj); void printObj(const Object *obj);
void debugObj(const Object *obj); void debugObj(const Object *obj);
void printErr(const Object *obj); void printErr(const Object *obj);
int getType(const Object *obj);
int isEmpty(const Object *obj); int isEmpty(const Object *obj);
Object *tail(const Object *listObj); Object *tail(const Object *listObj);

View File

@ -24,15 +24,17 @@ Object evalDefArgs(const Object *argForms, struct Environment *env)
Object evalIfArgs(const Object *argForms, struct Environment *env) Object evalIfArgs(const Object *argForms, struct Environment *env)
{ {
return eval(argForms, env).number? return eval(argForms, env).number ?
eval(argForms->forward, env) : eval(argForms->forward, env) :
eval(argForms->forward->forward, env); eval(argForms->forward->forward, env);
} }
Object evalLambdaArgs(const Object *argForms) Object evalLambdaArgs(const Object *argForms)
{ {
// params // body return constructLambda(
return constructLambda(argForms, argForms? argForms->forward : NULL); argForms, // Params
argForms ? argForms->forward : NULL // Body
);
} }
Object evalMapArgs(const Object *argForms, struct Environment *env) Object evalMapArgs(const Object *argForms, struct Environment *env)
@ -42,12 +44,11 @@ Object evalMapArgs(const Object *argForms, struct Environment *env)
Object lambda = eval(argForms, env); Object lambda = eval(argForms, env);
const Object *inputList = argForms->forward; const Object *inputList = argForms->forward;
Object outputList = listObject();
if(lambda.type != TYPE_LAMBDA || inputList->type != TYPE_LIST) if(lambda.type != TYPE_LAMBDA)
return errorObject(BAD_TYPE); return errorObject(BAD_TYPE);
Object list = listObject();
FOR_POINTER_IN_LIST(inputList) { FOR_POINTER_IN_LIST(inputList) {
// Create a new list for each element, // Create a new list for each element,
// since lambda evaluation looks for a list // since lambda evaluation looks for a list
@ -57,13 +58,13 @@ Object evalMapArgs(const Object *argForms, struct Environment *env)
struct Environment newEnv = envForLambda(params, &tempList, env); struct Environment newEnv = envForLambda(params, &tempList, env);
// Add the lambda evaluation to the list // Add the lambda evaluation to the list
nf_addToList(&list, eval(&lambda.lambda->body, &newEnv)); nf_addToList(&outputList, eval(&lambda.lambda->body, &newEnv));
deleteEnv(&newEnv); deleteEnv(&newEnv);
cleanObject(&tempList); cleanObject(&tempList);
} }
cleanObject(&lambda); cleanObject(&lambda);
return list; return outputList;
} }
Object evalBuiltIns(const Object *first, const Object *rest, Object evalBuiltIns(const Object *first, const Object *rest,
@ -72,6 +73,7 @@ Object evalBuiltIns(const Object *first, const Object *rest,
if(first->type != TYPE_SYMBOL) { if(first->type != TYPE_SYMBOL) {
return errorObject(NOT_A_SYMBOL); return errorObject(NOT_A_SYMBOL);
} }
if(strcmp(first->string, "def") == 0) { if(strcmp(first->string, "def") == 0) {
return evalDefArgs(rest, env); return evalDefArgs(rest, env);
} else if(strcmp(first->string, "if") == 0) { } else if(strcmp(first->string, "if") == 0) {
@ -85,7 +87,7 @@ Object evalBuiltIns(const Object *first, const Object *rest,
return errorObject(BUILT_IN_NOT_FOUND); return errorObject(BUILT_IN_NOT_FOUND);
} }
void eval_forms(Object *destList, const Object *src, struct Environment *env) void evalForms(Object *destList, const Object *src, struct Environment *env)
{ {
int length = listLength(src) - 1; // Not counting first_form int length = listLength(src) - 1; // Not counting first_form
for(int i = 0; i < length; i++) { // Evaluates all in list for(int i = 0; i < length; i++) { // Evaluates all in list
@ -94,9 +96,82 @@ void eval_forms(Object *destList, const Object *src, struct Environment *env)
} }
} }
Object evalList(const Object *obj, struct Environment *env)
{
const int evalLength = listLength(obj);
if(evalLength == 0)
return cloneObject(*obj);
if(evalLength == 1) {
if(listLength(obj->list) == 0)
return cloneObject(*obj);
return eval(obj->list, env);
}
Object *first_form = obj->list;
{ // Try to eval built-ins
const Object builtIn =
evalBuiltIns(first_form, first_form->forward, env);
if(!isError(builtIn, BUILT_IN_NOT_FOUND) &&
!isError(builtIn, NOT_A_SYMBOL)) {
return builtIn;
}
}
Object first_eval = eval(first_form, env);
if(first_eval.type == TYPE_FUNC) {
int length = evalLength - 1; // Not counting first_form
Object rest[length];
evalForms(rest, obj, env);
Object func_eval = rest[0];
if(length == 1) {
func_eval = first_eval.func(
func_eval, errorObject(ONLY_ONE_ARGUMENT), env);
// Consider it a partial function if only one arg
if(isError(func_eval, ONLY_ONE_ARGUMENT))
return cloneObject(*obj);
} else {
for(int i = 1; i < length; i++) {
Object toClean = func_eval;
func_eval = first_eval.func(func_eval, rest[i], env);
cleanObject(&toClean);
cleanObject(&rest[i]);
}
}
return func_eval;
} else if (first_eval.type == TYPE_LAMBDA) {
struct Environment newEnv = envForLambda(
&first_eval.lambda->params,
first_form->forward,
env
);
Object ret = eval(&first_eval.lambda->body, &newEnv);
deleteEnv(&newEnv);
cleanObject(&first_eval);
return ret;
} else {
Object list = listObject();
FOR_POINTER_IN_LIST(obj) {
nf_addToList(&list, eval(POINTER, env));
}
return list;
}
}
Object eval(const Object *obj, struct Environment *env) Object eval(const Object *obj, struct Environment *env)
{ {
switch(obj->type) { switch(obj->type) {
case TYPE_ERROR:
case TYPE_FUNC:
return *obj;
case TYPE_NUMBER: case TYPE_NUMBER:
case TYPE_BOOL: case TYPE_BOOL:
case TYPE_STRING: case TYPE_STRING:
@ -106,79 +181,13 @@ Object eval(const Object *obj, struct Environment *env)
return fetchFromEnvironment(obj->string, env); return fetchFromEnvironment(obj->string, env);
case TYPE_LIST: case TYPE_LIST:
{ return evalList(obj, env);
if(listLength(obj) == 0)
return *obj;
if(listLength(obj) == 1)
return eval(obj->list, env);
Object *first_form = obj->list;
{ // Try to eval built-ins
const Object builtIn =
evalBuiltIns(first_form, first_form->forward, env);
if(builtIn.type != TYPE_ERROR) {
return builtIn;
}
}
Object first_eval = eval(first_form, env);
if(first_eval.type == TYPE_FUNC) {
int length = listLength(obj) - 1; // Not counting first_form
Object rest[length];
eval_forms(rest, obj, env);
Object func_eval = rest[0];
if(length == 1) {
func_eval = first_eval.func(
func_eval, errorObject(ONLY_ONE_ARGUMENT), env);
if(isError(func_eval, ONLY_ONE_ARGUMENT)) // Consider it a partial function
return cloneObject(*obj);
} else {
for(int i = 1; i < length; i++) {
Object toClean = func_eval;
func_eval = first_eval.func(func_eval, rest[i], env);
//if(i != length - 1)
cleanObject(&toClean);
cleanObject(&rest[i]);
}
}
return func_eval;
} else if (first_eval.type == TYPE_LAMBDA) {
struct Environment newEnv =
envForLambda(&first_eval.lambda->params, first_form->forward, env);
Object ret = eval(&first_eval.lambda->body, &newEnv);
deleteEnv(&newEnv);
cleanObject(&first_eval);
return ret;
} else {
Object list = listObject();
FOR_POINTER_IN_LIST(obj) {
nf_addToList(&list, eval(POINTER, env));
}
return list;
}
}
case TYPE_LAMBDA: case TYPE_LAMBDA:
return errorObject(UNEXPECTED_FORM); return errorObject(UNEXPECTED_FORM);
default:
return *obj;
} }
}
Result result(Object obj, struct Slice *slices) return errorObject(BAD_TYPE);
{
return (Result) {
.obj = obj,
.slices = slices
};
} }
Object catObjects(const Object obj1, const Object obj2, struct Environment *env) Object catObjects(const Object obj1, const Object obj2, struct Environment *env)
@ -202,6 +211,15 @@ Object catObjects(const Object obj1, const Object obj2, struct Environment *env)
return o; return o;
} }
Object listEquality(const Object *list1, const Object *list2)
{
FOR_POINTERS_IN_LISTS(list1, list2) {
if(P1->type != P2->type || P1->number != P2->number)
return boolObject(0);
}
return boolObject(1);
}
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) struct Environment *env)
{ {
@ -225,7 +243,9 @@ Object _basicOp(const Object *obj1, const Object *obj2, const char op,
case '=': case '=':
if(obj1->type == TYPE_STRING || obj2->type == TYPE_STRING) if(obj1->type == TYPE_STRING || obj2->type == TYPE_STRING)
return boolObject(!strcmp(obj1->string, obj2->string)); return boolObject(!strcmp(obj1->string, obj2->string));
return boolObject(n1 == n2); if(obj1->type == TYPE_LIST && obj2->type == TYPE_LIST)
return listEquality(obj1, obj2);
return boolObject(n1 == n2 && obj1->type == obj2->type);
case '>': case '>':
return boolObject(n1 > n2); return boolObject(n1 > n2);
case '<': case '<':
@ -376,10 +396,10 @@ Result parse(struct Slice *slices)
// todo check for null rest // todo check for null rest
return readSeq(rest); return readSeq(rest);
} else { // todo error on missing close paren } else { // todo error on missing close paren
return result(parseAtom(token), rest); return (Result){parseAtom(token), rest};
} }
} else { } else {
return result(errorObject(NULL_PARSE), NULL); return (Result){errorObject(NULL_PARSE), NULL};
} }
} }
@ -390,7 +410,7 @@ Result readSeq(struct Slice *tokens)
struct Slice *next = tokens; struct Slice *next = tokens;
struct Slice *rest = next->text? &next[1] : NULL; struct Slice *rest = next->text? &next[1] : NULL;
if(next->text[0] == ')') { if(next->text[0] == ')') {
return result(res, rest); return (Result){res, rest};
} }
Result r = parse(tokens); Result r = parse(tokens);
if(r.obj.type == TYPE_ERROR) if(r.obj.type == TYPE_ERROR)
@ -406,7 +426,7 @@ Object parseDecimal(struct Slice *s)
int num = 0; int num = 0;
for(int i = 0; i < s->length; i++) { for(int i = 0; i < s->length; i++) {
if(!isDigit(s->text[i])) { if(!isDigit(s->text[i])) {
return errorObject(SYMBOLS_CANT_START_WITH_DIGITS); return errorObject(BAD_NUMBER);
} }
num *= 10; num *= 10;
num += s->text[i] - '0'; num += s->text[i] - '0';
@ -414,22 +434,56 @@ Object parseDecimal(struct Slice *s)
return numberObject(num); return numberObject(num);
} }
Object parseHex(struct Slice *s)
{
int num = 0;
for(int i = 2; i < s->length; i++) {
const char c = s->text[i];
if(!isHex(c)) {
return errorObject(BAD_NUMBER);
}
num *= 16;
if(isDigit(c)) {
num += c - '0';
} else /* is hex */ {
num += c - 'a' + 10;
}
}
return numberObject(num);
}
Object parseBin(struct Slice *s)
{
int num = 0;
for(int i = 2; i < s->length; i++) {
const char c = s->text[i];
if(c != '0' && c != '1') {
return errorObject(BAD_NUMBER);
}
num *= 2;
num += c - '0';
}
return numberObject(num);
}
Object parseAtom(struct Slice *s) Object parseAtom(struct Slice *s)
{ {
if(isDigit(s->text[0])) { const char c = s->text[0];
if(s->text[0] != '0' || s->length == 1) if(isDigit(c)) {
if(c != '0' || s->length == 1) {
return parseDecimal(s); return parseDecimal(s);
else { } else if(c == '0' && s->text[1] == 'x') {
return parseHex(s);
} else if(c == '0' && s->text[1] == 'b') {
return parseBin(s);
} else {
return errorObject(UNSUPPORTED_NUMBER_TYPE); return errorObject(UNSUPPORTED_NUMBER_TYPE);
} }
} else if (s->length == 1 && (c == 'T' || c == 't')) {
} else if (s->length == 1 && (s->text[0] == 'T' || s->text[0] == 't')) {
return boolObject(1); return boolObject(1);
} else if (s->length == 1 && (c == 'F' || c == 'f')) {
} else if (s->length == 1 && (s->text[0] == 'F' || s->text[0] == 'f')) {
return boolObject(0); return boolObject(0);
} else if (c == '"' || c == '\'') {
} else if (s->text[0] == '"' || s->text[0] == '\'') {
return objFromSlice(s->text, s->length); return objFromSlice(s->text, s->length);
} else { } else {
return symFromSlice(s->text, s->length); return symFromSlice(s->text, s->length);
@ -449,7 +503,7 @@ Object parseEval(const char *input, struct Environment *env)
printd("start slice\n"); printd("start slice\n");
if(debug) { if(debug) {
while(debug->text) { while(debug->text) {
char tok[MAX_TOK_LEN]; char tok[100];
copySlice(tok, debug); copySlice(tok, debug);
printd("slice: '%s'\n", tok); printd("slice: '%s'\n", tok);
debug++; debug++;
@ -461,32 +515,27 @@ Object parseEval(const char *input, struct Environment *env)
int parens = 0; int parens = 0;
Object obj = numberObject(0); Object obj = numberObject(0);
struct Slice *tok = tokens; struct Slice *tok = tokens;
if(tok[i].text[0] != '(') { while(tok[i].text != NULL) {
Object parsed = parse(tok).obj; if(tok[i].text[0] == '(') {
if(parsed.type == TYPE_ERROR) parens++;
return parsed; } else if(tok[i].text[0] == ')') {
obj = eval(&parsed, env); parens--;
cleanObject(&parsed);
} else {
while(tok[i].text != NULL) {
if(tok[i].text[0] == '(') {
parens++;
} else if(tok[i].text[0] == ')') {
parens--;
if(parens == 0) {
cleanObject(&obj);
Object parsed = parse(tok).obj;
if(parsed.type == TYPE_ERROR)
return parsed;
tok = &tok[i + 1];
i = -1;
//printObj(&parsed);
obj = eval(&parsed, env);
cleanObject(&parsed);
}
}
i++;
} }
if(parens == 0) {
cleanObject(&obj);
Object parsed = parse(tok).obj;
if(parsed.type == TYPE_ERROR)
return parsed;
if(tok[i].text[0] == ')') {
tok = &tok[i + 1];
i = -1;
}
obj = eval(&parsed, env);
cleanObject(&parsed);
}
i++;
} }
free(tokens); free(tokens);
return obj; return obj;

View File

@ -29,14 +29,12 @@ Object eval(const Object *obj, struct Environment *env);
Result parse(struct Slice *slices); Result parse(struct Slice *slices);
Result readSeq(struct Slice *slices); Result readSeq(struct Slice *slices);
Object parseAtom(struct Slice *slice); Object parseAtom(struct Slice *slice);
void copySlice(char * dest, struct Slice *src);
Object parseEval(const char *input, struct Environment *env); Object parseEval(const char *input, struct Environment *env);
void eval_forms(Object *destList, const Object *src, struct Environment *env); void evalForms(Object *destList, const Object *src, struct Environment *env);
void copySlice(char * dest, struct Slice *src);
Object evalLambdaArgs(const Object *arg_forms); Object evalLambdaArgs(const Object *arg_forms);
Result result(Object obj, struct Slice *slices);
// Slices // Slices
void copySlice(char * dest, struct Slice *src); void copySlice(char * dest, struct Slice *src);
void debugSlice(struct Slice *s); void debugSlice(struct Slice *s);
@ -48,6 +46,7 @@ BASIC_OP(mul); BASIC_OP(dvi);
BASIC_OP(mod); BASIC_OP(equ); 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); Object filter(Object obj1, Object obj2, struct Environment *env);
Object append(Object list, Object newElement, struct Environment *env); Object append(Object list, Object newElement, struct Environment *env);

View File

@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
VALCOM="valgrind -q --leak-check=full --track-origins=yes"
TOTAL_PASSES=0 TOTAL_PASSES=0
TOTAL_FAILS=0 TOTAL_FAILS=0
PASSES=0 PASSES=0
@ -24,11 +26,9 @@ endBlock() {
title() { title() {
echo "$1" echo "$1"
# echo "$1" | sed 's/./-/g' | sed 's/$/-/g'
} }
pass() { pass() {
# echo "$1 test PASSED"
((PASSES++)) ((PASSES++))
((TOTAL_PASSES++)) ((TOTAL_PASSES++))
} }
@ -42,7 +42,7 @@ fail() {
check() { check() {
local output local output
if (($VALGRIND == 1)); then if (($VALGRIND == 1)); then
local output=$(valgrind -q --leak-check=full --track-origins=yes ./pebblisp "$2") local output=$($VALCOM ./pebblisp "$2")
else else
local output=$(./pebblisp "$2") local output=$(./pebblisp "$2")
fi fi
@ -62,6 +62,8 @@ title "Plain return tests"
check "PlainRet" "10" "10" check "PlainRet" "10" "10"
check "StrRetrn" "\"hey\"" "hey" check "StrRetrn" "\"hey\"" "hey"
check "SingleStrRetrn" "'hey'" "hey" check "SingleStrRetrn" "'hey'" "hey"
check "HexReturn" "0x0f0f0" "61680"
check "BinaryReturn" "0b011010011010011" "13523"
endBlock endBlock
title "Arithmetic" title "Arithmetic"
@ -99,7 +101,7 @@ check "EmptLst2" "( )" "( )"
check "ListIndex" "(at (+ 1 1) (1 2 1000 4 5))" "1000" check "ListIndex" "(at (+ 1 1) (1 2 1000 4 5))" "1000"
check "EvalElems" "((* 10 10) 7)" "( 100 7 )" check "EvalElems" "((* 10 10) 7)" "( 100 7 )"
check "AppendToList" "(ap (1 20 300 4000 50000) 600000)" "( 1 20 300 4000 50000 600000 )" check "AppendToList" "(ap (1 20 300 4000 50000) 600000)" "( 1 20 300 4000 50000 600000 )"
check "AppndToEnvList" "(def l (50000 4000 300 20)) (def l (ap l 1)) (l)" "( 50000 4000 300 20 1 )" check "AppndToEnvList" "(def l (50000 4000 300 20)) (def l (ap l 1)) l" "( 50000 4000 300 20 1 )"
check "Rest(Tail)OfList" "(def l (50000 4000 300 20)) (rest l)" "( 4000 300 20 )" check "Rest(Tail)OfList" "(def l (50000 4000 300 20)) (rest l)" "( 4000 300 20 )"
check "ListLength" "(def l (1 20 3 'abc' 'banana' (+ 10 5))) (len l)" "6" check "ListLength" "(def l (1 20 3 'abc' 'banana' (+ 10 5))) (len l)" "6"
endBlock endBlock
@ -158,7 +160,9 @@ title "ShouldError"
check "LenOfNotList" "(len 5)" "NOT_A_LIST" check "LenOfNotList" "(len 5)" "NOT_A_LIST"
check "NoMapList" "(map sq)" "( )" check "NoMapList" "(map sq)" "( )"
check "UnevenLists" "(+ (1 2) (1 2 3))" "LISTS_NOT_SAME_SIZE" check "UnevenLists" "(+ (1 2) (1 2 3))" "LISTS_NOT_SAME_SIZE"
check "BadSymbol" "(5df)" "SYMBOLS_START_WITH_LETTERS" check "BadNumber" "(5df)" "BAD_NUMBER"
check "BadHex" "(0x0zf)" "BAD_NUMBER"
check "BadBinary" "(0b01120)" "BAD_NUMBER"
check "BadParens" "(hey()" "MISMATCHED_PARENS" check "BadParens" "(hey()" "MISMATCHED_PARENS"
check "BadParens2" "(hey)(" "MISMATCHED_PARENS" check "BadParens2" "(hey)(" "MISMATCHED_PARENS"
check "BadParens3" "((hey(" "MISMATCHED_PARENS" check "BadParens3" "((hey(" "MISMATCHED_PARENS"
@ -175,10 +179,13 @@ endBlock
echo "" echo ""
if [ "$TOTAL_FAILS" -ne "0" ]; then if [ "$TOTAL_FAILS" -ne "0" ]; then
echo "$TOTAL_FAILS Tests Failed" echo -n ""
else
echo "$TOTAL_FAILS Tests Failed"
fi fi
echo "$TOTAL_FAILS Tests Failed"
if [ "$TOTAL_PASSES" -ne "0" ]; then
echo -n ""
fi
echo "$TOTAL_PASSES Tests Passed"
echo "$TOTAL_PASSES Tests Passed"
echo "" echo ""

View File

@ -35,6 +35,10 @@ int isDigit(const char c) {
return c >= '0' && c <= '9'; return c >= '0' && c <= '9';
} }
int isHex(const char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
}
int isWhitespace(const char c) { int isWhitespace(const char c) {
return c == ' ' || c == '\t' || c == '\n'; return c == ' ' || c == '\t' || c == '\n';
} }

View File

@ -5,6 +5,7 @@
int isSingle(const char c); int isSingle(const char c);
int isDigit(const char c); int isDigit(const char c);
int isHex(const char c);
struct Slice *nf_tokenize(const char *input); struct Slice *nf_tokenize(const char *input);
#endif #endif