Mercurial > lbo > hg > ylisp
changeset 146:aa551e42de49
built-ins: Implement minus, multiplication, if, == built-ins
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Tue, 03 Sep 2019 12:15:51 +0200 |
parents | 7887550c61c6 |
children | 1e9d534b903d |
files | src/built-ins.c src/built-ins_test.c |
diffstat | 2 files changed, 136 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/src/built-ins.c Tue Sep 03 12:15:21 2019 +0200 +++ b/src/built-ins.c Tue Sep 03 12:15:51 2019 +0200 @@ -232,14 +232,142 @@ #undef _pattern } +/// Expects a list expression starting with built-in "-" on the stack. It is not +/// modified. Returns a number expression or an exception. +yexpr_t ybuiltin_fn_minus(yeval_state_t* state) { +#define _pattern "(- numeric-expr numeric-expr [numeric-expr ...])" + yexpr_t minus; + + if (!yvec_pop(&state->call_stack, &minus)) NOTENOUGHFAIL(MINUS); + if (minus.typ != YEXPR_LIST) BADEXPRFAIL(MINUS, minus); + if (minus.value.list.len < 3) BADEXPRFAIL(MINUS, minus); + + yvec_t* minus_list = &minus.value.list; + + long long result = 0; + bool first = true; + for (size_t i = 1; i < minus_list->len; i++) { + yexpr_t* expr = YVEC_AT(minus_list, i, yexpr_t); + yexpr_t evald = yeval(state, expr, false); + if (evald.typ != YEXPR_NUMBER) TYPEFAIL(MINUS, *expr, _pattern); + if (first) { + result += evald.value.n; + first = false; + } else { + result -= evald.value.n; + } + yexpr_destroy(&evald); + } + + yexpr_t result_expr = yexpr_new(); + yexpr_set_number(&result_expr, result); + return result_expr; + +#undef _pattern +} + +/// Expects a list expression starting with built-in "*" on the stack. It is not +/// modified. Returns a number expression or an exception. +yexpr_t ybuiltin_fn_times(yeval_state_t* state) { +#define _pattern "(* numeric-expr numeric-expr [numeric-expr ...])" + yexpr_t times; + + if (!yvec_pop(&state->call_stack, ×)) NOTENOUGHFAIL(MULT); + if (times.typ != YEXPR_LIST) BADEXPRFAIL(MULT, times); + if (times.value.list.len < 3) BADEXPRFAIL(MULT, times); + + yvec_t* times_list = ×.value.list; + + long long result = 1; + for (size_t i = 1; i < times_list->len; i++) { + yexpr_t* expr = YVEC_AT(times_list, i, yexpr_t); + yexpr_t evald = yeval(state, expr, false); + if (evald.typ != YEXPR_NUMBER) TYPEFAIL(MULT, *expr, _pattern); + result *= evald.value.n; + yexpr_destroy(&evald); + } + + yexpr_t result_expr = yexpr_new(); + yexpr_set_number(&result_expr, result); + return result_expr; + +#undef _pattern +} + +yexpr_t ybuiltin_fn_if(yeval_state_t* state) { +#define _pattern \ + "(if condition then-expr/(then-exprs) [else-expr/(else-exprs)])" + yexpr_t if_expr = yexpr_new(); + + if (!yvec_pop(&state->call_stack, &if_expr)) NOTENOUGHFAIL(IF); + if (if_expr.typ != YEXPR_LIST) BADEXPRFAIL(IF, if_expr); + if (if_expr.value.list.len < 3) BADEXPRFAIL(IF, if_expr); + + yexpr_t* condition = YVEC_AT(&if_expr.value.list, 1, yexpr_t); + yexpr_t* then_expr = YVEC_AT(&if_expr.value.list, 2, yexpr_t); + yexpr_t* else_expr = NULL; + if (if_expr.value.list.len > 3) + else_expr = YVEC_AT(&if_expr.value.list, 3, yexpr_t); + + yexpr_t cond_result = yeval(state, condition, false); + bool result = false; + if (cond_result.typ == YEXPR_ATOM && + yatom_get_or_add("true") == cond_result.value.atom) + result = true; + if (cond_result.typ == YEXPR_NUMBER && cond_result.value.n != 0) + result = true; + + if (result) { + if (then_expr->typ == YEXPR_LIST) + return yeval_list_return_last(state, &then_expr->value.list, 0); + return yeval(state, then_expr, false); + } else if (else_expr != NULL) { + if (else_expr->typ == YEXPR_LIST) + return yeval_list_return_last(state, &else_expr->value.list, 0); + return yeval(state, else_expr, false); + } else { + return yexpr_new(); + } + +#undef _pattern +} + +yexpr_t ybuiltin_fn_eq(yeval_state_t* state) { +#define _pattern "(== expr expr [expr...])" + yexpr_t eq = yexpr_new(); + + if (!yvec_pop(&state->call_stack, &eq)) NOTENOUGHFAIL(EQ); + if (eq.typ != YEXPR_LIST) BADEXPRFAIL(EQ, eq); + if (eq.value.list.len < 3) BADEXPRFAIL(EQ, eq); + + yexpr_t* first = YVEC_AT(&eq.value.list, 1, yexpr_t); + yexpr_t* second = YVEC_AT(&eq.value.list, 2, yexpr_t); + yexpr_t firstevald = yeval(state, first, false); + yexpr_t secondevald = yeval(state, second, false); + bool equal = yexpr_equal(&firstevald, &secondevald); + yexpr_destroy(&firstevald); + yexpr_destroy(&secondevald); + + yexpr_t result = yexpr_new(); + if (equal) + yexpr_set_atom(&result, yatom_get_or_add("true")); + else + yexpr_set_atom(&result, yatom_get_or_add("false")); + return result; +#undef _pattern +} + /** * @brief Table of built-in functions, indexed by YBUILTIN_TYPE. * * TODO: write built-ins. */ static const ybuiltin_fn YBUILTIN_FNS[] = {ybuiltin_fn_undef, ybuiltin_fn_for, - ybuiltin_fn_let, NULL, - ybuiltin_fn_plus}; + ybuiltin_fn_let, NULL, + ybuiltin_fn_plus, ybuiltin_fn_minus, + ybuiltin_fn_times, NULL, + ybuiltin_fn_if, NULL, + ybuiltin_fn_eq}; const char* ybuiltin_name(YBUILTIN_TYPE t) { assert(t * sizeof(const char*) < sizeof(YBUILTIN_ENUM_STR));
--- a/src/built-ins_test.c Tue Sep 03 12:15:21 2019 +0200 +++ b/src/built-ins_test.c Tue Sep 03 12:15:51 2019 +0200 @@ -39,7 +39,10 @@ yexpr_t* for_expr = YVEC_AT(&program.value.list, 0, yexpr_t); assert(for_expr->typ == YEXPR_LIST); + yexpr_debug(&program); ypreprocess_resolve_builtins(&program); + ypreprocess_refs(&program); + yexpr_debug(&program); yeval_state_t state = {.call_stack = YVEC_NEW(NULL, 0, yexpr_t)}; YVEC_PUSH(&state.call_stack, for_expr); @@ -65,9 +68,7 @@ yexpr_t* for_expr = YVEC_AT(&program.value.list, 0, yexpr_t); assert(for_expr->typ == YEXPR_LIST); - assert(ybuiltin_translate(YVEC_AT(&for_expr->value.list, 0, yexpr_t))); - assert(ybuiltin_translate(YVEC_AT( - &YVEC_AT(&for_expr->value.list, 3, yexpr_t)->value.list, 0, yexpr_t))); + ypreprocess(&program); yexpr_debug(for_expr); yeval_state_t state = {.call_stack = YVEC_NEW(NULL, 0, yexpr_t)}; @@ -97,6 +98,7 @@ assert(for_expr->typ == YEXPR_LIST); ypreprocess_resolve_builtins(&program); + ypreprocess_refs(&program); yexpr_debug(for_expr); yeval_state_t state = {.call_stack = YVEC_NEW(NULL, 0, yexpr_t)}; @@ -250,5 +252,6 @@ test_builtin_let_parsed(); test_builtin_let_recall(); yvalue_free_all(); + yatom_free_all(); return 0; }