Mercurial > lbo > hg > ylisp
changeset 103:354afb93f898
in-progress: built-ins: Implement `for`
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Wed, 28 Aug 2019 12:11:28 +0200 |
parents | da80a755723f |
children | b9ea42b9f3f6 |
files | src/built-ins.c src/built-ins_test.c |
diffstat | 2 files changed, 78 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/built-ins.c Wed Aug 28 10:29:52 2019 +0200 +++ b/src/built-ins.c Wed Aug 28 12:11:28 2019 +0200 @@ -133,6 +133,8 @@ yvec_t* for_items_l = &for_items->value.list; yeval_state_t emptystate = {.call_stack = YVEC_NEW(NULL, 0, yexpr_t)}; + + // nested loop: once items, then exprs // counter now points to the first expression. for (size_t i = 0; i < for_items_l->len; i++) { yexpr_t* expr = YVEC_AT(for_items_l, i, yexpr_t); @@ -190,13 +192,41 @@ #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_plus(yeval_state_t* state) { +#define _pattern "(+ numeric-expr numeric-expr [numeric-expr ...])" + yexpr_t plus; + + if (!yvec_pop(&state->call_stack, &plus)) NOTENOUGHFAIL(PLUS); + if (plus.typ != YEXPR_LIST) BADEXPRFAIL(PLUS, plus); + if (plus.value.list.len < 3) BADEXPRFAIL(PLUS, plus); + + yvec_t* plus_list = &plus.value.list; + + long long result = 0; + for (size_t i = 1; i < plus_list->len; i++) { + yexpr_t* expr = YVEC_AT(plus_list, i, yexpr_t); + yexpr_t evald = yeval(state, expr, false); + if (evald.typ != YEXPR_NUMBER) TYPEFAIL(PLUS, *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 +} + /** * @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}; + ybuiltin_fn_let, NULL, ybuiltin_fn_plus}; const char* ybuiltin_name(YBUILTIN_TYPE t) { assert(t * sizeof(const char*) < sizeof(YBUILTIN_ENUM_STR));
--- a/src/built-ins_test.c Wed Aug 28 10:29:52 2019 +0200 +++ b/src/built-ins_test.c Wed Aug 28 12:11:28 2019 +0200 @@ -26,6 +26,51 @@ assert(YBUILTIN_LET == expr.value.builtin); } +void test_builtin_for(void) { + ystr_t input = ystr_new("(for loopvar (1 2 3) loopvar)"), error = ystr_new(NULL); + yexpr_t program = yexpr_new(); + assert(yparse_str(&input, &program, &error)); + 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))); + + yeval_state_t state = { .call_stack = YVEC_NEW(NULL, 0, yexpr_t) }; + YVEC_PUSH(&state.call_stack, for_expr); + + yexpr_t result = ybuiltin_run(YBUILTIN_FOR, &state); + assert(result.typ == YEXPR_LIST); + + yvec_destroy(&state.call_stack); + yexpr_destroy(&program); + ystr_destroy(&input); +} + +void test_builtin_for_complex(void) { + ystr_t input = ystr_new("(for loopvar (1 2 3) (+ loopvar 1))"), error = ystr_new(NULL); + yexpr_t program = yexpr_new(); + assert(yparse_str(&input, &program, &error)); + 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))); + yexpr_debug(for_expr); + + yeval_state_t state = { .call_stack = YVEC_NEW(NULL, 0, yexpr_t) }; + YVEC_PUSH(&state.call_stack, for_expr); + + yexpr_t result = ybuiltin_run(YBUILTIN_FOR, &state); + assert(result.typ == YEXPR_LIST); + + yexpr_debug(&result); + fputs("\n", stderr); + + yvec_destroy(&state.call_stack); + yexpr_destroy(&program); + ystr_destroy(&input); +} + void test_builtin_let(void) { yexpr_t ref_expr = yexpr_new(); yexpr_t let_expr = yexpr_new(); @@ -125,6 +170,8 @@ int main(void) { test_builtin_translate(); + test_builtin_for(); + test_builtin_for_complex(); test_builtin_let(); test_builtin_let_parsed(); return 0;