Add simple varargs.

This commit is contained in:
Sage Vaillancourt 2022-04-25 13:35:39 -04:00 committed by Sage Vaillancourt
parent 61a402604b
commit ce3472cb90
8 changed files with 72 additions and 41 deletions

View File

@ -132,9 +132,21 @@ struct Environment envForLambda(const Object* params, const Object* arguments, i
const Object* param = params->list; const Object* param = params->list;
const Object* argument = arguments; const Object* argument = arguments;
for (int i = 0; i < paramCount && param; i++) { for (int i = 0; i < paramCount && param; i++) {
const char* paramName = param->string;
if (paramName[0] == '.' && paramName[1] == '.' && paramName[2] == '.' && paramName[3] != '\0') {
paramName = &paramName[3];
Object BuildListNamed(varargs);
while (argument) {
addToList(varargs, eval(argument, outer));
argument = argument->forward;
}
addToEnv(&env, paramName, varargs);
cleanObject(&varargs);
break;
}
Object newEnvObj = eval(argument, outer); Object newEnvObj = eval(argument, outer);
const char* paramName = param->string;
addToEnv(&env, paramName, newEnvObj); addToEnv(&env, paramName, newEnvObj);
cleanObject(&newEnvObj); cleanObject(&newEnvObj);

View File

@ -1,4 +1,5 @@
#!/usr/bin/pl #!/usr/bin/pl
(def string (fn (a) (cat "" a))) (def string (fn (a) (cat "" a)))
(def switch (fn (val dict) ( (def switch (fn (val dict) (
@ -27,9 +28,19 @@
(def nl (ch 10)) (def nl (ch 10))
(def prnl (fn (_txt) (def prnlambda (fn (text) (prn text)))
"Print with an appended newline." (
(prn (cat _txt nl)) (def prnl (fn (...text)
"Print the given elements with an appended newline." (
(for-each prnlambda text)
(prn nl)
)))
(def join (fn (separator text)
"With the given separator, join the given elements as a string. (join \"_\" (1 2 3)) => 1_2_3" (
(def initial (first text))
(def concat (fn (left right) (cat left separator right)))
(reduce (rest text) concat initial)
))) )))
(def _indexOf (fn (txt search) ( (def _indexOf (fn (txt search) (
@ -80,18 +91,22 @@
(+ (fib (- a 1)) (fib (- a 2))) (+ (fib (- a 1)) (fib (- a 2)))
))) )))
(def max (fn (a b) (def _max (fn (a b) (if (> a b) a b)))
"Return the larger of the given values"
(if (> a b) a b) (def max (fn (...values)
"Return the largest of the given values"
(reduce values _max (first values))
)) ))
(def min (fn (a b) (def _min (fn (a b) (if (< a b) a b)))
"Return the smaller of the given values"
(if (< a b) a b) (def min (fn (...values)
"Return the smallest of the given values"
(reduce values _min (first values))
)) ))
(def for-each (fn (action list) (def for-each (fn (action list)
"Apply the given action to each element in list." ( "Apply the given action to each element in list, and return an empty string." (
(map action list) (map action list)
"" ""
))) )))
@ -150,13 +165,3 @@
(def endsWith (fn (text pattern) ( (def endsWith (fn (text pattern) (
(matches text (cat "*" pattern)) (matches text (cat "*" pattern))
))) )))
; Switch expression
; Doesn't yet work with lambdas
;(def switch (fn (val pair_list)
; (if (= 0 (len pair_list)) "no match"
; (if (= val (at 0 (at 0 pair_list))) (at 1 (at 0 pair_list)) (
; (switch val (rest pair_list))
; ))
; )
;))

View File

@ -244,7 +244,7 @@ int main(int argc, const char* argv[])
readFile(SCRIPTDIR "/lib.pbl", &env); readFile(SCRIPTDIR "/lib.pbl", &env);
} }
Object o = parseEval("(def prompt %%)", &env, nullTerminated("pebblisp::> ")); Object o = parseEval("(def prompt %%)", &env);
cleanObject(&o); cleanObject(&o);
o = parseEval("(def preprocess (fn (text) (text)))", &env); o = parseEval("(def preprocess (fn (text) (text)))", &env);
cleanObject(&o); cleanObject(&o);

View File

@ -227,7 +227,7 @@ void stringStruct(struct string* s, const Object* obj)
*/ */
int stringNObj(struct string* s, const Object* obj) int stringNObj(struct string* s, const Object* obj)
{ {
inflate(s, 16); // In most cases this is enough to fit the appended string. inflate(s, 32); // In most cases this is enough to fit the appended string.
switch (obj->type) { switch (obj->type) {
case TYPE_NUMBER: case TYPE_NUMBER:
appendf(s, "%ld", obj->number); appendf(s, "%ld", obj->number);

View File

@ -10,16 +10,14 @@
#endif #endif
Object singleDef(Object* string, Object* value, struct Environment* env) Object singleDef(const char* name, Object* value, struct Environment* env)
{ {
const char* name = string->string;
Object finalValue = eval(value, env); Object finalValue = eval(value, env);
addToEnv(env, name, finalValue); addToEnv(env, name, finalValue);
cleanObject(&finalValue); cleanObject(&finalValue);
return cloneObject(*string); return nullTerminated(name);
} }
Object listDef(Object* nameList, Object* valueList, struct Environment* env) Object listDef(Object* nameList, Object* valueList, struct Environment* env)
@ -29,7 +27,17 @@ Object listDef(Object* nameList, Object* valueList, struct Environment* env)
if (!value) { if (!value) {
break; break;
} }
singleDef(POINTER, value, env); const char* name = POINTER->string;
if (name[0] == '.' && name[1] == '.' && name[2] == '.' && name[3] != '\0') {
Object BuildListNamed(varargs);
while (value) {
addToList(varargs, *value);
value = value->forward;
}
addToEnv(env, &name[3], varargs);
break;
}
addToEnv(env, name, eval(value, env));
value = value->forward; value = value->forward;
} }
return cloneObject(*nameList); return cloneObject(*nameList);
@ -40,7 +48,7 @@ Object listDef(Object* nameList, Object* valueList, struct Environment* env)
* *
* If `argForms` (symbol) and `argForms->forward` (value) are lists of the same * If `argForms` (symbol) and `argForms->forward` (value) are lists of the same
* length, define each symbol element with the corresponding value element. * length, define each symbol element with the corresponding value element.
* I.e. `(def (a b) (5 20))` would store `a` as `5` and `b` as `20`. * I.e. `(def '(a b) (5 20))` would store `a` as `5` and `b` as `20`.
* *
* @param argForms The symbol(s) and value(s) to define in the environment * @param argForms The symbol(s) and value(s) to define in the environment
* @param env The environment to add the new definition to * @param env The environment to add the new definition to
@ -49,7 +57,7 @@ Object listDef(Object* nameList, Object* valueList, struct Environment* env)
Object def(Object* params, unused int length, struct Environment* env) Object def(Object* params, unused int length, struct Environment* env)
{ {
if (isStringy(params[0])) { if (isStringy(params[0])) {
return singleDef(&params[0], &params[1], env); return singleDef(params[0].string, &params[1], env);
} }
if (length == 2 && isListy(params[0]) && isListy(params[1])) { if (length == 2 && isListy(params[0]) && isListy(params[1])) {
@ -125,8 +133,8 @@ Object mapO(Object* params, int length, struct Environment* env)
Object lambda = eval(&params[0], env); Object lambda = eval(&params[0], env);
const Object* inputList = &params[1]; const Object* inputList = &params[1];
if (!isFuncy(lambda)) { if (lambda.type != TYPE_LAMBDA) {
throw(BAD_TYPE, "First argument of (map) should be func-like."); throw(BAD_TYPE, "First argument of (map) must be a lambda!"); // TODO: why no function?
} }
Object BuildListNamed(outputList); Object BuildListNamed(outputList);
@ -567,7 +575,9 @@ Object parseEval(const char* input, struct Environment* env)
free(err.context); free(err.context);
return o; return o;
} }
if (!tokens->text) { if (!tokens->text) {
free(tokens);
return symFromSlice(" ", 1); return symFromSlice(" ", 1);
} }

View File

@ -23,11 +23,11 @@ typedef struct Result {
Object eval(const Object* obj, struct Environment* env); Object eval(const Object* obj, struct Environment* env);
Result readSeq(struct Slice* slices, va_list* injections); Result readSeq(struct Slice* slices);
Result parseAtom(struct Slice* slice); Result parseAtom(struct Slice* slice);
Object parseEval(const char* input, struct Environment* env, ...); Object parseEval(const char* input, struct Environment* env);
Object evalList(const Object* obj, struct Environment* env); Object evalList(const Object* obj, struct Environment* env);

View File

@ -11,17 +11,21 @@
*/ */
// Is the char a standalone token? // Is the char a standalone token?
static const char singleTokens[] = "()'?."; static const char singleTokens[] = "()'?";
int isSingle(const char c) int isSingle(const char *c)
{ {
int i = 0; int i = 0;
while (singleTokens[i] != '\0') { while (singleTokens[i] != '\0') {
if (singleTokens[i] == c) { if (singleTokens[i] == c[0]) {
return 1; return 1;
} }
i++; i++;
} }
// It's not a single if it's next to another '.'
if (c[0] == '.' && c[1] != '.' && c[-1] != '.') {
return 1;
}
return 0; return 0;
} }
@ -91,7 +95,7 @@ struct Slice* nf_tokenize(const char* input, struct Error* err)
slices[slice].text = &input[i]; slices[slice].text = &input[i];
slices[slice].lineNumber = lineNumber; slices[slice].lineNumber = lineNumber;
if (isSingle(input[i])) { if (isSingle(&input[i])) {
i++; i++;
} else if (input[i] == ';') { } else if (input[i] == ';') {
while (input[i] && input[i] != '\n') { while (input[i] && input[i] != '\n') {
@ -145,7 +149,7 @@ void processString(const char* input, struct Error* err, struct Slice* slices, i
void collectSymbol(const char* input, int* i, int* length) void collectSymbol(const char* input, int* i, int* length)
{ {
while (!isWhitespace(input[++(*i)]) && !isSingle(input[(*i)]) && input[(*i)] != '"' && input[(*i)] != '\0') { while (!isWhitespace(input[++(*i)]) && !isSingle(&input[(*i)]) && input[(*i)] != '"' && input[(*i)] != '\0') {
(*length)++; (*length)++;
} }
} }

View File

@ -3,7 +3,7 @@
#include "pebblisp.h" #include "pebblisp.h"
int isSingle(char c); int isSingle(const char *c);
int isDigit(char c); int isDigit(char c);