Add simple varargs.
This commit is contained in:
parent
61a402604b
commit
ce3472cb90
14
src/env.c
14
src/env.c
|
@ -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 = ¶mName[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);
|
||||||
|
|
|
@ -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)
|
||||||
""
|
""
|
||||||
)))
|
)))
|
||||||
|
@ -149,14 +164,4 @@
|
||||||
|
|
||||||
(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))
|
|
||||||
; ))
|
|
||||||
; )
|
|
||||||
;))
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(¶ms[0], ¶ms[1], env);
|
return singleDef(params[0].string, ¶ms[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(¶ms[0], env);
|
Object lambda = eval(¶ms[0], env);
|
||||||
const Object* inputList = ¶ms[1];
|
const Object* inputList = ¶ms[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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
14
src/tokens.c
14
src/tokens.c
|
@ -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)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue