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:
parent
3d7bef187c
commit
3bbd0e79a1
6 changed files with 52 additions and 4 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ struct matcher_state {
|
|||
|
||||
struct matcher_call_stack_entry {
|
||||
size_t pc;
|
||||
bool from_predicate;
|
||||
struct matcher *matcher;
|
||||
struct scopes scopes;
|
||||
|
||||
|
|
|
|||
20
src/eval.c
20
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;
|
||||
|
|
|
|||
32
src/functional-tests/predicate.at
Normal file
32
src/functional-tests/predicate.at
Normal 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
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue