Added variable arguments to lambda functions. Last argument must be '&' to work.

This commit is contained in:
2014-05-27 20:50:39 +01:00
parent c1987617a0
commit a56e93808d
4 changed files with 27 additions and 12 deletions

View File

@@ -56,10 +56,7 @@ lval* builtin_pow(lenv* env, lval* val){
lval* builtin_op(lenv* env, lval* val, char* op) { lval* builtin_op(lenv* env, lval* val, char* op) {
//Ensure numbers only //Ensure numbers only
for(int i = 0; i < val->cell_count; i++) { for(int i = 0; i < val->cell_count; i++) {
if (val->cell_list[i]->type != LVAL_NUM) { LASSERT_TYPE(op, val, val->cell_list[i], LVAL_NUM);
lval_delete(val);
return lval_err(LERR_BAD_NUM);
}
} }
//Get the first element //Get the first element
@@ -78,10 +75,10 @@ lval* builtin_op(lenv* env, lval* val, char* op) {
if (strcmp(op, "*") == 0) { x->data.num *= y->data.num; } if (strcmp(op, "*") == 0) { x->data.num *= y->data.num; }
if (strcmp(op, "^") == 0) { x->data.num = pow(x->data.num,y->data.num); } if (strcmp(op, "^") == 0) { x->data.num = pow(x->data.num,y->data.num); }
if (strcmp(op, "/") == 0) { if (strcmp(op, "/") == 0) {
int zero = 0; short divZero = 0;
if (y->type == LVAL_NUM && fabs(y->data.num) <= DBL_EPSILON) {zero = 1;} if (y->type == LVAL_NUM && fabs(y->data.num) <= DBL_EPSILON) {divZero = 1;}
if (zero) { if (divZero) {
lval_delete(x); lval_delete(x);
lval_delete(y); lval_delete(y);
x = lval_err(LERR_DIV_ZERO); x = lval_err(LERR_DIV_ZERO);
@@ -202,9 +199,14 @@ lval* builtin_lambda(lenv* env, lval* val) {
LASSERT_TYPE("lambda", val, val->cell_list[1], LVAL_Q_EXPR); LASSERT_TYPE("lambda", val, val->cell_list[1], LVAL_Q_EXPR);
lval* symbols = val->cell_list[0]; lval* symbols = val->cell_list[0];
lval* va = NULL;
for(int i = 0; i < symbols->cell_count; i++) { for(int i = 0; i < symbols->cell_count; i++) {
LASSERT_TYPE("lambda args", val, symbols->cell_list[i], LVAL_SYM); LASSERT_TYPE("lambda args", val, symbols->cell_list[i], LVAL_SYM);
if (strcmp("&", symbols->cell_list[i]->data.sym) == 0 && i+1 == symbols->cell_count) {
va = lval_pop(symbols, i);
break;
}
} }
lval* formals = lval_pop(val, 0); lval* formals = lval_pop(val, 0);
@@ -212,6 +214,7 @@ lval* builtin_lambda(lenv* env, lval* val) {
body->type = LVAL_S_EXPR; body->type = LVAL_S_EXPR;
lval* lambda = lval_lambda(formals, body); lval* lambda = lval_lambda(formals, body);
lambda->data.func->va = va;
lval_delete(val); lval_delete(val);
return lambda; return lambda;
} }

13
lval.c
View File

@@ -113,10 +113,21 @@ lval* lval_call(lenv* env, lval* function, lval* args) {
LASSERT(args, func->formals->cell_count <= args->cell_count, LERR_SYNTAX, LASSERT(args, func->formals->cell_count <= args->cell_count, LERR_SYNTAX,
"lambda: insufficient arguments. Expected %ld got %ld", func->formals->cell_count, args->cell_count); "lambda: insufficient arguments. Expected %ld got %ld", func->formals->cell_count, args->cell_count);
for(int i = 0; i < args->cell_count; i++) { for(int i = 0; i < func->formals->cell_count; i++) {
lenv_put(func->env, func->formals->cell_list[i], args->cell_list[i]); lenv_put(func->env, func->formals->cell_list[i], args->cell_list[i]);
} }
if (func->va != NULL) {
lval* vaArgs = lval_q_expr();
for(int i = func->formals->cell_count; i < args->cell_count; i ++ ) {
lval_add(vaArgs, lval_copy(args->cell_list[i]));
}
lenv_put(func->env, func->va, vaArgs);
lval_delete(vaArgs);
}
lval_delete(args); lval_delete(args);
func->env->parent = env; func->env->parent = env;

1
lval.h
View File

@@ -34,6 +34,7 @@ struct lval_func {
lenv* env; lenv* env;
lval* formals; lval* formals;
lval* body; lval* body;
lval* va;
}; };
struct lval { struct lval {

View File

@@ -24,7 +24,7 @@ CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}}
# Project Name # Project Name
PROJECTNAME=KLisp PROJECTNAME=klisp
# Active Configuration # Active Configuration
DEFAULTCONF=Debug DEFAULTCONF=Debug