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.
This commit is contained in:
Laria 2022-11-19 23:20:22 +01:00
parent 3d7bef187c
commit 3bbd0e79a1
6 changed files with 52 additions and 4 deletions

View file

@ -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)

View file

@ -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;

View file

@ -90,6 +90,7 @@ struct matcher_state {
struct matcher_call_stack_entry {
size_t pc;
bool from_predicate;
struct matcher *matcher;
struct scopes scopes;

View file

@ -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;

View file

@ -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

View file

@ -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",