Compare commits

..

27 Commits

Author SHA1 Message Date
06f17f491c Move variable setting code into utilities. 2018-09-13 23:57:33 -07:00
ca6075e8d5 Add a new method call operator, and more.
The '.' operator now represents method calls. A function f: (a, b)->c
can be called as a.f(b), which is equivalent to f(a, b). Besides
this change, all reserved operators now have a negative precedence
(it's relative, remember?), and some function names were changed.
2018-09-13 17:05:39 -07:00
4425b27b52 Make overloading code a utility function and call from interpreter.
This fixes #10.
2018-09-13 16:09:04 -07:00
25dd70f040 Fix segmentation fault during type initialization. 2018-09-13 15:08:57 -07:00
5617484aff Make parsing function public.
libab already provides a _run_tree ... you can't run_tree if there's
no tree.
2018-09-12 14:43:43 -07:00
b311c854ee Fix segmentation fault on function parsing error. 2018-09-12 14:32:28 -07:00
c4a7117704 Ensure operator does not try to take ownership of string. 2018-08-22 17:45:45 -07:00
899ac31210 Add a README. 2018-08-20 00:00:02 -07:00
01720914e0 Fix bug in table lookups. 2018-08-18 17:30:33 -07:00
8c9acafc93 Fix bug in shunting yard implementation. 2018-08-17 19:10:48 -07:00
37593abe40 Fix GC bug in overloaded functions. 2018-08-14 18:51:00 -07:00
0065fe5e65 Add utility functions to create libab instances on the heap. 2018-08-12 00:46:37 -07:00
de0ad13785 Remove function call prints from interactive. 2018-08-11 22:42:36 -07:00
3d0e4776fc Fix bugs related to partial application types. 2018-08-11 22:26:11 -07:00
3fc7f46680 Increment tree refcount. 2018-08-11 21:19:02 -07:00
cf57c4a29a Remove deliberate memory leak.
It was used to test the GC.
2018-08-11 20:29:08 -07:00
59b03d0a94 Fix partial application memory leak. 2018-08-11 20:27:52 -07:00
ffcbab9d94 Remove unused files. 2018-08-11 20:11:32 -07:00
8847643c2e Merge branch 'gc' 2018-08-11 20:09:56 -07:00
76ea606099 Finish basic implementation of garbage collection. 2018-08-11 20:01:43 -07:00
f4ecb82c46 Intermediate commit before visitor refactor. 2018-08-11 18:22:18 -07:00
80e7c95915 Make small adjustments to GC functions. 2018-08-11 16:00:00 -07:00
f257d0b2de Remove freed refcount from any list it's part of. 2018-08-11 01:42:30 -07:00
9eae28928a Move GC code to separate source file. 2018-08-11 01:40:30 -07:00
ec2421e5d7 Begin working on a garbage collector. 2018-08-11 01:29:48 -07:00
0b7b49d03d Fix memory leak caused by not freeing type. 2018-08-11 00:42:15 -07:00
512d68000f Link math library for atan2 and atan 2018-08-11 00:41:39 -07:00
20 changed files with 705 additions and 183 deletions

View File

@@ -8,7 +8,7 @@ project(libabacus)
add_compile_options(-pedantic -Wall) 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(libabacus src/main.c)
add_executable(interactive src/interactive.c) add_executable(interactive src/interactive.c)
add_subdirectory(external/liblex) add_subdirectory(external/liblex)
@@ -20,4 +20,4 @@ target_include_directories(libabacus PUBLIC include)
target_link_libraries(abacus lex) target_link_libraries(abacus lex)
target_link_libraries(libabacus abacus) target_link_libraries(libabacus abacus)
target_link_libraries(interactive abacus) target_link_libraries(interactive abacus m)

74
README.md Normal file
View File

@@ -0,0 +1,74 @@
# libabacus
A math-centered programming language library.
## About
libabacus is effectively a stripped down, embeddable programming language.
It relies on the program it's embedded into to provide the standard library. In fact,
it doesn't even provide an underlying implementation for numbers - the client code
provides a means of convering a string into a number, and a way of freeing that value.
libabacus takes care of the rest. The features of libabacus are geared towards
calculators, so it does not provide higher-level abstractions like OOP.
## Syntax
libabacus has fairly simple syntax. A simple number expression is
```
42
```
If an operator `+` is registered with libabacus, then an expression using
that operator looks like
```
21+21
```
If two functions, `f` and `g` are registered with libabacus, where `f` takes
one argument and `g` takes two, then the syntax for calling these functions is
```
f(42)
g(21, 21)
```
Blocks are a way to combine a sequence of expressions into one. The value of a block
is the result of the last expression in that block. Expressions are delimited by the
`;` character. For example,
```
{ 3; 2; 1 }
```
evalutes to `1`. Blocks are the first bit of syntax we've seen that can evalute to
a value that isn't a number. For instance, the empty block, `{}`, does not
evaluate to a number. Instead, it evalutes to `()`. This is a value of the `unit` type,
which only has one possible value, `()`.
User-defined functions are supported by libabacus:
```
fun square(a: num): num { a*a }
```
Let's pick this apart. The first part of a function declaration is the `fun` keyword. The name
of the function is next, followed by the list of parameters that this function accepts. Parameters
are listed in the form `[name]:[type]`. The return type of the function must also be specified.
Lastly, the block used to evaluate the function is needed.
The block captures the scope in which the function was declared. For instance, in the following piece of code,
```
a = 0;
fun test(): num {
a = a + 1
}
```
`test` actually has access to `a`, and calling `test` many times will yield increasing values of a.
Although all parameters must specify a type, this type can be
arbitrary to allow for polymorphic functions. For instance, a function to apply another function to an argument
twice can be written as:
```
fun apply_twice(func: ('T)->'T, a: 'T): 'T {
func(a);
func(a)
}
```
## Integration
Everything in libabacus revolves around the `libab` struct. This struct is used to keep all the state related to the evaluation,
and also contains the garbage collector. It needs to be instantiated using the `libab_init` function.
```C
libab ab;
libab_init(&ab, parse_function, free_function);
```
Please see `interactive.c` for an example of a simple yet complete implementation.

View File

@@ -135,8 +135,9 @@ void libab_behavior_free(libab_behavior* behavior);
* @param associativity the associativity (left = -1, right = 1) of the * @param associativity the associativity (left = -1, right = 1) of the
* operator. * operator.
* @param function the function this operator represents. * @param function the function this operator represents.
* @result the result of the initialization.
*/ */
void libab_operator_init(libab_operator* op, libab_operator_variant variant, libab_result libab_operator_init(libab_operator* op, libab_operator_variant variant,
int precedence, int associativity, const char* function); int precedence, int associativity, const char* function);
/** /**
* Frees the given operator. * Frees the given operator.

56
include/gc.h Normal file
View 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
View 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

View File

@@ -70,11 +70,25 @@ libab_result libab_interpreter_run(libab_interpreter* intr, libab_tree* tree,
* @param into the reference to store the result into. * @param into the reference to store the result into.
* @return the result of the call. * @return the result of the call.
*/ */
libab_result libab_interpreter_run_function(libab_interpreter* intr, libab_result libab_interpreter_call_function(libab_interpreter* intr,
libab_ref* scope, libab_ref* scope,
const char* function, const char* function,
libab_ref_vec* params, libab_ref_vec* params,
libab_ref* into); libab_ref* into);
/**
* Calls a function value with the given parameters.
* @param intr the interpreter to use to call the function.
* @param scope the scope in which the function should be searched for.
* @param function the function to call.
* @param params the parameters to pass to the function.
* @param into the reference to store the result into.
* @return the result of the call.
*/
libab_result libab_interpreter_call_value(libab_interpreter* intr,
libab_ref* scope,
libab_ref* function,
libab_ref_vec* params,
libab_ref* into);
/** /**
* Gets the unit value from this interpreter. * Gets the unit value from this interpreter.
* @param intr the interpreter from which to get the unit value. * @param intr the interpreter from which to get the unit value.

View File

@@ -9,6 +9,7 @@
#include "parser.h" #include "parser.h"
#include "result.h" #include "result.h"
#include "table.h" #include "table.h"
#include "gc.h"
/** /**
* The main struct of libabacus, * The main struct of libabacus,
@@ -59,6 +60,12 @@ struct libab_s {
* The unit type instance. * The unit type instance.
*/ */
libab_ref type_unit; 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 * Internal; the number basetype. This cannot be a static
@@ -225,6 +232,13 @@ void libab_get_false_value(libab* ab, libab_ref* into);
*/ */
void libab_get_bool_value(libab* ab, int val, libab_ref* into); void libab_get_bool_value(libab* ab, int val, libab_ref* into);
/**
* Parses the given piece of code using the given libabacus instance.
* @param ab the instance to use to parse the code.
* @param string the source code to parse.
* @param into the value to store the newly parsed tree into.
*/
libab_result libab_parse(libab* ab, const char* string, libab_tree** into);
/** /**
* Executes the given string of code. * Executes the given string of code.
* @param ab the libabacus instance to use for executing code. * @param ab the libabacus instance to use for executing code.
@@ -249,7 +263,7 @@ libab_result libab_run_tree(libab* ab, libab_tree* tree, libab_ref* value);
* @param param_count the number of parameters given to this function. * @param param_count the number of parameters given to this function.
* @return the result of the call. * @return the result of the call.
*/ */
libab_result libab_run_function(libab* ab, const char* function, libab_result libab_call_function(libab* ab, const char* function,
libab_ref* into, libab_ref* into,
size_t param_count, ...); size_t param_count, ...);
/** /**
@@ -279,7 +293,7 @@ libab_result libab_run_tree_scoped(libab* ab, libab_tree* tree, libab_ref* scope
* @param param_count the number of parameters given to this function. * @param param_count the number of parameters given to this function.
* @return the result of the call. * @return the result of the call.
*/ */
libab_result libab_run_function_scoped(libab* ab, const char* function, libab_ref* scope, libab_result libab_call_function_scoped(libab* ab, const char* function, libab_ref* scope,
libab_ref* into, libab_ref* into,
size_t param_count, ...); size_t param_count, ...);

View File

@@ -2,6 +2,7 @@
#define LIBABACUS_REFCOUNT_H #define LIBABACUS_REFCOUNT_H
#include "result.h" #include "result.h"
#include "gc_functions.h"
/** /**
* A struct for holding * A struct for holding
@@ -10,6 +11,10 @@
* to free the value. * to free the value.
*/ */
struct libab_ref_count_s { struct libab_ref_count_s {
/**
* The value this reference holds.
*/
void* data;
/** /**
* The fucntion to free the value. * The fucntion to free the value.
* Can be NULL for no-op. * Can be NULL for no-op.
@@ -25,6 +30,26 @@ struct libab_ref_count_s {
* that still exist, even to a freed instance. * that still exist, even to a freed instance.
*/ */
int weak; 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. * of how many references are pointing to the value.
*/ */
struct libab_ref_count_s* count; struct libab_ref_count_s* count;
/**
* The value this reference holds.
*/
void* data;
}; };
typedef struct libab_ref_s libab_ref; typedef struct libab_ref_s libab_ref;

View File

@@ -7,6 +7,7 @@
#include "parsetype.h" #include "parsetype.h"
#include "result.h" #include "result.h"
#include "table.h" #include "table.h"
#include "libabacus.h"
#include <string.h> #include <string.h>
/** /**
@@ -78,11 +79,12 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
libab_ref* into, size_t n, ...); libab_ref* into, size_t n, ...);
/** /**
* Creates a new libab_table, and stores it into the given reference. * 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 into the reference to store the table into.
* @param parent the parent reference to store. * @param parent the parent reference to store.
* @return the result of the instantiation. * @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. * Allocates a new reference counted value with the given type and data.
* @param into the reference to store the allocated data into. * @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. * @param type the type to give the value.
* @return the result of necessary allocations. * @return the result of necessary allocations.
*/ */
libab_result libab_create_value_ref(libab_ref* into, libab_ref* data, libab_result libab_create_value_ref(libab* ab, libab_ref* into,
libab_ref* type); libab_ref* data, libab_ref* type);
/** /**
* Allocates a new reference counted value with the given type and data. * Allocates a new reference counted value with the given type and data.
* @param into the reference to store the allocated data into. * @param into the reference to store the allocated data into.
@@ -99,8 +101,30 @@ libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
* @param type the type to give the value. * @param type the type to give the value.
* @return the result of necessary allocations. * @return the result of necessary allocations.
*/ */
libab_result libab_create_value_raw(libab_ref* into, void* data, libab_result libab_create_value_raw(libab* ab, libab_ref* into,
libab_ref* type); void* data, libab_ref* type);
/**
* Overloads a function of the given name.
* @param table the table to insert the function into.
* @param name the name of the function.
* @param function the function to register.
* @return the result of the overload.
*/
libab_result libab_overload_function(libab* ab,
libab_table* table,
const char* name,
libab_ref* function);
/**
* Sets a value under the given name, overriding
* an existing value if it exists.
* @param table the table to store the value into.
* @param name the name of the variable.
* @param the value of the new variable.
* @return the result of setting the variable.
*/
libab_result libab_set_variable(libab_table* table,
const char* name,
libab_ref* value);
/** /**
* Allocates a function that uses internal code to run. * Allocates a function that uses internal code to run.
* @param into the reference into which to store the new function. * @param into the reference into which to store the new function.
@@ -109,7 +133,7 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
* @param scope the scope in which this function was declared. * @param scope the scope in which this function was declared.
* @return libab_result the result of any necessary allocations. * @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*), void (*free_function)(void*),
libab_function_ptr fun, libab_function_ptr fun,
libab_ref* scope); libab_ref* scope);
@@ -121,7 +145,7 @@ libab_result libab_create_function_internal(libab_ref* into,
* @param scope the scope in which this function was declared. * @param scope the scope in which this function was declared.
* @return libab_result the result of any necessary allocations. * @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*), void (*free_function)(void*),
libab_tree* tree, libab_tree* tree,
libab_ref* scope); libab_ref* scope);
@@ -133,7 +157,7 @@ libab_result libab_create_function_tree(libab_ref* into,
* @param scope the scope in which this function was declared. * @param scope the scope in which this function was declared.
* @return libab_result the result of any necessary allocations. * @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*), void (*free_function)(void*),
libab_behavior* behavior, libab_behavior* behavior,
libab_ref* scope); libab_ref* scope);
@@ -143,7 +167,7 @@ libab_result libab_create_function_behavior(libab_ref* into,
* @param the function_list type. * @param the function_list type.
* @return the result of the allocations. * @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. * Creates a new table entry that holds the given value.
* @param table the table to store the entry into. * @param table the table to store the entry into.
@@ -185,5 +209,19 @@ void* libab_unwrap_param(libab_ref_vec* vec, size_t index);
* @param buffer_size the size of the to buffer. * @param buffer_size the size of the to buffer.
*/ */
void libab_sanitize(char* to, const char* from, size_t buffer_size); void libab_sanitize(char* to, const char* from, size_t buffer_size);
/**
* Creates a new instance of libabacus allocated on the heap.
* @param into the pointer into which to store the newly allocated libab instance.
* @param parse_function the function used to parse numbers.
* @param free_function the function used to free parsed numbers.
*/
libab_result libab_create_instance(libab** into,
void* (*parse_function)(const char*),
void (*free_function)(void*));
/**
* Destroys the given libabacus instance allocated on the stack.
* @param into the reference to destroy.
*/
void libab_destroy_instance(libab* into);
#endif #endif

View File

@@ -1,4 +1,5 @@
#include "custom.h" #include "custom.h"
#include "util.h"
void libab_behavior_init_internal(libab_behavior* behavior, void libab_behavior_init_internal(libab_behavior* behavior,
libab_function_ptr func) { libab_function_ptr func) {
@@ -15,6 +16,9 @@ void libab_behavior_init_tree(libab_behavior* behavior, libab_tree* tree) {
void libab_behavior_copy(libab_behavior* behavior, libab_behavior* into) { void libab_behavior_copy(libab_behavior* behavior, libab_behavior* into) {
into->variant = behavior->variant; into->variant = behavior->variant;
into->data_u = behavior->data_u; into->data_u = behavior->data_u;
if(into->variant == BIMPL_TREE) {
into->data_u.tree->int_value++;
}
} }
void libab_behavior_free(libab_behavior* behavior) { void libab_behavior_free(libab_behavior* behavior) {
@@ -23,16 +27,20 @@ void libab_behavior_free(libab_behavior* behavior) {
} }
} }
void libab_operator_init(libab_operator* op, libab_operator_variant variant, libab_result libab_operator_init(libab_operator* op, libab_operator_variant variant,
int precedence, int associativity, const char* function) { int precedence, int associativity, const char* function) {
libab_result result = LIBAB_SUCCESS;
char* into;
op->variant = variant; op->variant = variant;
op->precedence = precedence; op->precedence = precedence;
op->associativity = associativity; op->associativity = associativity;
op->function = function; result = libab_copy_string(&into, function);
op->function = into;
return result;
} }
void libab_operator_free(libab_operator* op) { void libab_operator_free(libab_operator* op) {
free((char*) op->function);
} }
libab_result _function_init(libab_function* function, libab_ref* scope) { libab_result _function_init(libab_function* function, libab_ref* scope) {

102
src/gc.c Normal file
View File

@@ -0,0 +1,102 @@
#include "gc.h"
#include "refcount.h"
#include <stdlib.h>
#include <stdio.h>
#include <memory.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;
}
}

View File

@@ -30,7 +30,7 @@ libab_result create_double_value(libab* ab, double val, libab_ref* into) {
double* new_double = malloc(sizeof(*new_double)); double* new_double = malloc(sizeof(*new_double));
if(new_double) { if(new_double) {
*new_double = val; *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) { if(result != LIBAB_SUCCESS) {
free(new_double); free(new_double);
} }
@@ -71,13 +71,11 @@ FUNCTION(xor) {
} }
FUNCTION(atan) { FUNCTION(atan) {
printf("atan called\n");
double* val = libab_unwrap_param(params, 0); double* val = libab_unwrap_param(params, 0);
return create_double_value(ab, atan(*val), into); return create_double_value(ab, atan(*val), into);
} }
FUNCTION(atan2) { FUNCTION(atan2) {
printf("atan2 called\n");
double* left = libab_unwrap_param(params, 0); double* left = libab_unwrap_param(params, 0);
double* right = libab_unwrap_param(params, 1); double* right = libab_unwrap_param(params, 1);
return create_double_value(ab, atan2(*left, *right), into); return create_double_value(ab, atan2(*left, *right), into);
@@ -115,7 +113,6 @@ FUNCTION(print_unit) {
libab_result result = LIBAB_SUCCESS; \ libab_result result = LIBAB_SUCCESS; \
double right; \ double right; \
double left; \ double left; \
printf(#name " called\n"); \
left = *((double*)libab_unwrap_param(params, 0)); \ left = *((double*)libab_unwrap_param(params, 0)); \
right = *((double*)libab_unwrap_param(params, 1)); \ right = *((double*)libab_unwrap_param(params, 1)); \
create_double_value(ab, expression, into); \ create_double_value(ab, expression, into); \
@@ -176,6 +173,7 @@ libab_result register_functions(libab* ab) {
libab_ref_free(&trig_type); libab_ref_free(&trig_type);
libab_ref_free(&atan2_type); libab_ref_free(&atan2_type);
libab_ref_free(&difficult_type); libab_ref_free(&difficult_type);
libab_ref_free(&equals_num_type);
libab_ref_free(&print_num_type); libab_ref_free(&print_num_type);
libab_ref_free(&print_unit_type); libab_ref_free(&print_unit_type);
libab_ref_free(&print_bool_type); libab_ref_free(&print_bool_type);
@@ -200,7 +198,7 @@ libab_result loop(libab* ab, int interaction_count, libab_ref* scope) {
if (eval_result != LIBAB_SUCCESS) { if (eval_result != LIBAB_SUCCESS) {
printf("Invalid input (error code %d).\n", eval_result); printf("Invalid input (error code %d).\n", eval_result);
} else { } else {
result = libab_run_function_scoped(ab, "print", scope, &call_into, 1, &eval_into); result = libab_call_function_scoped(ab, "print", scope, &call_into, 1, &eval_into);
if(result == LIBAB_BAD_CALL) { if(result == LIBAB_BAD_CALL) {
printf("(?)\n"); printf("(?)\n");
result = LIBAB_SUCCESS; result = LIBAB_SUCCESS;
@@ -225,7 +223,7 @@ int main() {
result = register_functions(&ab); result = register_functions(&ab);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
result = libab_create_table(&scope, &ab.table); result = libab_create_table(&ab, &scope, &ab.table);
} }
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
loop(&ab, INTERACTIONS, &scope); loop(&ab, INTERACTIONS, &scope);

View File

@@ -13,7 +13,7 @@ libab_result _create_bool_value(libab* ab, int val, libab_ref* into) {
new_bool = malloc(sizeof(*new_bool)); new_bool = malloc(sizeof(*new_bool));
if(new_bool) { if(new_bool) {
*new_bool = val; *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) { if(result != LIBAB_SUCCESS) {
free(new_bool); 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(&intr->value_false);
libab_ref_null(&unit_data); 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) { if(result == LIBAB_SUCCESS) {
libab_ref_free(&intr->value_true); libab_ref_free(&intr->value_true);
result = _create_bool_value(ab, 1, &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))) { if ((data = state->ab->impl.parse_num(from))) {
libab_ref_free(into); 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) { if (result != LIBAB_SUCCESS) {
((libab_parsetype*)libab_ref_get(&state->ab->type_num)) ((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 type the new type.
* @param into the reference into which to store the new value. * @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_ref_vec* into) {
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
libab_value* old_value = libab_ref_get(param); libab_value* old_value = libab_ref_get(param);
libab_ref new_value; 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) { if (result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(into, &new_value); 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. * @param into the pre-initialized vector to store the new values into.
* @return the result of any allocations. * @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* new_types,
libab_ref_vec* into) { libab_ref_vec* into) {
libab_result result = LIBAB_SUCCESS; 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(params, index, &temp_param);
libab_ref_vec_index(new_types, index, &temp_type); 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_param);
libab_ref_free(&temp_type); libab_ref_free(&temp_type);
@@ -531,7 +533,7 @@ libab_result _interpreter_call_tree(struct interpreter_state* state,
libab_ref param; libab_ref param;
libab_table* new_scope_raw; libab_table* new_scope_raw;
size_t i; 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) { if(result == LIBAB_SUCCESS) {
new_scope_raw = libab_ref_get(&new_scope); 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 function the function to copy.
* @param into the reference to store the copy into. * @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* scope,
libab_ref* into) { libab_ref* into) {
libab_function* func = libab_ref_get(function); libab_function* func = libab_ref_get(function);
void (*free_function)(void*) = function->count->free_func; 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_vec* params,
libab_ref* scope, libab_ref* scope,
libab_ref* into) { libab_ref* into) {
int index = 0; int index = 0;
libab_ref param; libab_ref param;
libab_function* func; 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); func = libab_ref_get(into);
for(; index < params->size && result == LIBAB_SUCCESS; index++) { for(; index < params->size && result == LIBAB_SUCCESS; index++) {
@@ -619,7 +623,6 @@ libab_result _interpreter_copy_type_offset(libab_ref* type,
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
libab_parsetype* new_type; libab_parsetype* new_type;
libab_parsetype* copy_of = libab_ref_get(type); libab_parsetype* copy_of = libab_ref_get(type);
size_t index = 0;
if((new_type = malloc(sizeof(*new_type)))) { if((new_type = malloc(sizeof(*new_type)))) {
new_type->variant = copy_of->variant; new_type->variant = copy_of->variant;
new_type->data_u = copy_of->data_u; new_type->data_u = copy_of->data_u;
@@ -628,9 +631,9 @@ libab_result _interpreter_copy_type_offset(libab_ref* type,
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
libab_ref child_type_ref; libab_ref child_type_ref;
for(; index < copy_of->children.size - 1 - offset && for(; offset < copy_of->children.size &&
result == LIBAB_SUCCESS; index++) { result == LIBAB_SUCCESS; offset++) {
libab_ref_vec_index(&copy_of->children, offset + index, &child_type_ref); libab_ref_vec_index(&copy_of->children, offset, &child_type_ref);
result = libab_ref_vec_insert(&new_type->children, &child_type_ref); result = libab_ref_vec_insert(&new_type->children, &child_type_ref);
libab_ref_free(&child_type_ref); libab_ref_free(&child_type_ref);
} }
@@ -669,14 +672,14 @@ libab_result _interpreter_partially_apply(struct interpreter_state* state,
value = libab_ref_get(function); value = libab_ref_get(function);
libab_ref_null(&new_type); 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) { if(result == LIBAB_SUCCESS) {
libab_ref_free(&new_type); libab_ref_free(&new_type);
result = _interpreter_copy_type_offset(&value->type, 0, &new_type); result = _interpreter_copy_type_offset(&value->type, params->size, &new_type);
} }
if(result == LIBAB_SUCCESS) { 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 { } else {
libab_ref_null(into); libab_ref_null(into);
} }
@@ -711,10 +714,11 @@ libab_result _interpreter_foreach_insert_param(const libab_ref* param,
return result; 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* parent_scope,
libab_ref_trie* param_map) { 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) { if (result == LIBAB_SUCCESS) {
result = libab_ref_trie_foreach(param_map, _interpreter_foreach_insert_param, into); result = libab_ref_trie_foreach(param_map, _interpreter_foreach_insert_param, into);
@@ -750,7 +754,7 @@ libab_result _interpreter_perform_function_call(struct interpreter_state* state,
function_type = libab_ref_get(&function_value->type); function_type = libab_ref_get(&function_value->type);
new_params = params->size - function->params.size; 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) { if(result != LIBAB_SUCCESS) {
libab_ref_null(into); libab_ref_null(into);
@@ -789,7 +793,7 @@ libab_result _interpreter_cast_and_perform_function_call(
function = libab_ref_get(&function_value->data); function = libab_ref_get(&function_value->data);
result = libab_ref_vec_init_copy(&new_params, &function->params); result = libab_ref_vec_init_copy(&new_params, &function->params);
if (result == LIBAB_SUCCESS) { 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) { if (result == LIBAB_SUCCESS) {
result = _interpreter_perform_function_call(state, to_call, result = _interpreter_perform_function_call(state, to_call,
@@ -1117,7 +1121,7 @@ libab_result _interpreter_create_function_value(
libab_ref_null(&type); libab_ref_null(&type);
libab_ref_null(into); 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) { if(result == LIBAB_SUCCESS) {
libab_ref_free(&type); libab_ref_free(&type);
@@ -1126,7 +1130,7 @@ libab_result _interpreter_create_function_value(
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
libab_ref_free(into); 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) { if(result != LIBAB_SUCCESS) {
@@ -1175,7 +1179,7 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
(mode == SCOPE_NORMAL && libab_tree_has_scope(tree->variant)); (mode == SCOPE_NORMAL && libab_tree_has_scope(tree->variant));
if (needs_scope) { if (needs_scope) {
result = libab_create_table(&new_scope, scope); result = libab_create_table(state->ab, &new_scope, scope);
scope = &new_scope; scope = &new_scope;
} }
@@ -1220,7 +1224,7 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
_interpreter_create_function_value(state, tree, scope, &function); _interpreter_create_function_value(state, tree, scope, &function);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
result = libab_put_table_value(libab_ref_get(scope), result = libab_overload_function(state->ab, libab_ref_get(scope),
tree->string_value, &function); tree->string_value, &function);
if(result != LIBAB_SUCCESS) { if(result != LIBAB_SUCCESS) {
libab_ref_free(&function); libab_ref_free(&function);
@@ -1293,7 +1297,7 @@ libab_result libab_interpreter_run(libab_interpreter* intr, libab_tree* tree,
return result; return result;
} }
libab_result libab_interpreter_run_function(libab_interpreter* intr, libab_result libab_interpreter_call_function(libab_interpreter* intr,
libab_ref* scope, libab_ref* scope,
const char* function, const char* function,
libab_ref_vec* params, libab_ref_vec* params,
@@ -1318,6 +1322,21 @@ libab_result libab_interpreter_run_function(libab_interpreter* intr,
return result; return result;
} }
libab_result libab_interpreter_call_value(libab_interpreter* intr,
libab_ref* scope,
libab_ref* function,
libab_ref_vec* params,
libab_ref* into) {
struct interpreter_state state;
libab_result result = LIBAB_SUCCESS;
_interpreter_init(&state, intr, scope);
result = _interpreter_try_call(&state, function, params, into);
_interpreter_free(&state);
return result;
}
void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into) { void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into) {
libab_ref_copy(&intr->value_unit, into); libab_ref_copy(&intr->value_unit, into);
} }

View File

@@ -27,6 +27,7 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*),
int interpreter_initialized = 0; int interpreter_initialized = 0;
libab_ref null_ref; libab_ref null_ref;
libab_result result; libab_result result;
libab_gc_list_init(&ab->containers);
libab_ref_null(&null_ref); libab_ref_null(&null_ref);
libab_ref_null(&ab->type_num); libab_ref_null(&ab->type_num);
libab_ref_null(&ab->type_bool); 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); libab_ref_null(&ab->type_unit);
ab->impl.parse_num = parse_function; 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) { if (result == LIBAB_SUCCESS) {
libab_ref_free(&ab->type_num); libab_ref_free(&ab->type_num);
@@ -101,7 +102,7 @@ libab_result _register_operator(libab* ab, const char* op,
if ((new_entry = malloc(sizeof(*new_entry)))) { if ((new_entry = malloc(sizeof(*new_entry)))) {
new_entry->variant = ENTRY_OP; new_entry->variant = ENTRY_OP;
new_operator = &(new_entry->data_u.op); new_operator = &(new_entry->data_u.op);
libab_operator_init(new_operator, token_type, precedence, associativity, result = libab_operator_init(new_operator, token_type, precedence, associativity,
function); function);
} else { } else {
result = LIBAB_MALLOC; result = LIBAB_MALLOC;
@@ -144,107 +145,32 @@ libab_result libab_register_operator_postfix(libab* ab, const char* op,
return _register_operator(ab, op, OPERATOR_POSTFIX, 0, 0, function); 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_function_ptr func,
libab_ref* scope) { libab_ref* scope) {
libab_ref function_ref; libab_ref function_ref;
libab_result result = 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); libab_ref_null(into);
if (result == LIBAB_SUCCESS) { if (result == LIBAB_SUCCESS) {
libab_ref_free(into); 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); libab_ref_free(&function_ref);
return result; return result;
} }
libab_result _create_value_function_list(libab_ref* into, libab_ref* type) {
libab_ref list_ref;
libab_result result = libab_create_function_list(&list_ref, type);
libab_ref_null(into);
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_create_value_ref(into, &list_ref, type);
}
libab_ref_free(&list_ref);
return result;
}
libab_result _libab_register_function_existing(libab* ab,
libab_table_entry* entry,
libab_ref* function_val) {
libab_value* old_value;
libab_parsetype* old_type;
libab_result result = LIBAB_SUCCESS;
old_value = libab_ref_get(&entry->data_u.value);
old_type = libab_ref_get(&old_value->type);
if (old_type->data_u.base == &_basetype_function_list) {
libab_function_list* list = libab_ref_get(&old_value->data);
result = libab_function_list_insert(list, function_val);
} else if (old_type->data_u.base == &_basetype_function) {
libab_ref new_list;
result =
_create_value_function_list(&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);
result = libab_function_list_insert(list, &entry->data_u.value);
if (result == LIBAB_SUCCESS) {
result = libab_function_list_insert(list, function_val);
}
}
if (result == LIBAB_SUCCESS) {
libab_ref_swap(&entry->data_u.value, &new_list);
}
libab_ref_free(&new_list);
} else {
libab_ref_swap(&entry->data_u.value, function_val);
}
return result;
}
libab_result _libab_register_function_new(libab* ab, const char* name,
libab_ref* function_val) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* entry;
if ((entry = malloc(sizeof(*entry)))) {
entry->variant = ENTRY_VALUE;
libab_ref_copy(function_val, &entry->data_u.value);
result = libab_table_put(libab_ref_get(&ab->table), name, entry);
if (result != LIBAB_SUCCESS) {
libab_table_entry_free(entry);
free(entry);
}
} else {
result = LIBAB_MALLOC;
}
return result;
}
libab_result libab_register_function(libab* ab, const char* name, libab_result libab_register_function(libab* ab, const char* name,
libab_ref* type, libab_function_ptr func) { libab_ref* type, libab_function_ptr func) {
libab_table_entry* existing_entry;
libab_ref function_value; libab_ref function_value;
libab_result result = 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) { if (result == LIBAB_SUCCESS) {
existing_entry = libab_table_search_filter( libab_overload_function(ab, libab_ref_get(&ab->table), name, &function_value);
libab_ref_get(&ab->table), name, NULL, libab_table_compare_value);
if (existing_entry) {
result = _libab_register_function_existing(ab, existing_entry,
&function_value);
} else {
result = _libab_register_function_new(ab, name, &function_value);
} }
libab_ref_free(&function_value); libab_ref_free(&function_value);
}
return result; return result;
} }
@@ -404,7 +330,7 @@ void libab_get_bool_value(libab* ab, int val, libab_ref* into) {
val ? libab_get_true_value(ab, into) : libab_get_false_value(ab, into); val ? libab_get_true_value(ab, into) : libab_get_false_value(ab, into);
} }
libab_result _create_tree(libab* ab, const char* string, libab_tree** into) { libab_result libab_parse(libab* ab, const char* string, libab_tree** into) {
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
ll tokens; ll tokens;
@@ -440,7 +366,7 @@ libab_result libab_run(libab* ab, const char* string, libab_ref* value) {
libab_tree* root; libab_tree* root;
libab_ref_null(value); libab_ref_null(value);
result = _create_tree(ab, string, &root); result = libab_parse(ab, string, &root);
if (result == LIBAB_SUCCESS) { if (result == LIBAB_SUCCESS) {
libab_ref_free(value); libab_ref_free(value);
@@ -451,7 +377,7 @@ libab_result libab_run(libab* ab, const char* string, libab_ref* value) {
return result; return result;
} }
libab_result libab_run_function(libab* ab, const char* function, libab_result libab_call_function(libab* ab, const char* function,
libab_ref* into, libab_ref* into,
size_t param_count, ...) { size_t param_count, ...) {
libab_ref_vec params; libab_ref_vec params;
@@ -463,7 +389,7 @@ libab_result libab_run_function(libab* ab, const char* function,
result = _handle_va_params(ab, &params, param_count, args); result = _handle_va_params(ab, &params, param_count, args);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
libab_ref_free(into); libab_ref_free(into);
result = libab_interpreter_run_function(&ab->intr, &ab->table, function, &params, into); result = libab_interpreter_call_function(&ab->intr, &ab->table, function, &params, into);
libab_ref_vec_free(&params); libab_ref_vec_free(&params);
} }
@@ -481,7 +407,7 @@ libab_result libab_run_scoped(libab* ab, const char* string, libab_ref* scope, l
libab_tree* root; libab_tree* root;
libab_ref_null(into); libab_ref_null(into);
result = _create_tree(ab, string, &root); result = libab_parse(ab, string, &root);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
libab_ref_free(into); libab_ref_free(into);
result = libab_interpreter_run(&ab->intr, root, scope, SCOPE_NONE, into); result = libab_interpreter_run(&ab->intr, root, scope, SCOPE_NONE, into);
@@ -491,7 +417,7 @@ libab_result libab_run_scoped(libab* ab, const char* string, libab_ref* scope, l
return result; return result;
} }
libab_result libab_run_function_scoped(libab* ab, const char* function, libab_ref* scope, libab_ref* into, libab_result libab_call_function_scoped(libab* ab, const char* function, libab_ref* scope, libab_ref* into,
size_t param_count, ...) { size_t param_count, ...) {
libab_ref_vec params; libab_ref_vec params;
libab_result result; libab_result result;
@@ -502,7 +428,7 @@ libab_result libab_run_function_scoped(libab* ab, const char* function, libab_re
result = _handle_va_params(ab, &params, param_count, args); result = _handle_va_params(ab, &params, param_count, args);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
libab_ref_free(into); libab_ref_free(into);
result = libab_interpreter_run_function(&ab->intr, scope, function, &params, into); result = libab_interpreter_call_function(&ab->intr, scope, function, &params, into);
libab_ref_vec_free(&params); libab_ref_vec_free(&params);
} }
@@ -516,6 +442,7 @@ libab_result libab_run_tree_scoped(libab* ab, libab_tree* tree, libab_ref* scope
} }
libab_result libab_free(libab* ab) { libab_result libab_free(libab* ab) {
libab_result result = LIBAB_SUCCESS;
libab_table_free(libab_ref_get(&ab->table)); libab_table_free(libab_ref_get(&ab->table));
libab_ref_free(&ab->table); libab_ref_free(&ab->table);
libab_ref_free(&ab->type_num); libab_ref_free(&ab->type_num);
@@ -524,5 +451,7 @@ libab_result libab_free(libab* ab) {
libab_ref_free(&ab->type_unit); libab_ref_free(&ab->type_unit);
libab_parser_free(&ab->parser); libab_parser_free(&ab->parser);
libab_interpreter_free(&ab->intr); libab_interpreter_free(&ab->intr);
return libab_lexer_free(&ab->lexer); result = libab_lexer_free(&ab->lexer);
libab_gc_run(&ab->containers);
return result;
} }

View File

@@ -525,6 +525,7 @@ libab_result _parse_fun(struct parser_state* state, libab_tree** store_into) {
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
int is_parenth, is_comma; int is_parenth, is_comma;
libab_tree* temp; libab_tree* temp;
*store_into = NULL;
result = _parser_consume_type(state, TOKEN_KW_FUN); result = _parser_consume_type(state, TOKEN_KW_FUN);
if (result == LIBAB_SUCCESS) { if (result == LIBAB_SUCCESS) {
if (_parser_is_type(state, TOKEN_ID)) { if (_parser_is_type(state, TOKEN_ID)) {
@@ -1056,9 +1057,8 @@ libab_result _parse_expression(struct parser_state* state,
while (result == LIBAB_SUCCESS && op_stack.tail && while (result == LIBAB_SUCCESS && op_stack.tail &&
_parser_match_is_op(op_stack.tail->data)) { _parser_match_is_op(op_stack.tail->data)) {
libab_lexer_match* other_token = op_stack.tail->data; libab_lexer_match* other_token = op_stack.tail->data;
if(other_token->type == TOKEN_OP_INFIX) { if(other_token->type == TOKEN_OP_INFIX || other_token->type == TOKEN_OP_RESERVED) {
_parser_find_operator_infix(state, op_stack.tail->data, _parser_find_operator_infix(state, other_token, &other_operator);
&other_operator);
} }
if (other_token->type == TOKEN_OP_PREFIX || if (other_token->type == TOKEN_OP_PREFIX ||

View File

@@ -45,7 +45,7 @@ libab_result libab_parsetype_init_va(libab_parsetype* type,
result = libab_ref_vec_insert(&type->children, ref); result = libab_ref_vec_insert(&type->children, ref);
} }
if (free_vec) { if (result != LIBAB_SUCCESS && free_vec) {
libab_ref_vec_free(&type->children); libab_ref_vec_free(&type->children);
} }

View File

@@ -7,10 +7,13 @@ libab_result libab_ref_new(libab_ref* ref, void* data,
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
ref->null = 0; ref->null = 0;
ref->strong = 1; ref->strong = 1;
ref->data = data;
if ((ref->count = malloc(sizeof(*(ref->count))))) { if ((ref->count = malloc(sizeof(*(ref->count))))) {
ref->count->data = data;
ref->count->strong = ref->count->weak = 1; ref->count->strong = ref->count->weak = 1;
ref->count->free_func = free_func; ref->count->free_func = free_func;
ref->count->visit_children = NULL;
ref->count->prev = NULL;
ref->count->next = NULL;
} else { } else {
result = LIBAB_MALLOC; result = LIBAB_MALLOC;
} }
@@ -23,10 +26,12 @@ void _libab_ref_changed(libab_ref* ref) {
if (ref->count->strong == 0) { if (ref->count->strong == 0) {
ref->count->strong--; ref->count->strong--;
if (ref->count->free_func) { 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->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); 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* libab_ref_get(const libab_ref* ref) {
void* to_return = NULL; void* to_return = NULL;
if (!ref->null && ref->count->strong > 0) { if (!ref->null && ref->count->strong > 0) {
to_return = ref->data; to_return = ref->count->data;
} }
return to_return; return to_return;
} }

View File

@@ -4,18 +4,6 @@
#include "value.h" #include "value.h"
#include "libabacus.h" #include "libabacus.h"
libab_result _update_entry(libab_table* table, const char* name, libab_ref* value) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* value_entry = libab_table_search_entry_value(table, name);
if(value_entry) {
libab_ref_free(&value_entry->data_u.value);
libab_ref_copy(value, &value_entry->data_u.value);
} else {
result = libab_put_table_value(table, name, value);
}
return result;
}
libab_result _behavior_assign(libab* ab, libab_ref* scope, libab_result _behavior_assign(libab* ab, libab_ref* scope,
libab_tree* left, libab_tree* right, libab_tree* left, libab_tree* right,
libab_ref* into) { libab_ref* into) {
@@ -24,7 +12,7 @@ libab_result _behavior_assign(libab* ab, libab_ref* scope,
if(left->variant == TREE_ID) { if(left->variant == TREE_ID) {
result = libab_run_tree_scoped(ab, right, scope, into); result = libab_run_tree_scoped(ab, right, scope, into);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
result = _update_entry(libab_ref_get(scope), left->string_value, into); result = libab_set_variable(libab_ref_get(scope), left->string_value, into);
} }
if(result != LIBAB_SUCCESS) { if(result != LIBAB_SUCCESS) {
@@ -41,6 +29,61 @@ libab_result _behavior_assign(libab* ab, libab_ref* scope,
return result; return result;
} }
libab_result _behavior_method(libab* ab, libab_ref* scope,
libab_tree* left, libab_tree* right,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
libab_ref param;
libab_ref callee;
libab_ref_vec params;
int free_params = 0;
size_t index = 0;
libab_ref_null(&callee);
if(right->variant == TREE_CALL) {
result = libab_ref_vec_init(&params);
} else {
result = LIBAB_BAD_CALL;
}
if(result == LIBAB_SUCCESS) {
free_params = 1;
result = libab_run_tree_scoped(ab, left, scope, &param);
if(result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &param);
}
libab_ref_free(&param);
}
for(; index < right->children.size - 1 && result == LIBAB_SUCCESS; index++) {
result = libab_run_tree_scoped(ab, vec_index(&right->children, index),
scope, &param);
if(result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &param);
}
libab_ref_free(&param);
}
if(result == LIBAB_SUCCESS) {
libab_ref_free(&callee);
result = libab_run_tree_scoped(ab, vec_index(&right->children, right->children.size - 1),
scope, &callee);
}
if(result == LIBAB_SUCCESS) {
result = libab_interpreter_call_value(&ab->intr, scope, &callee, &params, into);
} else {
libab_ref_null(into);
}
if(free_params) {
libab_ref_vec_free(&params);
}
libab_ref_free(&callee);
return result;
}
libab_result _expect_boolean(libab* ab, libab_ref* scope, libab_result _expect_boolean(libab* ab, libab_ref* scope,
libab_tree* to_run, int* into) { libab_tree* to_run, int* into) {
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
@@ -103,19 +146,25 @@ libab_result _behavior_lor(libab* ab, libab_ref* scope,
static const libab_reserved_operator libab_reserved_operators[] = { static const libab_reserved_operator libab_reserved_operators[] = {
{ {
"=", /* Assignment */ "=", /* Assignment */
0, /* Lowest precedence */ -3, /* Lowest precedence */
1, /* Right associative, a = b = 6 should be a = (b = 6) */ 1, /* Right associative, a = b = 6 should be a = (b = 6) */
_behavior_assign _behavior_assign
}, },
{
".",
-2,
-1,
_behavior_method
},
{ {
"&&", /* Logical and */ "&&", /* Logical and */
0, /* Low precedence */ -1, /* Low precedence */
-1, /* Left associative. */ -1, /* Left associative. */
_behavior_land _behavior_land
}, },
{ {
"||", /* Logical or */ "||", /* Logical or */
0, /* Low precedence */ -1, /* Low precedence */
-1, /* Left associative. */ -1, /* Left associative. */
_behavior_lor _behavior_lor
}, },

View File

@@ -67,7 +67,7 @@ libab_table_entry* libab_table_search_entry_operator(libab_table* table,
} else if (type == OPERATOR_INFIX) { } else if (type == OPERATOR_INFIX) {
entry = libab_table_search_filter(table, string, NULL, entry = libab_table_search_filter(table, string, NULL,
libab_table_compare_op_infix); libab_table_compare_op_infix);
} else if (type == OPERATOR_PREFIX) { } else if (type == OPERATOR_POSTFIX) {
entry = libab_table_search_filter(table, string, NULL, entry = libab_table_search_filter(table, string, NULL,
libab_table_compare_op_postfix); libab_table_compare_op_postfix);
} }

View File

@@ -2,6 +2,7 @@
#include "value.h" #include "value.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "free_functions.h" #include "free_functions.h"
libab_result libab_convert_lex_result(liblex_result to_convert) { 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; 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_table* table;
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
if ((table = malloc(sizeof(*table)))) { if ((table = malloc(sizeof(*table)))) {
@@ -203,12 +228,19 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent) {
if (result != LIBAB_SUCCESS) { if (result != LIBAB_SUCCESS) {
libab_ref_null(into); libab_ref_null(into);
} else {
libab_gc_add(into, _gc_visit_table_children, &ab->containers);
} }
return result; return result;
} }
libab_result libab_create_value_ref(libab_ref* into, libab_ref* data, void _gc_visit_value_children(void* val, libab_visitor_function_ptr visitor, void* data) {
libab_ref* type) { 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_value* value;
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
if ((value = malloc(sizeof(*value)))) { 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) { if (result != LIBAB_SUCCESS) {
libab_ref_null(into); libab_ref_null(into);
} else {
libab_gc_add(into, _gc_visit_value_children, &ab->containers);
} }
return result; return result;
} }
libab_result libab_create_value_raw(libab_ref* into, void* data, libab_result libab_create_value_raw(libab* ab, libab_ref* into,
libab_ref* type) { void* data, libab_ref* type) {
libab_value* value; libab_value* value;
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
@@ -249,12 +283,125 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
if (result != LIBAB_SUCCESS) { if (result != LIBAB_SUCCESS) {
libab_ref_null(into); libab_ref_null(into);
free(value); free(value);
} else {
libab_gc_add(into, _gc_visit_value_children, &ab->containers);
} }
return result; return result;
} }
libab_result libab_create_function_internal(libab_ref* into, 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(ab, &list_ref, type);
libab_ref_null(into);
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_create_value_ref(ab, into, &list_ref, type);
}
libab_ref_free(&list_ref);
return result;
}
libab_result _register_function_existing(libab* ab,
libab_table_entry* entry,
libab_ref* function_val) {
libab_value* old_value;
libab_parsetype* old_type;
libab_result result = LIBAB_SUCCESS;
old_value = libab_ref_get(&entry->data_u.value);
old_type = libab_ref_get(&old_value->type);
if (old_type->data_u.base == libab_get_basetype_function_list(ab)) {
libab_function_list* list = libab_ref_get(&old_value->data);
result = libab_function_list_insert(list, function_val);
} else if (old_type->data_u.base == libab_get_basetype_function(ab)) {
libab_ref new_list;
result =
_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);
result = libab_function_list_insert(list, &entry->data_u.value);
if (result == LIBAB_SUCCESS) {
result = libab_function_list_insert(list, function_val);
}
}
if (result == LIBAB_SUCCESS) {
libab_ref_swap(&entry->data_u.value, &new_list);
}
libab_ref_free(&new_list);
} else {
libab_ref_swap(&entry->data_u.value, function_val);
}
return result;
}
libab_result _register_function_new(libab* ab, const char* name,
libab_ref* function_val) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* entry;
if ((entry = malloc(sizeof(*entry)))) {
entry->variant = ENTRY_VALUE;
libab_ref_copy(function_val, &entry->data_u.value);
result = libab_table_put(libab_ref_get(&ab->table), name, entry);
if (result != LIBAB_SUCCESS) {
libab_table_entry_free(entry);
free(entry);
}
} else {
result = LIBAB_MALLOC;
}
return result;
}
libab_result libab_overload_function(libab* ab,
libab_table* table,
const char* name,
libab_ref* function) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* existing_entry = libab_table_search_filter(
table, name, NULL, libab_table_compare_value);
if (existing_entry) {
result = _register_function_existing(ab, existing_entry,
function);
} else {
result = _register_function_new(ab, name, function);
}
return result;
}
libab_result libab_set_variable(libab_table* table,
const char* name,
libab_ref* value) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* value_entry = libab_table_search_entry_value(table, name);
if(value_entry) {
libab_ref_free(&value_entry->data_u.value);
libab_ref_copy(value, &value_entry->data_u.value);
} else {
result = libab_put_table_value(table, name, value);
}
return result;
}
void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) {
size_t index = 0;
libab_function* func = function;
libab_gc_visit(&func->scope, visitor, data);
for(; index < func->params.size; index++) {
libab_gc_visit(&func->params.data[index], visitor, data);
}
}
libab_result libab_create_function_internal(libab* ab, libab_ref* into,
void (*free_function)(void*), void (*free_function)(void*),
libab_function_ptr fun, libab_function_ptr fun,
libab_ref* scope) { libab_ref* scope) {
@@ -277,12 +424,14 @@ libab_result libab_create_function_internal(libab_ref* into,
if (result != LIBAB_SUCCESS) { if (result != LIBAB_SUCCESS) {
libab_ref_null(into); libab_ref_null(into);
free(new_function); free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
} }
return result; 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*), void (*free_function)(void*),
libab_tree* tree, libab_tree* tree,
libab_ref* scope) { libab_ref* scope) {
@@ -305,12 +454,14 @@ libab_result libab_create_function_tree(libab_ref* into,
if (result != LIBAB_SUCCESS) { if (result != LIBAB_SUCCESS) {
libab_ref_null(into); libab_ref_null(into);
free(new_function); free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
} }
return result; 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*), void (*free_function)(void*),
libab_behavior* behavior, libab_behavior* behavior,
libab_ref* scope) { libab_ref* scope) {
@@ -333,12 +484,23 @@ libab_result libab_create_function_behavior(libab_ref* into,
if(result != LIBAB_SUCCESS) { if(result != LIBAB_SUCCESS) {
libab_ref_null(into); libab_ref_null(into);
free(new_function); free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
} }
return result; return result;
} }
libab_result libab_create_function_list(libab_ref* into, libab_ref* type) {
void _gc_visit_function_list_children(void* list, libab_visitor_function_ptr visitor, void* data) {
size_t index = 0;
libab_function_list* func_list = list;
for(; index < func_list->functions.size; index++) {
libab_gc_visit(&func_list->functions.data[index], visitor, data);
}
}
libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* type) {
libab_function_list* list; libab_function_list* list;
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
@@ -360,6 +522,8 @@ libab_result libab_create_function_list(libab_ref* into, libab_ref* type) {
if (result != LIBAB_SUCCESS) { if (result != LIBAB_SUCCESS) {
libab_ref_null(into); libab_ref_null(into);
free(list); free(list);
} else {
libab_gc_add(into, _gc_visit_function_list_children, &ab->containers);
} }
return result; return result;
@@ -422,9 +586,29 @@ void libab_sanitize(char* to, const char* from, size_t buffer_size) {
while (*from && index < (buffer_size - 2)) { while (*from && index < (buffer_size - 2)) {
if (*from == '+' || *from == '*' || *from == '\\' || if (*from == '+' || *from == '*' || *from == '\\' ||
*from == '|' || *from == '[' || *from == ']' || *from == '(' || *from == '|' || *from == '[' || *from == ']' || *from == '(' ||
*from == ')') *from == ')' || *from == '.')
to[index++] = '\\'; to[index++] = '\\';
to[index++] = *(from++); to[index++] = *(from++);
} }
to[index] = '\0'; to[index] = '\0';
} }
libab_result libab_create_instance(libab** into,
void* (*parse_function)(const char*),
void (*free_function)(void*)) {
libab_result result = LIBAB_SUCCESS;
if((*into = malloc(sizeof(**into)))) {
result = libab_init(*into, parse_function, free_function);
if(result != LIBAB_SUCCESS) {
free(*into);
*into = NULL;
}
} else {
result = LIBAB_MALLOC;
}
return result;
}
void libab_destroy_instance(libab* into) {
libab_free(into);
free(into);
}