diff --git a/src/Makefile b/src/Makefile index 71655b2..1fd09ee 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,15 +12,15 @@ mkfile_dir := $(dir $(mkfile_path)) GCC_ARGS ?= -g -Wall -o $(exe) -D WEBSERVER -D STANDALONE -DSCRIPTDIR=\"$(SCRIPTDIR)\" GCC_COM ?= gcc -O0 $(GCC_ARGS) -all: - $(GCC_COM) $(file_libs) && echo && ./tests.sh - release: gcc -O3 $(GCC_ARGS) $(file_libs) && strip ./$(exe) && echo && ./tests.sh notest: $(GCC_COM) $(file_libs) +all: notest + echo && ./tests.sh + local: gcc -g -O0 -Wall -o $(exe) -D STANDALONE -DSCRIPTDIR=\"$(mkfile_dir)/examples\" $(file_libs) diff --git a/src/env.c b/src/env.c index 122581b..8775b03 100644 --- a/src/env.c +++ b/src/env.c @@ -412,6 +412,7 @@ struct Environment defaultEnv() pf(append), pf(prepend), pf(reduce), + pf(mapO), pf(at), pf(rest), pf(charAt), diff --git a/src/examples/pebblisp.pbl b/src/examples/pebblisp.pbl index c0cf16f..d3082da 100644 --- a/src/examples/pebblisp.pbl +++ b/src/examples/pebblisp.pbl @@ -15,7 +15,7 @@ (def reload (fn () (loadfile (cat (env "HOME") "/.pebblisp.pbl")))) (def hour (fn (ti) ( - (def h (% ti's hour 12)) + (def h (% ti.hour 12)) (if (= 0 h) 12 h) ))) @@ -23,7 +23,7 @@ (def zero (fn (num) (cat (if (< num 10) "0" "") num))) -(def clock (fn (ti) (cat (hour ti) ":" (zero ti's minute) ":" (zero ti's sec)))) +(def clock (fn (ti) (cat (hour ti) ":" (zero ti.minute) ":" (zero ti.sec)))) (def prompt (fn (a) ( (def ti (time)) diff --git a/src/object.c b/src/object.c index 8ed9a67..10f7997 100644 --- a/src/object.c +++ b/src/object.c @@ -701,7 +701,7 @@ inline Object symFromSlice(const char* string, int len) /// Creates a stringy object with room for a reference-count prefix and trailing null byte. /// Thus, withLen(3, TYPE_STRING) will actually allocate a 5-byte "string". -inline Object withLen(int len, enum Type type) +inline Object withLen(size_t len, enum Type type) { Object o = newObject(type); o.string = malloc(sizeof(char) * (len + 2)); diff --git a/src/object.h b/src/object.h index 7ed44f9..55aa05c 100644 --- a/src/object.h +++ b/src/object.h @@ -206,7 +206,7 @@ Object stringFromSlice(const char* string, int len); Object symFromSlice(const char* string, int len); -Object withLen(int len, enum Type type); +Object withLen(size_t len, enum Type type); Object boolObject(int b); diff --git a/src/pebbleobject.c b/src/pebbleobject.c index e2530a7..df79d6d 100644 --- a/src/pebbleobject.c +++ b/src/pebbleobject.c @@ -57,18 +57,18 @@ Object deleteWindow(Object window, Object o2, struct Environment* env) /* Maintain a list of layers to delete? */ if (getPebbleType(window) == WINDOW) { window_stack_remove(accessPebbleObject(window)->window, true); - return boolObject(1); + return trueObject(); } - return boolObject(0); + return falseObject(); } Object pushWindow(Object window, Object o2, struct Environment* env) { if (getPebbleType(window) == WINDOW) { window_stack_push(accessPebbleObject(window)->window, true); - return boolObject(1); + return trueObject(); } - return boolObject(0); + return falseObject(); } Object updateTextLayer(Object textLayer, Object text, struct Environment* env) @@ -77,9 +77,9 @@ Object updateTextLayer(Object textLayer, Object text, struct Environment* env) struct PebbleObject* po = accessPebbleObject(textLayer); stringObj(po->textLayer->text, &text); text_layer_set_text(po->textLayer->layer, po->textLayer->text); - return boolObject(1); + return trueObject(); } - return boolObject(0); + return falseObject(); } Object addTextLayer(Object window, Object text, struct Environment* env) @@ -130,7 +130,7 @@ Object subscribe(Object function, Object time, struct Environment* env) 6 ? YEAR_UNIT : MINUTE_UNIT; tick_timer_service_subscribe(unit, subscriptionHandler); - return boolObject(1); + return trueObject(); } - return boolObject(0); + return falseObject(); } diff --git a/src/pebblisp.c b/src/pebblisp.c index bf3d3b7..5f9741d 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -49,6 +49,8 @@ Object def(Object* params, int length, struct Environment* env) /** * Add a struct to the environment with a given name and fields. * + * Not a typical pl function because I don't feel like adding more syntactic sugar right now. + * * (struct point (x y)) */ Object evalStructArgs(const Object* symbol, const Object* fields, struct Environment* env) @@ -66,20 +68,21 @@ Object evalStructArgs(const Object* symbol, const Object* fields, struct Environ def.fieldCount = listLength(fields); def.names = malloc(sizeof(char*) * def.fieldCount); - { - int i = 0; - FOR_POINTER_IN_LIST(fields) { - def.names[i] = malloc(sizeof(char) * (strlen(POINTER->string) + 1)); - strcpy(def.names[i], POINTER->string); - i++; - } + int i = 0; + FOR_POINTER_IN_LIST(fields) { + def.names[i] = malloc(sizeof(char) * (strlen(POINTER->string) + 1)); + strcpy(def.names[i], POINTER->string); + i++; } addStructDef(def); - return boolObject(1); + return trueObject(); } +/** + * Not a typical pl function because delayed evaluation is annoying in those right now. + */ Object evalIfArgs(const Object* argForms, struct Environment* env) { Object condition = eval(argForms, env); @@ -89,19 +92,22 @@ Object evalIfArgs(const Object* argForms, struct Environment* env) return result; } +/** + * Not a typical pl function because it relies almost exclusively on symbols + */ Object evalLambdaArgs(const Object* argForms, struct Environment* env) { return constructLambda(argForms, argForms ? argForms->forward : NULL, env); } -Object evalMapArgs(const Object* argForms, struct Environment* env) +Object mapO(Object* params, int length, struct Environment* env) { - if (!argForms) { + if (length < 2) { return errorObject(NULL_MAP_ARGS); } - Object lambda = eval(argForms, env); - const Object* inputList = argForms->forward; + Object lambda = eval(¶ms[0], env); + const Object* inputList = ¶ms[1]; if (lambda.type != TYPE_LAMBDA) { return errorObject(BAD_TYPE); @@ -114,8 +120,8 @@ Object evalMapArgs(const Object* argForms, struct Environment* env) // since lambda evaluation looks for a list Object tempInput = cloneObject(*POINTER); - Object* params = &lambda.lambda->params; - struct Environment newEnv = envForLambda(params, &tempInput, listLength(params), env); + Object* lambdaParams = &lambda.lambda->params; + struct Environment newEnv = envForLambda(lambdaParams, &tempInput, listLength(lambdaParams), env); // Add the lambda evaluation to the list Object lambda_output = eval(&lambda.lambda->body, &newEnv); @@ -137,8 +143,6 @@ Object evalBuiltIns(const Object* first, const Object* rest, return evalIfArgs(rest, env); } else if (strcmp(first->string, "fn") == 0) { return evalLambdaArgs(rest, env); - } else if (strcmp(first->string, "map") == 0) { - return evalMapArgs(rest, env); } else if (strcmp(first->string, "struct") == 0) { return evalStructArgs(rest, rest->forward, env); } @@ -358,7 +362,7 @@ Result parse(struct Slice* slices) return r; } } else { - return (Result) {errorObject(NULL_PARSE), NULL}; + return (Result) { errorObject(NULL_PARSE), NULL }; } } @@ -376,7 +380,7 @@ Result readSeq(struct Slice* tokens) struct Slice* next = tokens; struct Slice* rest = next->text ? &next[1] : NULL; if (next->text[0] == ')') { - return (Result) {res, rest}; + return (Result) { res, rest }; } Result r = parse(tokens); sugar("(? fil) => (? 'fil')" // or, @@ -446,36 +450,34 @@ Result parseAtom(struct Slice* s) const char c = s->text[0]; if (isDigit(c)) { if (c != '0' || s->length == 1) { - return (Result) {parseDecimal(s), s}; + return (Result) { parseDecimal(s), s }; #ifndef LOW_MEM } else if (s->text[1] == 'x') { - return (Result) {parseHex(s), s}; + return (Result) { parseHex(s), s }; } else if (s->text[1] == 'b') { - return (Result) {parseBin(s), s}; + return (Result) { parseBin(s), s }; #endif } else { - return (Result) {errorObject(UNSUPPORTED_NUMBER_TYPE), s}; + return (Result) { errorWithContext(UNSUPPORTED_NUMBER_TYPE, s->text), s }; } - } else if (s->length == 1 && (c == 'T' || c == 't')) { - return (Result) {boolObject(1), s}; - } else if (s->length == 1 && (c == 'F' || c == 'f')) { - return (Result) {boolObject(0), s}; + } else if (s->length == 1 && c == 'T') { + return (Result) { trueObject(), s }; + } else if (s->length == 1 && c == 'F') { + return (Result) { falseObject(), s }; } else if (c == '"'/* || c == '\''*/) { - return (Result) {objFromSlice(s->text, s->length), s}; - } else { - if (s->text[s->length] == '\'' && s->text[s->length + 1] == 's') { - Object possessiveFunc = newObject(TYPE_FUNC); - possessiveFunc.func = &possessive; - Object list = startList(possessiveFunc); - Object possesser = symFromSlice(s->text, s->length); - nf_addToList(&list, possesser); - struct Slice* next = s + 3; - Object possessed = objFromSlice(&next->text[-1], next->length + 1); - nf_addToList(&list, possessed); - return (Result) {list, next}; - } - return (Result) {symFromSlice(s->text, s->length), s}; + return (Result) { objFromSlice(s->text, s->length), s }; + } else if (s->text[s->length] == '.') { + Object possessiveFunc = newObject(TYPE_FUNC); + possessiveFunc.func = &possessive; + Object list = startList(possessiveFunc); + Object possesser = symFromSlice(s->text, s->length); + nf_addToList(&list, possesser); + struct Slice* next = s + 2; + Object possessed = objFromSlice(&next->text[-1], next->length + 1); + nf_addToList(&list, possessed); + return (Result) { list, next }; } + return (Result) { symFromSlice(s->text, s->length), s }; } struct Slice* lastOpen = NULL; diff --git a/src/pebblisp.h b/src/pebblisp.h index 29eb53f..c4c76d6 100644 --- a/src/pebblisp.h +++ b/src/pebblisp.h @@ -28,6 +28,10 @@ fnn(_name, _docs, __VA_ARGS__) static const char * const _name ## Symbol = _symbol; \ fnn(_name, _docs, __VA_ARGS__) +#define trueObject() boolObject(1) + +#define falseObject() boolObject(0) + struct Slice { const char* text; unsigned char length; @@ -68,6 +72,11 @@ int readFile(const char* filename, struct Environment* env); #endif /* STANDALONE */ +fn(mapO, "map", + "Map over a list with a function.", + "(map (fn (a) (* a a)) (1 2 3))", "( 1 4 9 )", +); + fn(def, "def", "Define a variable in the current scope.", "(def x 10) x", "10", diff --git a/src/pebcom.c b/src/pebcom.c index 66a7025..9fe9547 100644 --- a/src/pebcom.c +++ b/src/pebcom.c @@ -44,7 +44,7 @@ Object doVibe(Object patternList, Object o2, struct Environment* env) } vibes_enqueue_custom_pattern( (VibePattern) {.durations = pattern, .num_segments = length}); - return boolObject(1); + return trueObject(); } else { return errorObject(NOT_A_LIST); } diff --git a/src/plfunc.c b/src/plfunc.c index fe32b18..5b43d9a 100644 --- a/src/plfunc.c +++ b/src/plfunc.c @@ -169,7 +169,7 @@ Object isNum(Object* params, int length, struct Environment* env) checkTypes(isNum) Object test = params[0]; - return test.type == TYPE_NUMBER ? boolObject(1) : boolObject(0); + return boolObject(test.type == TYPE_NUMBER); } Object isList(Object* params, int length, struct Environment* env) @@ -177,7 +177,7 @@ Object isList(Object* params, int length, struct Environment* env) checkTypes(isList) Object test = params[0]; - return test.type == TYPE_LIST ? boolObject(1) : boolObject(0); + return boolObject(test.type == TYPE_LIST); } Object isString(Object* params, int length, struct Environment* env) @@ -185,7 +185,7 @@ Object isString(Object* params, int length, struct Environment* env) checkTypes(isString) Object test = params[0]; - return test.type == TYPE_STRING ? boolObject(1) : boolObject(0); + return boolObject(test.type == TYPE_STRING); } Object charVal(Object* params, int length, struct Environment* env) @@ -201,7 +201,7 @@ Object isErr(Object* params, int length, struct Environment* env) checkTypes(isErr) Object test = params[0]; - return test.type == TYPE_ERROR ? boolObject(1) : boolObject(0); + return boolObject(test.type == TYPE_ERROR); } Object parseEvalO(Object* params, int length, struct Environment* env) diff --git a/src/plfunc.h b/src/plfunc.h index 3844826..6a344a5 100644 --- a/src/plfunc.h +++ b/src/plfunc.h @@ -194,7 +194,7 @@ fn(possessive, "poss", "Get the value of a struct's field", "(struct Post (title body))\n " "(def p (Post \"TI\" \"BO\"))\n " - "p's title", "TI" + "p.title", "TI" ); #ifdef STANDALONE diff --git a/src/tests.sh b/src/tests.sh index 2077e58..ed6c2d9 100755 --- a/src/tests.sh +++ b/src/tests.sh @@ -205,7 +205,7 @@ check "Building a struct"\ '(struct Post (title body)) (Post "A title" "The Body")'\ '{ title: "A title", body: "The Body" }' check "Accessing struct fields"\ - "(struct Post (title body)) (def p (Post \"TITLE\" \"BODY\")) (p's title p's body)"\ + "(struct Post (title body)) (def p (Post \"TITLE\" \"BODY\")) (p.title p.body)"\ "( TITLE BODY )" title "HigherOrder" @@ -217,7 +217,7 @@ check "FuncReturningAFunc" "(def plusser (fn (outer) (fn (inner) (+ outer inner) title "ShouldError" check "LenOfNotList" "(len 5)" regex "BAD_PARAMS_ON.*" -check "NoMapList" "(map sq)" "( )" +check "NoMapList" "(map sq)" "NULL_MAP_ARGS" check "BadNumber" "(5df)" regex "BAD_NUMBER.*" check "BadHex" "(0x0zf)" regex "BAD_NUMBER.*" check "BadBinary" "(0b01120)" regex "BAD_NUMBER.*" diff --git a/src/tokens.c b/src/tokens.c index 036b6c5..58abe4d 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -14,7 +14,7 @@ */ // Is the char a standalone token? -static const char singleTokens[] = "()+-*/='?"; +static const char singleTokens[] = "()+-*/='?."; int isSingle(const char c) {