From 3bbd0e79a1fbe16bec065d7ae073929ffb20ad0f Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Sat, 19 Nov 2022 23:20:22 +0100 Subject: [PATCH] Implement predicates This implements the last remaining feature of the language syntax! :) The implementation of this was delightfully simple, since all the heavy lifting is done by already implemented functions. --- src/CMakeLists.txt | 1 + src/apfl.h | 1 - src/context.h | 1 + src/eval.c | 20 +++++++++++++++++-- src/functional-tests/predicate.at | 32 +++++++++++++++++++++++++++++++ src/messages.c | 1 - 6 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/functional-tests/predicate.at diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 11d758a..c03f377 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,6 +68,7 @@ functionaltest("eq") functionaltest("chained-assignments") functionaltest("dictionary-assignments") functionaltest("variadic-functions") +functionaltest("predicate") install(TARGETS apfl DESTINATION lib) install(TARGETS apfl-bin DESTINATION bin) diff --git a/src/apfl.h b/src/apfl.h index 3c03a7d..14b085a 100644 --- a/src/apfl.h +++ b/src/apfl.h @@ -731,7 +731,6 @@ struct apfl_messages { const char *could_not_alloc_mem; const char *input_error_while_parsing; const char *unexpected_end_of_file; - const char *feature_not_implemented; const char *corrupted_bytecode; const char *not_a_list; const char *not_a_dict; diff --git a/src/context.h b/src/context.h index a9e7496..200af96 100644 --- a/src/context.h +++ b/src/context.h @@ -90,6 +90,7 @@ struct matcher_state { struct matcher_call_stack_entry { size_t pc; + bool from_predicate; struct matcher *matcher; struct scopes scopes; diff --git a/src/eval.c b/src/eval.c index 31be76d..0f12c63 100644 --- a/src/eval.c +++ b/src/eval.c @@ -734,6 +734,7 @@ matcher_init_matching_inner(apfl_ctx ctx, struct matcher *matcher, struct scopes size_t capture_count = matcher->instructions->capture_count; struct matcher_call_stack_entry matcher_cse = { .pc = 0, + .from_predicate = false, .matcher = matcher, .scopes = scopes, .capture_index = 0, @@ -1177,6 +1178,11 @@ evaluate_matcher(apfl_ctx ctx, struct matcher_call_stack_entry *cse) { union matcher_instruction_or_arg arg; + if (cse->from_predicate) { + cse->from_predicate = false; + RETURN_WITHOUT_MATCH_ON_FALSE(ctx, apfl_is_truthy(ctx, -1)); + } + size_t *pc = &cse->pc; struct matcher *matcher = cse->matcher; struct matcher_instruction_list *milist = matcher->instructions; @@ -1229,8 +1235,18 @@ evaluate_matcher(apfl_ctx ctx, struct matcher_call_stack_entry *cse) } must_get_matcher_argument(ctx, pc, milist, &arg); matcher_check_index(ctx, milist->value_count, arg.index); - apfl_raise_const_error(ctx, APFL_RESULT_ERR, apfl_messages.feature_not_implemented); // TODO: Implement this - goto continue_loop; + apfl_stack_must_push(ctx, apfl_value_set_cow_flag(matcher->values[arg.index])); + apfl_list_create(ctx, 1); + apfl_stack_must_push(ctx, apfl_value_set_cow_flag(cur)); + apfl_list_append(ctx, -2, -1); + + cse->from_predicate = true; + call(ctx, -2, -1, true); + + // By returning from this function, the newly pushed call stack entry (if any) will get picked up by + // evaluate_until_call_stack_return. In case no new CSE was pushed (when a cfunc was called), we'll the + // simply continue with the current call stack. + return; case MATCHER_ENTER_LIST: RETURN_WITHOUT_MATCH_ON_FALSE(ctx, matcher_enter_list(ctx, cse)); goto continue_loop; diff --git a/src/functional-tests/predicate.at b/src/functional-tests/predicate.at new file mode 100644 index 0000000..980f23d --- /dev/null +++ b/src/functional-tests/predicate.at @@ -0,0 +1,32 @@ +===== script ===== +print ({ + x?{x -> == (len x) 2} -> [2 x] + x?{x -> == (len x) 3} -> [3 x] +} [1 2 3]) + +k = 'foo +d = [ + 'foo -> 'oldfoo + 'bar -> 'oldbar +] +print d.foo +print d.bar +d@k?{ k = 'bar; true } = 'newfoo +print d.foo +print d.bar +print k + +===== output ===== +[ + 3 + [ + 1 + 2 + 3 + ] +] +oldfoo +oldbar +newfoo +oldbar +bar diff --git a/src/messages.c b/src/messages.c index bdb4e9d..3353cfa 100644 --- a/src/messages.c +++ b/src/messages.c @@ -5,7 +5,6 @@ const struct apfl_messages apfl_messages = { .could_not_alloc_mem = "Could not allocate memory", .input_error_while_parsing = "Input error while parsing", .unexpected_end_of_file = "Unexpected end of file", - .feature_not_implemented = "Feature not implemented", .corrupted_bytecode = "Bytecode is corrupted", .not_a_list = "Value is not a list", .not_a_dict = "Value is not a dictionary",