apfl/src/matcher.c
Laria Carolin Chabowski 42fe4f6b33 matcher: Fix relying on GC'ed milist in deinit function
When the GC calls the matchers deinit function, the milist (also an GC-able
object) might already have been deinitialized, so we can't use the count
values from there.

Maybe milist should actually be refcounted? It doesn't build cycles and
doesn't reference other GC objects. This would simplify it and remove the
now duplicated count data.
2022-08-12 14:42:49 +02:00

83 lines
2.1 KiB
C

#include "alloc.h"
#include "gc.h"
#include "matcher.h"
static bool
init_values_list(struct apfl_allocator allocator, struct apfl_value **list, size_t len)
{
if (len == 0) {
return true;
}
if ((*list = ALLOC_LIST(allocator, struct apfl_value, len)) == NULL) {
return false;
}
for (size_t i = 0; i < len; i++) {
(*list)[i] = (struct apfl_value) { .type = VALUE_NIL };
}
return true;
}
struct matcher *
apfl_matcher_new(struct gc *gc, struct matcher_instruction_list *milist)
{
struct matcher matcher = {
.instructions = milist,
.value_count = 0,
.capture_count = 0,
.values = NULL,
.captures = NULL,
.result = false,
};
if (!init_values_list(gc->allocator, &matcher.values, milist->value_count)) {
goto error;
}
matcher.value_count = milist->value_count;
if (!init_values_list(gc->allocator, &matcher.captures, milist->capture_count)) {
goto error;
}
matcher.capture_count = milist->capture_count;
struct matcher *gc_matcher = apfl_gc_new_matcher(gc);
if (gc_matcher == NULL) {
goto error;
}
*gc_matcher = matcher;
return gc_matcher;
error:
apfl_matcher_deinit(gc->allocator, &matcher);
return NULL;
}
void
apfl_matcher_deinit(struct apfl_allocator allocator, struct matcher *matcher)
{
FREE_LIST(allocator, matcher->values, matcher->value_count);
FREE_LIST(allocator, matcher->captures, matcher->capture_count);
}
void
apfl_gc_matcher_traverse(struct matcher *matcher, gc_visitor visitor, void *opaque)
{
visitor(opaque, GC_OBJECT_FROM(matcher->instructions, GC_TYPE_MATCHER_INSTRUCTIONS));
for (size_t i = 0; i < matcher->instructions->value_count; i++) {
struct gc_object *object = apfl_value_get_gc_object(matcher->values[i]);
if (object != NULL) {
visitor(opaque, object);
}
}
for (size_t i = 0; i < matcher->instructions->capture_count; i++) {
struct gc_object *object = apfl_value_get_gc_object(matcher->captures[i]);
if (object != NULL) {
visitor(opaque, object);
}
}
}