lval* lval_call(lenv* e, lval* f, lval* a) { /* If Builtin then simply apply that */ if (f->builtin) { return f->builtin(e, a); } /* Record Argument Counts */ int given = a->count; int total = f->formals->count; /* While arguments still remain to be processed */ while (a->count) { /* If we've ran out of formal arguments to bind */ if (f->formals->count == 0) { lval_del(a); return lval_err("Function passed too many arguments. Got %i, Expected %i.", given, total); } /* Pop the first symbol from the formals */ lval* sym = lval_pop(f->formals, 0); /* Special Case to deal with '&' */ if (strcmp(sym->sym, "&") == 0) { /* Ensure '&' is followed by another symbol */ if (f->formals->count != 1) { lval_del(a); return lval_err("Function format invalid. Symbol '&' not followed by single symbol."); } /* Next formal should be bound to remaining arguments */ lval* nsym = lval_pop(f->formals, 0); lenv_put(f->env, nsym, builtin_list(e, a)); lval_del(sym); lval_del(nsym); break; } /* Pop the next argument from the list */ lval* val = lval_pop(a, 0); /* Bind a copy into the function's environment */ lenv_put(f->env, sym, val); /* Delete symbol and value */ lval_del(sym); lval_del(val); } /* Argument list is now bound so can be cleaned up */ lval_del(a); /* If '&' remains in formal list it should be bound to empty list */ if (f->formals->count > 0 && strcmp(f->formals->cell[0]->sym, "&") == 0) { /* Check to ensure that & is not passed invalidly. */ if (f->formals->count != 2) { return lval_err("Function format invalid. Symbol '&' not followed by single symbol."); } /* Pop and delete '&' symbol */ lval_del(lval_pop(f->formals, 0)); /* Pop next symbol and create empty list */ lval* sym = lval_pop(f->formals, 0); lval* val = lval_qexpr(); /* Bind to environment and delete */ lenv_put(f->env, sym, val); lval_del(sym); lval_del(val); } /* If all formals have been bound evaluate */ if (f->formals->count == 0) { /* Set Function Environment parent to current evaluation Environment */ f->env->par = e; /* Evaluate and return */ return builtin_eval(f->env, lval_add(lval_sexpr(), lval_copy(f->body))); } else { /* Otherwise return partially evaluated function */ return lval_copy(f); } }
lval* lval_call(lenv* e, lval* f, lval* a) { if (f->builtin) { return f->builtin(e, a); } int given = a->count; int total = f->formals->count; while (a->count) { if (f->formals->count == 0) { lval_del(a); return lval_err("Function passed too many arguments. Expected %i, Got %i.", total, given); } lval* sym = lval_pop(f->formals, 0); // Variadic operator if (strcmp(sym->sym, "&") == 0){ if (f->formals->count != 1) { lval_del(a); return lval_err("Function format invalid. " "Symbol '&' not followed by a single symbol"); } lval* nsym = lval_pop(f->formals, 0); lenv_put(f->env, nsym, builtin_list(e, a)); lval_del(sym); lval_del(nsym); break; } lval* val = lval_pop(a, 0); lenv_put(f->env, sym, val); lval_del(val); lval_del(sym); } lval_del(a); // If '&' remains in formal list bind to empty list if (f->formals->count > 0 && strcmp(f->formals->cell[0]->sym, "&") == 0) { if (f->formals->count != 2) { return lval_err("Function format invalid. " "Symbol '&' not followed by a single symbol"); } lval_del(lval_pop(f->formals, 0)); lval* sym = lval_pop(f->formals, 0); lval* val = lval_qexpr(); lenv_put(f->env, sym, val); lval_del(val); lval_del(sym); } if (f->formals->count == 0) { f->env->par = e; return builtin_eval(f->env, lval_add(lval_sexpr(), lval_copy(f->body))); } else { return lval_copy(f); } }
Value* tl_val_call(Env* e, Value* fn, Value* args) { if(fn->builtin) { return fn->builtin(e, args); } int given = args->count; int total = fn->formals->count; while (args->count) { if (fn->formals->count == 0) { tl_val_delete(args); return tl_val_error( "Function passed too many arguments. " "Got %i, expected %i.", given, total); } Value* sym = tl_val_pop(fn->formals, 0); if (strcmp(sym->sym, "&") == 0) { if (fn->formals->count != 1) { tl_val_delete(args); return tl_val_error("Function format invalid." "Symbol '&' not followed by single symbol"); } Value* symbols = tl_val_pop(fn->formals, 0); tl_env_put(fn->env, symbols, builtin_list(e, args)); tl_val_delete(sym); tl_val_delete(symbols); break; } Value* val = tl_val_pop(args, 0); tl_env_put(fn->env, sym, val); tl_val_delete(sym); tl_val_delete(val); } if (fn->formals->count > 0 && strcmp(fn->formals->cell[0]->sym, "&") == 0) { if (fn->formals->count != 2) { return tl_val_error("Function format invalid." "Symbol '&' not followed by single symbol"); } tl_val_delete(tl_val_pop(fn->formals, 0)); Value* symbol = tl_val_pop(fn->formals, 0); Value* value = tl_val_qexpr(); tl_env_put(e, symbol, value); tl_val_delete(symbol); tl_val_delete(value); } tl_val_delete(args); if (fn->formals->count == 0) { // Eval and return if all formals have been bound fn->env->parent = e; return builtin_eval(fn->env, tl_val_add(tl_val_sexpr(), tl_val_copy(fn->body))); } else { // Partially evaluated function return tl_val_copy(fn); } }