Merge branch 'gc'
This commit is contained in:
commit
8847643c2e
|
@ -8,7 +8,7 @@ project(libabacus)
|
|||
|
||||
add_compile_options(-pedantic -Wall)
|
||||
|
||||
add_library(abacus STATIC src/lexer.c src/util.c src/table.c src/parser.c src/libabacus.c src/tree.c src/debug.c src/parsetype.c src/reserved.c src/trie.c src/refcount.c src/ref_vec.c src/ref_trie.c src/basetype.c src/value.c src/custom.c src/interpreter.c src/function_list.c src/free_functions.c)
|
||||
add_library(abacus STATIC src/lexer.c src/util.c src/table.c src/parser.c src/libabacus.c src/tree.c src/debug.c src/parsetype.c src/reserved.c src/trie.c src/refcount.c src/ref_vec.c src/ref_trie.c src/basetype.c src/value.c src/custom.c src/interpreter.c src/function_list.c src/free_functions.c src/gc.c)
|
||||
add_executable(libabacus src/main.c)
|
||||
add_executable(interactive src/interactive.c)
|
||||
add_subdirectory(external/liblex)
|
||||
|
|
56
include/gc.h
Normal file
56
include/gc.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef LIBABACUS_GC_H
|
||||
#define LIBABACUS_GC_H
|
||||
|
||||
#include "refcount.h"
|
||||
#include "gc_functions.h"
|
||||
|
||||
/**
|
||||
* Struct used to create an interface
|
||||
* for a set of objects to be collected.
|
||||
*/
|
||||
struct libab_gc_list_s {
|
||||
/**
|
||||
* The head sentinel node.
|
||||
*/
|
||||
struct libab_ref_count_s head_sentinel;
|
||||
/**
|
||||
* The tail sentinel node.
|
||||
*/
|
||||
struct libab_ref_count_s tail_sentinel;
|
||||
};
|
||||
|
||||
typedef struct libab_gc_list_s libab_gc_list;
|
||||
|
||||
/**
|
||||
* Initializes a garbage collection tracking list.
|
||||
* @param list the list to initialize.
|
||||
*/
|
||||
void libab_gc_list_init(libab_gc_list* list);
|
||||
/**
|
||||
* Visits the children of the current node, applying the given function to them.
|
||||
* @param ref the reference whose children to visit.
|
||||
* @param visitor the function to call for each child.
|
||||
* @param data the data to pass to the visitor.
|
||||
*/
|
||||
void libab_gc_visit_children(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data);
|
||||
/**
|
||||
* Applies the given visitor function to this reference.
|
||||
*/
|
||||
void libab_gc_visit(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data);
|
||||
/**
|
||||
* Adds the given reference to the given garbage collection list,
|
||||
* and specifies a function used to reach its children.
|
||||
* @param ref the reference whose children to visit.
|
||||
* @param visit_children the function used to reach the chilren of this reference.
|
||||
* @param list the list to which to add the reference.
|
||||
*/
|
||||
void libab_gc_add(struct libab_ref_s* ref,
|
||||
libab_visit_function_ptr visit_children,
|
||||
libab_gc_list* list);
|
||||
/**
|
||||
* Performs garbage collection on a given list of container objects/
|
||||
* @param list the list to run collection on.
|
||||
*/
|
||||
void libab_gc_run(libab_gc_list* list);
|
||||
|
||||
#endif
|
10
include/gc_functions.h
Normal file
10
include/gc_functions.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef LIBABACUS_GC_FUNCTIONS_H
|
||||
#define LIBABACUS_GC_FUNCTIONS_H
|
||||
|
||||
struct libab_ref_count_s;
|
||||
struct libab_ref_s;
|
||||
|
||||
typedef void (*libab_visitor_function_ptr)(struct libab_ref_count_s* , void*);
|
||||
typedef void (*libab_visit_function_ptr)(void*, libab_visitor_function_ptr, void*);
|
||||
|
||||
#endif
|
|
@ -9,6 +9,7 @@
|
|||
#include "parser.h"
|
||||
#include "result.h"
|
||||
#include "table.h"
|
||||
#include "gc.h"
|
||||
|
||||
/**
|
||||
* The main struct of libabacus,
|
||||
|
@ -59,6 +60,12 @@ struct libab_s {
|
|||
* The unit type instance.
|
||||
*/
|
||||
libab_ref type_unit;
|
||||
/**
|
||||
* List of containers references
|
||||
* that should be tracked by the
|
||||
* garbage collector for cycles.
|
||||
*/
|
||||
libab_gc_list containers;
|
||||
|
||||
/**
|
||||
* Internal; the number basetype. This cannot be a static
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define LIBABACUS_REFCOUNT_H
|
||||
|
||||
#include "result.h"
|
||||
#include "gc_functions.h"
|
||||
|
||||
/**
|
||||
* A struct for holding
|
||||
|
@ -10,6 +11,10 @@
|
|||
* to free the value.
|
||||
*/
|
||||
struct libab_ref_count_s {
|
||||
/**
|
||||
* The value this reference holds.
|
||||
*/
|
||||
void* data;
|
||||
/**
|
||||
* The fucntion to free the value.
|
||||
* Can be NULL for no-op.
|
||||
|
@ -25,6 +30,26 @@ struct libab_ref_count_s {
|
|||
* that still exist, even to a freed instance.
|
||||
*/
|
||||
int weak;
|
||||
/**
|
||||
* The number of outside references.
|
||||
* This is used for garbage collection.
|
||||
*/
|
||||
int gc;
|
||||
/**
|
||||
* Previous pointer for garbage collection
|
||||
* linked list.
|
||||
*/
|
||||
struct libab_ref_count_s* prev;
|
||||
/**
|
||||
* Next pointer for garbage collection
|
||||
* linked list.
|
||||
*/
|
||||
struct libab_ref_count_s* next;
|
||||
/**
|
||||
* Function used to visit child containers,
|
||||
* used by GC.
|
||||
*/
|
||||
libab_visit_function_ptr visit_children;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -44,10 +69,6 @@ struct libab_ref_s {
|
|||
* of how many references are pointing to the value.
|
||||
*/
|
||||
struct libab_ref_count_s* count;
|
||||
/**
|
||||
* The value this reference holds.
|
||||
*/
|
||||
void* data;
|
||||
};
|
||||
|
||||
typedef struct libab_ref_s libab_ref;
|
||||
|
|
8
include/refcount_internal.h
Normal file
8
include/refcount_internal.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef LIBABACUS_REFCOUNT_INTERNAL_H
|
||||
#define LIBABACUS_REFCOUNT_INTERNAL_H
|
||||
|
||||
#include "refcount.h"
|
||||
|
||||
void libab_ref_count_changed(libab_ref_count* count);
|
||||
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
#include "parsetype.h"
|
||||
#include "result.h"
|
||||
#include "table.h"
|
||||
#include "libabacus.h"
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
|
@ -78,11 +79,12 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
|
|||
libab_ref* into, size_t n, ...);
|
||||
/**
|
||||
* Creates a new libab_table, and stores it into the given reference.
|
||||
* @param ab the libabacus instance in which the table is being created.
|
||||
* @param into the reference to store the table into.
|
||||
* @param parent the parent reference to store.
|
||||
* @return the result of the instantiation.
|
||||
*/
|
||||
libab_result libab_create_table(libab_ref* into, libab_ref* parent);
|
||||
libab_result libab_create_table(libab* ab, libab_ref* into, libab_ref* parent);
|
||||
/**
|
||||
* Allocates a new reference counted value with the given type and data.
|
||||
* @param into the reference to store the allocated data into.
|
||||
|
@ -90,8 +92,8 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent);
|
|||
* @param type the type to give the value.
|
||||
* @return the result of necessary allocations.
|
||||
*/
|
||||
libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
|
||||
libab_ref* type);
|
||||
libab_result libab_create_value_ref(libab* ab, libab_ref* into,
|
||||
libab_ref* data, libab_ref* type);
|
||||
/**
|
||||
* Allocates a new reference counted value with the given type and data.
|
||||
* @param into the reference to store the allocated data into.
|
||||
|
@ -99,8 +101,8 @@ libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
|
|||
* @param type the type to give the value.
|
||||
* @return the result of necessary allocations.
|
||||
*/
|
||||
libab_result libab_create_value_raw(libab_ref* into, void* data,
|
||||
libab_ref* type);
|
||||
libab_result libab_create_value_raw(libab* ab, libab_ref* into,
|
||||
void* data, libab_ref* type);
|
||||
/**
|
||||
* Allocates a function that uses internal code to run.
|
||||
* @param into the reference into which to store the new function.
|
||||
|
@ -109,7 +111,7 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
|
|||
* @param scope the scope in which this function was declared.
|
||||
* @return libab_result the result of any necessary allocations.
|
||||
*/
|
||||
libab_result libab_create_function_internal(libab_ref* into,
|
||||
libab_result libab_create_function_internal(libab* ab, libab_ref* into,
|
||||
void (*free_function)(void*),
|
||||
libab_function_ptr fun,
|
||||
libab_ref* scope);
|
||||
|
@ -121,7 +123,7 @@ libab_result libab_create_function_internal(libab_ref* into,
|
|||
* @param scope the scope in which this function was declared.
|
||||
* @return libab_result the result of any necessary allocations.
|
||||
*/
|
||||
libab_result libab_create_function_tree(libab_ref* into,
|
||||
libab_result libab_create_function_tree(libab* ab, libab_ref* into,
|
||||
void (*free_function)(void*),
|
||||
libab_tree* tree,
|
||||
libab_ref* scope);
|
||||
|
@ -133,7 +135,7 @@ libab_result libab_create_function_tree(libab_ref* into,
|
|||
* @param scope the scope in which this function was declared.
|
||||
* @return libab_result the result of any necessary allocations.
|
||||
*/
|
||||
libab_result libab_create_function_behavior(libab_ref* into,
|
||||
libab_result libab_create_function_behavior(libab* ab, libab_ref* into,
|
||||
void (*free_function)(void*),
|
||||
libab_behavior* behavior,
|
||||
libab_ref* scope);
|
||||
|
@ -143,7 +145,7 @@ libab_result libab_create_function_behavior(libab_ref* into,
|
|||
* @param the function_list type.
|
||||
* @return the result of the allocations.
|
||||
*/
|
||||
libab_result libab_create_function_list(libab_ref* into, libab_ref* type);
|
||||
libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* type);
|
||||
/**
|
||||
* Creates a new table entry that holds the given value.
|
||||
* @param table the table to store the entry into.
|
||||
|
|
103
src/gc.c
Normal file
103
src/gc.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include "gc.h"
|
||||
#include "refcount.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "refcount_internal.h"
|
||||
|
||||
void libab_gc_list_init(libab_gc_list* list) {
|
||||
memset(&list->head_sentinel, 0, sizeof(list->head_sentinel));
|
||||
memset(&list->tail_sentinel, 0, sizeof(list->tail_sentinel));
|
||||
list->head_sentinel.next = &list->tail_sentinel;
|
||||
list->tail_sentinel.prev = &list->head_sentinel;
|
||||
}
|
||||
|
||||
void _gc_count_visit_children(libab_ref_count* ref, libab_visitor_function_ptr func, void* data) {
|
||||
if(ref->strong && ref->visit_children) ref->visit_children(ref->data, func, data);
|
||||
}
|
||||
void libab_gc_visit_children(libab_ref* ref, libab_visitor_function_ptr func, void* data) {
|
||||
if(!ref->null) _gc_count_visit_children(ref->count, func, data);
|
||||
}
|
||||
|
||||
void libab_gc_visit(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data) {
|
||||
if(!ref->null) {
|
||||
visitor(ref->count, data);
|
||||
}
|
||||
}
|
||||
|
||||
void _libab_gc_list_append(libab_gc_list* list,
|
||||
libab_ref_count* node) {
|
||||
libab_ref_count* before;
|
||||
if(node->next) node->next->prev = node->prev;
|
||||
if(node->prev) node->prev->next = node->next;
|
||||
before = &list->tail_sentinel;
|
||||
node->next = before;
|
||||
node->prev = before->prev;
|
||||
before->prev->next = node;
|
||||
before->prev = node;
|
||||
}
|
||||
void libab_gc_add(libab_ref* ref,
|
||||
libab_visit_function_ptr visit_children,
|
||||
libab_gc_list* list) {
|
||||
ref->count->visit_children = visit_children;
|
||||
_libab_gc_list_append(list, ref->count);
|
||||
}
|
||||
|
||||
void _gc_decrement(libab_ref_count* count, void* data) {
|
||||
if(count->visit_children) count->gc--;
|
||||
}
|
||||
void _gc_save(libab_ref_count* count, void* data) {
|
||||
libab_gc_list* list = data;
|
||||
if(count->visit_children && count->gc >= 0) {
|
||||
count->gc = -1;
|
||||
_libab_gc_list_append(list, count);
|
||||
_gc_count_visit_children(count, _gc_save, data);
|
||||
}
|
||||
}
|
||||
|
||||
void libab_gc_run(libab_gc_list* list) {
|
||||
libab_gc_list safe;
|
||||
libab_ref_count* head;
|
||||
|
||||
#define ITERATE(CODE) head = list->head_sentinel.next; \
|
||||
while(head != &list->tail_sentinel) { \
|
||||
libab_ref_count* node = head; \
|
||||
CODE;\
|
||||
head = head->next; \
|
||||
}
|
||||
|
||||
libab_gc_list_init(&safe);
|
||||
ITERATE(node->gc = node->weak);
|
||||
ITERATE(_gc_count_visit_children(node, _gc_decrement, NULL));
|
||||
|
||||
head = list->head_sentinel.next;
|
||||
while(head != &list->tail_sentinel) {
|
||||
if(head->gc > 0) {
|
||||
_gc_save(head, &safe);
|
||||
head = &list->head_sentinel;
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
ITERATE(
|
||||
node->weak = -1;
|
||||
node->strong = -1;
|
||||
if(node->free_func) node->free_func(node->data);
|
||||
);
|
||||
|
||||
while ((head = list->head_sentinel.next) != &list->tail_sentinel) {
|
||||
head->prev->next = head->next;
|
||||
head->next->prev = head->prev;
|
||||
free(head);
|
||||
}
|
||||
|
||||
if(safe.head_sentinel.next != &safe.tail_sentinel) {
|
||||
list->head_sentinel.next = safe.head_sentinel.next;
|
||||
list->head_sentinel.next->prev = &list->head_sentinel;
|
||||
list->tail_sentinel.prev = safe.tail_sentinel.prev;
|
||||
list->tail_sentinel.prev->next = &list->tail_sentinel;
|
||||
} else {
|
||||
list->head_sentinel.next = &list->tail_sentinel;
|
||||
list->tail_sentinel.prev = &list->head_sentinel;
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ libab_result create_double_value(libab* ab, double val, libab_ref* into) {
|
|||
double* new_double = malloc(sizeof(*new_double));
|
||||
if(new_double) {
|
||||
*new_double = val;
|
||||
result = libab_create_value_raw(into, new_double, &type_num);
|
||||
result = libab_create_value_raw(ab, into, new_double, &type_num);
|
||||
if(result != LIBAB_SUCCESS) {
|
||||
free(new_double);
|
||||
}
|
||||
|
@ -217,6 +217,7 @@ libab_result loop(libab* ab, int interaction_count, libab_ref* scope) {
|
|||
int main() {
|
||||
libab_result result;
|
||||
libab_ref scope;
|
||||
libab_ref test;
|
||||
libab ab;
|
||||
|
||||
if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) {
|
||||
|
@ -226,10 +227,12 @@ int main() {
|
|||
|
||||
result = register_functions(&ab);
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
result = libab_create_table(&scope, &ab.table);
|
||||
result = libab_create_table(&ab, &scope, &ab.table);
|
||||
}
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
loop(&ab, INTERACTIONS, &scope);
|
||||
libab_table_search_value(libab_ref_get(&scope), "test", &test);
|
||||
printf("%p\n", libab_ref_get(&test));
|
||||
libab_ref_free(&scope);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ libab_result _create_bool_value(libab* ab, int val, libab_ref* into) {
|
|||
new_bool = malloc(sizeof(*new_bool));
|
||||
if(new_bool) {
|
||||
*new_bool = val;
|
||||
result = libab_create_value_raw(into, new_bool, &type_bool);
|
||||
result = libab_create_value_raw(ab, into, new_bool, &type_bool);
|
||||
if(result != LIBAB_SUCCESS) {
|
||||
free(new_bool);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ libab_result libab_interpreter_init(libab_interpreter* intr, libab* ab) {
|
|||
libab_ref_null(&intr->value_false);
|
||||
|
||||
libab_ref_null(&unit_data);
|
||||
result = libab_create_value_ref(&intr->value_unit, &unit_data, &ab->type_unit);
|
||||
result = libab_create_value_ref(ab, &intr->value_unit, &unit_data, &ab->type_unit);
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(&intr->value_true);
|
||||
result = _create_bool_value(ab, 1, &intr->value_true);
|
||||
|
@ -75,7 +75,7 @@ libab_result _interpreter_create_num_val(struct interpreter_state* state,
|
|||
|
||||
if ((data = state->ab->impl.parse_num(from))) {
|
||||
libab_ref_free(into);
|
||||
result = libab_create_value_raw(into, data, &state->ab->type_num);
|
||||
result = libab_create_value_raw(state->ab, into, data, &state->ab->type_num);
|
||||
|
||||
if (result != LIBAB_SUCCESS) {
|
||||
((libab_parsetype*)libab_ref_get(&state->ab->type_num))
|
||||
|
@ -466,13 +466,14 @@ libab_result _interpreter_find_match(libab_function_list* function_values,
|
|||
* @param type the new type.
|
||||
* @param into the reference into which to store the new value.
|
||||
*/
|
||||
libab_result _interpreter_cast_param(libab_ref* param, libab_ref* type,
|
||||
libab_result _interpreter_cast_param(libab* ab, libab_ref* param,
|
||||
libab_ref* type,
|
||||
libab_ref_vec* into) {
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
libab_value* old_value = libab_ref_get(param);
|
||||
libab_ref new_value;
|
||||
|
||||
result = libab_create_value_ref(&new_value, &old_value->data, type);
|
||||
result = libab_create_value_ref(ab, &new_value, &old_value->data, type);
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
result = libab_ref_vec_insert(into, &new_value);
|
||||
}
|
||||
|
@ -488,7 +489,8 @@ libab_result _interpreter_cast_param(libab_ref* param, libab_ref* type,
|
|||
* @param into the pre-initialized vector to store the new values into.
|
||||
* @return the result of any allocations.
|
||||
*/
|
||||
libab_result _interpreter_cast_params(libab_ref_vec* params,
|
||||
libab_result _interpreter_cast_params(libab* ab,
|
||||
libab_ref_vec* params,
|
||||
libab_ref_vec* new_types,
|
||||
libab_ref_vec* into) {
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
|
@ -500,7 +502,7 @@ libab_result _interpreter_cast_params(libab_ref_vec* params,
|
|||
libab_ref_vec_index(params, index, &temp_param);
|
||||
libab_ref_vec_index(new_types, index, &temp_type);
|
||||
|
||||
result = _interpreter_cast_param(&temp_param, &temp_type, into);
|
||||
result = _interpreter_cast_param(ab, &temp_param, &temp_type, into);
|
||||
|
||||
libab_ref_free(&temp_param);
|
||||
libab_ref_free(&temp_type);
|
||||
|
@ -531,7 +533,7 @@ libab_result _interpreter_call_tree(struct interpreter_state* state,
|
|||
libab_ref param;
|
||||
libab_table* new_scope_raw;
|
||||
size_t i;
|
||||
libab_result result = libab_create_table(&new_scope, scope);
|
||||
libab_result result = libab_create_table(state->ab, &new_scope, scope);
|
||||
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
new_scope_raw = libab_ref_get(&new_scope);
|
||||
|
@ -581,22 +583,24 @@ libab_result _interpreter_call_behavior(struct interpreter_state* state,
|
|||
* @param function the function to copy.
|
||||
* @param into the reference to store the copy into.
|
||||
*/
|
||||
libab_result _interpreter_copy_function_basic(libab_ref* function,
|
||||
libab_result _interpreter_copy_function_basic(libab* ab,
|
||||
libab_ref* function,
|
||||
libab_ref* scope,
|
||||
libab_ref* into) {
|
||||
libab_function* func = libab_ref_get(function);
|
||||
void (*free_function)(void*) = function->count->free_func;
|
||||
return libab_create_function_behavior(into, free_function, &func->behavior, scope);
|
||||
return libab_create_function_behavior(ab, into, free_function, &func->behavior, scope);
|
||||
}
|
||||
|
||||
libab_result _interpreter_copy_function_with_params(libab_ref* function,
|
||||
libab_result _interpreter_copy_function_with_params(libab* ab,
|
||||
libab_ref* function,
|
||||
libab_ref_vec* params,
|
||||
libab_ref* scope,
|
||||
libab_ref* into) {
|
||||
int index = 0;
|
||||
libab_ref param;
|
||||
libab_function* func;
|
||||
libab_result result = _interpreter_copy_function_basic(function, scope, into);
|
||||
libab_result result = _interpreter_copy_function_basic(ab, function, scope, into);
|
||||
func = libab_ref_get(into);
|
||||
|
||||
for(; index < params->size && result == LIBAB_SUCCESS; index++) {
|
||||
|
@ -669,14 +673,14 @@ libab_result _interpreter_partially_apply(struct interpreter_state* state,
|
|||
|
||||
value = libab_ref_get(function);
|
||||
libab_ref_null(&new_type);
|
||||
result = _interpreter_copy_function_with_params(&value->data, params, scope, &new_function);
|
||||
result = _interpreter_copy_function_with_params(state->ab, &value->data, params, scope, &new_function);
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(&new_type);
|
||||
result = _interpreter_copy_type_offset(&value->type, 0, &new_type);
|
||||
}
|
||||
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
result = libab_create_value_ref(into, &new_function, &new_type);
|
||||
result = libab_create_value_ref(state->ab, into, &new_function, &new_type);
|
||||
} else {
|
||||
libab_ref_null(into);
|
||||
}
|
||||
|
@ -711,10 +715,11 @@ libab_result _interpreter_foreach_insert_param(const libab_ref* param,
|
|||
return result;
|
||||
}
|
||||
|
||||
libab_result _interpreter_create_scope(libab_ref* into,
|
||||
libab_result _interpreter_create_scope(libab* ab,
|
||||
libab_ref* into,
|
||||
libab_ref* parent_scope,
|
||||
libab_ref_trie* param_map) {
|
||||
libab_result result = libab_create_table(into, parent_scope);
|
||||
libab_result result = libab_create_table(ab, into, parent_scope);
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
result = libab_ref_trie_foreach(param_map, _interpreter_foreach_insert_param, into);
|
||||
|
||||
|
@ -750,7 +755,7 @@ libab_result _interpreter_perform_function_call(struct interpreter_state* state,
|
|||
function_type = libab_ref_get(&function_value->type);
|
||||
new_params = params->size - function->params.size;
|
||||
|
||||
result = _interpreter_create_scope(&new_scope, &function->scope, param_map);
|
||||
result = _interpreter_create_scope(state->ab, &new_scope, &function->scope, param_map);
|
||||
|
||||
if(result != LIBAB_SUCCESS) {
|
||||
libab_ref_null(into);
|
||||
|
@ -789,7 +794,7 @@ libab_result _interpreter_cast_and_perform_function_call(
|
|||
function = libab_ref_get(&function_value->data);
|
||||
result = libab_ref_vec_init_copy(&new_params, &function->params);
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
result = _interpreter_cast_params(params, new_types, &new_params);
|
||||
result = _interpreter_cast_params(state->ab, params, new_types, &new_params);
|
||||
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
result = _interpreter_perform_function_call(state, to_call,
|
||||
|
@ -1117,7 +1122,7 @@ libab_result _interpreter_create_function_value(
|
|||
|
||||
libab_ref_null(&type);
|
||||
libab_ref_null(into);
|
||||
result = libab_create_function_tree(&function, libab_free_function, tree, scope);
|
||||
result = libab_create_function_tree(state->ab, &function, libab_free_function, tree, scope);
|
||||
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(&type);
|
||||
|
@ -1126,7 +1131,7 @@ libab_result _interpreter_create_function_value(
|
|||
|
||||
if(result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(into);
|
||||
result = libab_create_value_ref(into, &function, &type);
|
||||
result = libab_create_value_ref(state->ab, into, &function, &type);
|
||||
}
|
||||
|
||||
if(result != LIBAB_SUCCESS) {
|
||||
|
@ -1175,7 +1180,7 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
|
|||
(mode == SCOPE_NORMAL && libab_tree_has_scope(tree->variant));
|
||||
|
||||
if (needs_scope) {
|
||||
result = libab_create_table(&new_scope, scope);
|
||||
result = libab_create_table(state->ab, &new_scope, scope);
|
||||
scope = &new_scope;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*),
|
|||
int interpreter_initialized = 0;
|
||||
libab_ref null_ref;
|
||||
libab_result result;
|
||||
libab_gc_list_init(&ab->containers);
|
||||
libab_ref_null(&null_ref);
|
||||
libab_ref_null(&ab->type_num);
|
||||
libab_ref_null(&ab->type_bool);
|
||||
|
@ -34,7 +35,7 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*),
|
|||
libab_ref_null(&ab->type_unit);
|
||||
|
||||
ab->impl.parse_num = parse_function;
|
||||
result = libab_create_table(&ab->table, &null_ref);
|
||||
result = libab_create_table(ab, &ab->table, &null_ref);
|
||||
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(&ab->type_num);
|
||||
|
@ -144,28 +145,29 @@ libab_result libab_register_operator_postfix(libab* ab, const char* op,
|
|||
return _register_operator(ab, op, OPERATOR_POSTFIX, 0, 0, function);
|
||||
}
|
||||
|
||||
libab_result _create_value_function_internal(libab_ref* into, libab_ref* type,
|
||||
libab_result _create_value_function_internal(libab* ab,
|
||||
libab_ref* into, libab_ref* type,
|
||||
libab_function_ptr func,
|
||||
libab_ref* scope) {
|
||||
libab_ref function_ref;
|
||||
libab_result result =
|
||||
libab_create_function_internal(&function_ref, libab_free_function, func, scope);
|
||||
libab_create_function_internal(ab, &function_ref, libab_free_function, func, scope);
|
||||
libab_ref_null(into);
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(into);
|
||||
result = libab_create_value_ref(into, &function_ref, type);
|
||||
result = libab_create_value_ref(ab, into, &function_ref, type);
|
||||
}
|
||||
libab_ref_free(&function_ref);
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result _create_value_function_list(libab_ref* into, libab_ref* type) {
|
||||
libab_result _create_value_function_list(libab* ab, libab_ref* into, libab_ref* type) {
|
||||
libab_ref list_ref;
|
||||
libab_result result = libab_create_function_list(&list_ref, type);
|
||||
libab_result result = libab_create_function_list(ab, &list_ref, type);
|
||||
libab_ref_null(into);
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
libab_ref_free(into);
|
||||
result = libab_create_value_ref(into, &list_ref, type);
|
||||
result = libab_create_value_ref(ab, into, &list_ref, type);
|
||||
}
|
||||
libab_ref_free(&list_ref);
|
||||
return result;
|
||||
|
@ -187,7 +189,7 @@ libab_result _libab_register_function_existing(libab* ab,
|
|||
} else if (old_type->data_u.base == &_basetype_function) {
|
||||
libab_ref new_list;
|
||||
result =
|
||||
_create_value_function_list(&new_list, &ab->type_function_list);
|
||||
_create_value_function_list(ab, &new_list, &ab->type_function_list);
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
libab_function_list* list =
|
||||
libab_ref_get(&((libab_value*)libab_ref_get(&new_list))->data);
|
||||
|
@ -232,7 +234,7 @@ libab_result libab_register_function(libab* ab, const char* name,
|
|||
libab_table_entry* existing_entry;
|
||||
libab_ref function_value;
|
||||
libab_result result =
|
||||
_create_value_function_internal(&function_value, type, func, &ab->table);
|
||||
_create_value_function_internal(ab, &function_value, type, func, &ab->table);
|
||||
|
||||
if (result == LIBAB_SUCCESS) {
|
||||
existing_entry = libab_table_search_filter(
|
||||
|
@ -516,6 +518,7 @@ libab_result libab_run_tree_scoped(libab* ab, libab_tree* tree, libab_ref* scope
|
|||
}
|
||||
|
||||
libab_result libab_free(libab* ab) {
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
libab_table_free(libab_ref_get(&ab->table));
|
||||
libab_ref_free(&ab->table);
|
||||
libab_ref_free(&ab->type_num);
|
||||
|
@ -524,5 +527,7 @@ libab_result libab_free(libab* ab) {
|
|||
libab_ref_free(&ab->type_unit);
|
||||
libab_parser_free(&ab->parser);
|
||||
libab_interpreter_free(&ab->intr);
|
||||
return libab_lexer_free(&ab->lexer);
|
||||
result = libab_lexer_free(&ab->lexer);
|
||||
libab_gc_run(&ab->containers);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@ libab_result libab_ref_new(libab_ref* ref, void* data,
|
|||
libab_result result = LIBAB_SUCCESS;
|
||||
ref->null = 0;
|
||||
ref->strong = 1;
|
||||
ref->data = data;
|
||||
if ((ref->count = malloc(sizeof(*(ref->count))))) {
|
||||
ref->count->data = data;
|
||||
ref->count->strong = ref->count->weak = 1;
|
||||
ref->count->free_func = free_func;
|
||||
ref->count->visit_children = NULL;
|
||||
ref->count->prev = NULL;
|
||||
ref->count->next = NULL;
|
||||
} else {
|
||||
result = LIBAB_MALLOC;
|
||||
}
|
||||
|
@ -23,10 +26,12 @@ void _libab_ref_changed(libab_ref* ref) {
|
|||
if (ref->count->strong == 0) {
|
||||
ref->count->strong--;
|
||||
if (ref->count->free_func) {
|
||||
ref->count->free_func(ref->data);
|
||||
ref->count->free_func(ref->count->data);
|
||||
}
|
||||
}
|
||||
if (ref->count->weak == 0) {
|
||||
if(ref->count->prev) ref->count->prev->next = ref->count->next;
|
||||
if(ref->count->next) ref->count->next->prev = ref->count->prev;
|
||||
free(ref->count);
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +72,7 @@ void libab_ref_data_free(void* data) { free(data); }
|
|||
void* libab_ref_get(const libab_ref* ref) {
|
||||
void* to_return = NULL;
|
||||
if (!ref->null && ref->count->strong > 0) {
|
||||
to_return = ref->data;
|
||||
to_return = ref->count->data;
|
||||
}
|
||||
return to_return;
|
||||
}
|
||||
|
|
16
src/refcount_internal.c
Normal file
16
src/refcount_internal.c
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "refcount_internal.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void libab_ref_count_changed(libab_ref_count* count) {
|
||||
if (count->strong == 0) {
|
||||
count->strong--;
|
||||
if (count->free_func) {
|
||||
count->free_func(count->data);
|
||||
}
|
||||
}
|
||||
if (count->weak == 0) {
|
||||
if(count->prev) count->prev->next = count->next;
|
||||
if(count->next) count->next->prev = count->prev;
|
||||
free(count);
|
||||
}
|
||||
}
|
67
src/util.c
67
src/util.c
|
@ -2,6 +2,7 @@
|
|||
#include "value.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "free_functions.h"
|
||||
|
||||
libab_result libab_convert_lex_result(liblex_result to_convert) {
|
||||
|
@ -186,7 +187,31 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
|
|||
return result;
|
||||
}
|
||||
|
||||
libab_result libab_create_table(libab_ref* into, libab_ref* parent) {
|
||||
void _gc_visit_table_entry(libab_table_entry* entry, libab_visitor_function_ptr visitor, void* data) {
|
||||
if (entry->variant == ENTRY_VALUE) {
|
||||
libab_gc_visit(&entry->data_u.value, visitor, data);
|
||||
}
|
||||
}
|
||||
|
||||
void _gc_visit_table_trie(libab_trie_node* parent, libab_visitor_function_ptr visitor, void* data) {
|
||||
ll_node* head;
|
||||
if(parent == NULL) return;
|
||||
head = parent->values.head;
|
||||
_gc_visit_table_trie(parent->child, visitor, data);
|
||||
_gc_visit_table_trie(parent->next, visitor, data);
|
||||
while(head != NULL) {
|
||||
_gc_visit_table_entry(head->data, visitor, data);
|
||||
head = head->next;
|
||||
}
|
||||
}
|
||||
|
||||
void _gc_visit_table_children(void* parent, libab_visitor_function_ptr visitor, void* data) {
|
||||
libab_table* table = parent;
|
||||
libab_gc_visit(&table->parent, visitor, data);
|
||||
_gc_visit_table_trie(table->trie.head, visitor, data);
|
||||
}
|
||||
|
||||
libab_result libab_create_table(libab* ab, libab_ref* into, libab_ref* parent) {
|
||||
libab_table* table;
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
if ((table = malloc(sizeof(*table)))) {
|
||||
|
@ -203,12 +228,19 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent) {
|
|||
|
||||
if (result != LIBAB_SUCCESS) {
|
||||
libab_ref_null(into);
|
||||
} else {
|
||||
libab_gc_add(into, _gc_visit_table_children, &ab->containers);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
|
||||
libab_ref* type) {
|
||||
void _gc_visit_value_children(void* val, libab_visitor_function_ptr visitor, void* data) {
|
||||
libab_value* value = val;
|
||||
libab_gc_visit(&value->data, visitor, data);
|
||||
}
|
||||
|
||||
libab_result libab_create_value_ref(libab* ab, libab_ref* into,
|
||||
libab_ref* data, libab_ref* type) {
|
||||
libab_value* value;
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
if ((value = malloc(sizeof(*value)))) {
|
||||
|
@ -224,12 +256,14 @@ libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
|
|||
|
||||
if (result != LIBAB_SUCCESS) {
|
||||
libab_ref_null(into);
|
||||
} else {
|
||||
libab_gc_add(into, _gc_visit_value_children, &ab->containers);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result libab_create_value_raw(libab_ref* into, void* data,
|
||||
libab_ref* type) {
|
||||
libab_result libab_create_value_raw(libab* ab, libab_ref* into,
|
||||
void* data, libab_ref* type) {
|
||||
libab_value* value;
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
|
||||
|
@ -249,12 +283,19 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
|
|||
if (result != LIBAB_SUCCESS) {
|
||||
libab_ref_null(into);
|
||||
free(value);
|
||||
} else {
|
||||
libab_gc_add(into, _gc_visit_value_children, &ab->containers);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result libab_create_function_internal(libab_ref* into,
|
||||
void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) {
|
||||
libab_function* func = function;
|
||||
libab_gc_visit(&func->scope, visitor, data);
|
||||
}
|
||||
|
||||
libab_result libab_create_function_internal(libab* ab, libab_ref* into,
|
||||
void (*free_function)(void*),
|
||||
libab_function_ptr fun,
|
||||
libab_ref* scope) {
|
||||
|
@ -277,12 +318,14 @@ libab_result libab_create_function_internal(libab_ref* into,
|
|||
if (result != LIBAB_SUCCESS) {
|
||||
libab_ref_null(into);
|
||||
free(new_function);
|
||||
} else {
|
||||
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result libab_create_function_tree(libab_ref* into,
|
||||
libab_result libab_create_function_tree(libab* ab, libab_ref* into,
|
||||
void (*free_function)(void*),
|
||||
libab_tree* tree,
|
||||
libab_ref* scope) {
|
||||
|
@ -305,12 +348,14 @@ libab_result libab_create_function_tree(libab_ref* into,
|
|||
if (result != LIBAB_SUCCESS) {
|
||||
libab_ref_null(into);
|
||||
free(new_function);
|
||||
} else {
|
||||
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result libab_create_function_behavior(libab_ref* into,
|
||||
libab_result libab_create_function_behavior(libab* ab, libab_ref* into,
|
||||
void (*free_function)(void*),
|
||||
libab_behavior* behavior,
|
||||
libab_ref* scope) {
|
||||
|
@ -333,12 +378,14 @@ libab_result libab_create_function_behavior(libab_ref* into,
|
|||
if(result != LIBAB_SUCCESS) {
|
||||
libab_ref_null(into);
|
||||
free(new_function);
|
||||
} else {
|
||||
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
libab_result libab_create_function_list(libab_ref* into, libab_ref* type) {
|
||||
libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* type) {
|
||||
libab_function_list* list;
|
||||
libab_result result = LIBAB_SUCCESS;
|
||||
|
||||
|
@ -360,6 +407,8 @@ libab_result libab_create_function_list(libab_ref* into, libab_ref* type) {
|
|||
if (result != LIBAB_SUCCESS) {
|
||||
libab_ref_null(into);
|
||||
free(list);
|
||||
} else {
|
||||
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
Loading…
Reference in New Issue
Block a user