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.
83 lines
2.1 KiB
C
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);
|
|
}
|
|
}
|
|
}
|