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;