static action_t cont_list() { ref_t sym = check_symbol(car(expr)); expr = cdr(expr); if (sym == sym_do) eval_do(expr); else if (sym == sym_fn) C(cont)->fn = cont_fn; else if (sym == sym_if) C(cont)->fn = cont_if; else if (sym == sym_quote) C(cont)->fn = cont_quote; else eval_apply(get_function(sym)); return ACTION_APPLY_CONT; }
Value eval_list(Value expression, Environment *environment) { w_assert(expression.type == CONS); Bool lambda_call = false; Value function_symbol = NEXT(expression); Value lambda; Function *function; if (function_symbol.type == CONS) { if (CAR(function_symbol).type == SYMBOL && CAR(function_symbol).val.symbol_val == symbols_lambda.val.symbol_val) { lambda = eval(function_symbol, environment); lambda_call = true; } else { return VALUE_ERROR; } } else if (function_symbol.type == LAMBDA) { lambda = function_symbol; lambda_call = true; } else if (function_symbol.type == SYMBOL) { Value function_value; Bool found = hash_get(environment -> functions, function_symbol, &function_value); if (!found) { /* TODO: log error */ /* TODO: "Did you mean?" */ debug_value(function_symbol); log_error("Function XXX not found"); return VALUE_ERROR; } w_assert(function_value.type == FUNCTION); function = function_value.val.function_val; } else { return VALUE_ERROR; } Value args; if (lambda_call || function -> eval) { args = VALUE_NIL; while (expression.type == CONS) { Value arg = NEXT(expression); args = CONS(eval(arg, environment), args); } args = list_reverse(args); w_assert(expression.type == NIL); /* TODO: benchmark, which approach is better, the above or below? */ /* if (expression.type == CONS) { */ /* args = CONS1(VALUE_NIL); */ /* } else { */ /* args = expression; */ /* } */ /* Cons *top = args.val.cons_val; */ /* while (true) { */ /* Value arg = NEXT(expression); */ /* top -> car = eval(arg, environment); */ /* if (expression.type == CONS) { */ /* top -> cdr = CONS1(VALUE_NIL); */ /* top = top -> cdr.val.cons_val; */ /* } else { */ /* top -> cdr = expression; */ /* break; */ /* } */ /* } */ } else { /* To ensure we avoid mutation in altering code the list is copied If we guaranteed that no function with eval = false modifies the list we could give it directly This would be an obvious performance optimization. But needs tests. We can only guarantee this for c_code, not for userdefined macros. TODO: Do this */ args = list_copy(expression); } Value result; if (lambda_call) { result = eval_lambda(lambda, args, environment); } else { result = eval_apply(function_symbol, function, args, environment); } list_destroy(args); return result; }
static pobject apply(pobject env, pobject params) { /* XXX: apply needs more work */ return eval_apply(env, eval(env, cons_car(params)), eval(env, cons_nth(params, 2))); }
static void fn_apply() { eval_apply(check_function(lookup(sym_fn))); cont = continuation(NULL, cont); expr = check_list(lookup(sym_args)); }