From 97d79754dda571c28053c47f08d319b8a239021b Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Mon, 31 Oct 2022 15:51:56 +0100 Subject: [PATCH] Implement while --- src/CMakeLists.txt | 1 + src/apfl.h | 2 ++ src/context.c | 7 +++++++ src/functional-tests/while.at | 28 ++++++++++++++++++++++++++ src/globals.c | 37 +++++++++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+) create mode 100644 src/functional-tests/while.at diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 429017c..d748957 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,7 @@ functionaltest("len") functionaltest("not") functionaltest("type") functionaltest("if") +functionaltest("while") install(TARGETS apfl DESTINATION lib) install(TARGETS apfl-bin DESTINATION bin) diff --git a/src/apfl.h b/src/apfl.h index 71ed0cb..f2edde6 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -657,6 +657,8 @@ enum apfl_value_type apfl_get_type(apfl_ctx, apfl_stackidx); void apfl_drop(apfl_ctx, apfl_stackidx); // Move a value to the top of the stack void apfl_move_to_top_of_stack(apfl_ctx, apfl_stackidx); +// Copy a value to the top of the stack +void apfl_copy(apfl_ctx ctx, apfl_stackidx index); // Push a nil onto the stack void apfl_push_nil(apfl_ctx); // Push a boolean onto the stack diff --git a/src/context.c b/src/context.c index f3e30ea..ca1e98d 100644 --- a/src/context.c +++ b/src/context.c @@ -427,6 +427,13 @@ apfl_move_to_top_of_stack(apfl_ctx ctx, apfl_stackidx index) } } +void +apfl_copy(apfl_ctx ctx, apfl_stackidx index) +{ + struct apfl_value value = apfl_stack_must_get(ctx, index); + apfl_stack_must_push(ctx, apfl_value_set_cow_flag(value)); +} + void apfl_stack_clear(apfl_ctx ctx) { diff --git a/src/functional-tests/while.at b/src/functional-tests/while.at new file mode 100644 index 0000000..9ba3faa --- /dev/null +++ b/src/functional-tests/while.at @@ -0,0 +1,28 @@ +===== script ===== +i = 0 +while { (not (== i 10)) } { + print i + i = + i 1 +} + +i = 0 +print (while { (not (== i 10)) } { + i = + i 1 + * 10 i +}) + +print (while {false} {"fail"}) + +===== output ===== +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +100 +nil diff --git a/src/globals.c b/src/globals.c index c977162..2c501f4 100644 --- a/src/globals.c +++ b/src/globals.c @@ -274,6 +274,42 @@ type(apfl_ctx ctx) apfl_push_const_string(ctx, typestr(apfl_get_type(ctx, -1))); } +static void +impl_while(apfl_ctx ctx) +{ + size_t argc = apfl_len(ctx, 0); + if (argc != 2) { + apfl_raise_const_error(ctx, APFL_RESULT_ERR, "while needs 2 functions as arguments"); + } + + apfl_get_list_member_by_index(ctx, 0, 0); + if (apfl_get_type(ctx, -1) != APFL_VALUE_FUNC) { + apfl_raise_const_error(ctx, APFL_RESULT_ERR, "while needs 2 functions as arguments"); + } + apfl_get_list_member_by_index(ctx, 0, 1); + if (apfl_get_type(ctx, -1) != APFL_VALUE_FUNC) { + apfl_raise_const_error(ctx, APFL_RESULT_ERR, "while needs 2 functions as arguments"); + } + + apfl_drop(ctx, 0); + + apfl_push_nil(ctx); // Return value in case of no iteration + + for (;;) { + apfl_copy(ctx, 0); + apfl_list_create(ctx, 0); + apfl_call(ctx, -2, -1); + if (!apfl_is_truthy(ctx, -1)) { + break; + } + + apfl_drop(ctx, -1); + apfl_copy(ctx, 1); + apfl_list_create(ctx, 0); + apfl_call(ctx, -2, -1); + } +} + static const struct global_def globals[] = { {"if", impl_if}, {"==", impl_eq}, @@ -288,6 +324,7 @@ static const struct global_def globals[] = { {"not", not}, {"len", len}, {"type", type}, + {"while", impl_while}, {NULL, NULL}, };