Mercurial > lbo > hg > ylisp
changeset 156:3cd189bd595c
eval: Handle function-value calls correctly
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Tue, 03 Sep 2019 15:35:33 +0200 |
parents | cfe8ddaa770c |
children | 15825a4a3580 |
files | src/eval.c src/eval_test.c |
diffstat | 2 files changed, 69 insertions(+), 26 deletions(-) [+] |
line wrap: on
line diff
--- a/src/eval.c Tue Sep 03 15:35:04 2019 +0200 +++ b/src/eval.c Tue Sep 03 15:35:33 2019 +0200 @@ -4,6 +4,16 @@ #include "expr.h" #include "value.h" +static yexpr_t yeval_undef_ref(yref_t* ref) { + yexpr_t exception = yexpr_new(); + ystr_t msg = ystr_new(NULL); + ystr_t dbg = yref_debug(ref); + ystr_build(&msg, "undefined reference: %s", ystr_str(&dbg)); + ystr_destroy(&dbg); + yexpr_set_exception(&exception, msg); + return exception; +} + yexpr_t yeval_call_func(yeval_state_t* state, yfunc_t* ref, yexpr_t* call) { assert(call->typ == YEXPR_LIST); if (ref->args.len != call->value.list.len - 1) { @@ -73,18 +83,15 @@ return result; } yvalue_t* val = yvalue_get(expr->value.ref); + if (val == NULL) return yeval_undef_ref(&expr->value.ref); if (val->typ == YVALUE_EXPR) { result = yexpr_copy(&val->value.expr); return result; } else if (val->typ == YVALUE_FUNC) { return *expr; } - // Undefined reference! - yexpr_t exception = yexpr_new(); - ystr_t msg = ystr_new("Undefined reference!"); - yexpr_set_exception(&exception, msg); - return exception; + return yeval_undef_ref(&expr->value.ref); case YEXPR_LIST: // Is empty list? if (expr->value.list.len == 0) { @@ -102,30 +109,39 @@ YVEC_PUSH(&state->call_stack, expr); return ybuiltin_run(first->value.builtin, state); } + // Is function call? if (first->typ == YEXPR_REF) { - yvalue_t* val = yvalue_get(first->value.ref); - // Call function. - if (val->typ == YVALUE_FUNC) { - result = yeval_call_func(state, &val->value.func, expr); - if (in_place) { - yexpr_destroy(&result); - return result; + yexpr_t ref = yeval(state, first, false); + // If resolved reference is still possibly a function + if (ref.typ == YEXPR_REF) { + yvalue_t* val = yvalue_get(ref.value.ref); + if (val == NULL) { + return yeval_undef_ref(&expr->value.ref); } - return result; - } else if (val->typ == YVALUE_EXPR) { - // resolve as normal below; this seems to be a "data - // list". - } else { - yexpr_t exc = yexpr_new(); - ystr_t msg = ystr_new(NULL); - ystr_build(&msg, "possibly undefined function: "); - ystr_t dbg = yref_debug(&first->value.ref); - ystr_append(&msg, &dbg); - ystr_destroy(&dbg); - yexpr_set_exception(&exc, msg); - return exc; - assert(val->typ == YVALUE_FUNC || val->typ == YVALUE_EXPR); + // Call function. + if (val->typ == YVALUE_FUNC) { + result = yeval_call_func(state, &val->value.func, expr); + if (in_place) { + yexpr_destroy(&result); + return result; + } + return result; + } else if (val->typ == YVALUE_EXPR) { + // resolve as normal below; this seems to be a "data + // list". + } else { + yexpr_t exc = yexpr_new(); + ystr_t msg = ystr_new(NULL); + ystr_build(&msg, "possibly undefined function: "); + ystr_t dbg = yref_debug(&first->value.ref); + ystr_append(&msg, &dbg); + ystr_destroy(&dbg); + yexpr_set_exception(&exc, msg); + return exc; + assert(val->typ == YVALUE_FUNC || + val->typ == YVALUE_EXPR); + } } }
--- a/src/eval_test.c Tue Sep 03 15:35:04 2019 +0200 +++ b/src/eval_test.c Tue Sep 03 15:35:33 2019 +0200 @@ -83,10 +83,37 @@ ystr_destroy(&input); } +void test_eval_higher_order(void) { + fprintf(stderr, "test_eval_higher_order ===========\n"); + + // Calculate faculty values from 1 to 10. + ystr_t input = ystr_new( + "(defn f (a) (+ a 1))" + "(defn g (fn) (fn 3))" + "(g f)"); + + yexpr_t program = yexpr_new(); + ystr_t error = ystr_new(NULL); + assert(yparse_str(&input, &program, &error)); + ypreprocess(&program); + + yeval_state_t state; + state.call_stack = YVEC_NEW(NULL, 4, yexpr_t); + yexpr_t result = yeval_list_return_last(&state, &program.value.list, 0); + assert(YEXPR_NUMBER == result.typ && 4 == result.value.n); + + yexpr_destroy(&program); + yvec_destroy(&state.call_stack); + ystr_destroy(&error); + yexpr_destroy(&result); + ystr_destroy(&input); +} + int main(void) { test_eval_edge_cases(); test_eval_func_wrong_call(); test_eval_recursion(); + test_eval_higher_order(); yvalue_free_all(); yatom_free_all(); return 0;