Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06f17f491c | |||
| ca6075e8d5 | |||
| 4425b27b52 | |||
| 25dd70f040 | |||
| 5617484aff | |||
| b311c854ee | |||
| c4a7117704 | |||
| 899ac31210 | |||
| 01720914e0 | |||
| 8c9acafc93 | |||
| 37593abe40 | |||
| 0065fe5e65 | |||
| de0ad13785 | |||
| 3d0e4776fc | |||
| 3fc7f46680 | |||
| cf57c4a29a | |||
| 59b03d0a94 | |||
| ffcbab9d94 | |||
| 8847643c2e | |||
| 0b7b49d03d | |||
| 512d68000f |
74
README.md
Normal file
74
README.md
Normal 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.
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -232,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.
|
||||||
@@ -256,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, ...);
|
||||||
/**
|
/**
|
||||||
@@ -286,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, ...);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef LIBABACUS_REFCOUNT_INTERNAL_H
|
|
||||||
#define LIBABACUS_REFCOUNT_INTERNAL_H
|
|
||||||
|
|
||||||
#include "refcount.h"
|
|
||||||
|
|
||||||
void libab_ref_count_changed(libab_ref_count* count);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -103,6 +103,28 @@ libab_result libab_create_value_ref(libab* ab, libab_ref* into,
|
|||||||
*/
|
*/
|
||||||
libab_result libab_create_value_raw(libab* ab, libab_ref* into,
|
libab_result libab_create_value_raw(libab* ab, libab_ref* into,
|
||||||
void* data, 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.
|
||||||
@@ -187,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
|
||||||
|
|||||||
14
src/custom.c
14
src/custom.c
@@ -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) {
|
||||||
|
|||||||
1
src/gc.c
1
src/gc.c
@@ -3,7 +3,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include "refcount_internal.h"
|
|
||||||
|
|
||||||
void libab_gc_list_init(libab_gc_list* list) {
|
void libab_gc_list_init(libab_gc_list* list) {
|
||||||
memset(&list->head_sentinel, 0, sizeof(list->head_sentinel));
|
memset(&list->head_sentinel, 0, sizeof(list->head_sentinel));
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -216,7 +214,6 @@ libab_result loop(libab* ab, int interaction_count, libab_ref* scope) {
|
|||||||
int main() {
|
int main() {
|
||||||
libab_result result;
|
libab_result result;
|
||||||
libab_ref scope;
|
libab_ref scope;
|
||||||
libab_ref test;
|
|
||||||
libab ab;
|
libab ab;
|
||||||
|
|
||||||
if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) {
|
if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) {
|
||||||
@@ -230,8 +227,6 @@ int main() {
|
|||||||
}
|
}
|
||||||
if(result == LIBAB_SUCCESS) {
|
if(result == LIBAB_SUCCESS) {
|
||||||
loop(&ab, INTERACTIONS, &scope);
|
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);
|
libab_ref_free(&scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -623,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;
|
||||||
@@ -632,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(©_of->children, offset + index, &child_type_ref);
|
libab_ref_vec_index(©_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);
|
||||||
}
|
}
|
||||||
@@ -676,7 +675,7 @@ libab_result _interpreter_partially_apply(struct interpreter_state* state,
|
|||||||
result = _interpreter_copy_function_with_params(state->ab, &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) {
|
||||||
@@ -1225,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);
|
||||||
@@ -1298,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,
|
||||||
@@ -1323,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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,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;
|
||||||
@@ -161,92 +161,16 @@ libab_result _create_value_function_internal(libab* ab,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 _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(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 _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(ab, &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;
|
||||||
}
|
}
|
||||||
@@ -406,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;
|
||||||
|
|
||||||
@@ -442,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);
|
||||||
@@ -453,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;
|
||||||
@@ -465,7 +389,7 @@ libab_result libab_run_function(libab* ab, const char* function,
|
|||||||
result = _handle_va_params(ab, ¶ms, param_count, args);
|
result = _handle_va_params(ab, ¶ms, 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, ¶ms, into);
|
result = libab_interpreter_call_function(&ab->intr, &ab->table, function, ¶ms, into);
|
||||||
|
|
||||||
libab_ref_vec_free(¶ms);
|
libab_ref_vec_free(¶ms);
|
||||||
}
|
}
|
||||||
@@ -483,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);
|
||||||
@@ -493,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;
|
||||||
@@ -504,7 +428,7 @@ libab_result libab_run_function_scoped(libab* ab, const char* function, libab_re
|
|||||||
result = _handle_va_params(ab, ¶ms, param_count, args);
|
result = _handle_va_params(ab, ¶ms, 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, ¶ms, into);
|
result = libab_interpreter_call_function(&ab->intr, scope, function, ¶ms, into);
|
||||||
|
|
||||||
libab_ref_vec_free(¶ms);
|
libab_ref_vec_free(¶ms);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ||
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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(¶ms);
|
||||||
|
} else {
|
||||||
|
result = LIBAB_BAD_CALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
free_params = 1;
|
||||||
|
result = libab_run_tree_scoped(ab, left, scope, ¶m);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
result = libab_ref_vec_insert(¶ms, ¶m);
|
||||||
|
}
|
||||||
|
libab_ref_free(¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; index < right->children.size - 1 && result == LIBAB_SUCCESS; index++) {
|
||||||
|
result = libab_run_tree_scoped(ab, vec_index(&right->children, index),
|
||||||
|
scope, ¶m);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
result = libab_ref_vec_insert(¶ms, ¶m);
|
||||||
|
}
|
||||||
|
libab_ref_free(¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, ¶ms, into);
|
||||||
|
} else {
|
||||||
|
libab_ref_null(into);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(free_params) {
|
||||||
|
libab_ref_vec_free(¶ms);
|
||||||
|
}
|
||||||
|
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
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
139
src/util.c
139
src/util.c
@@ -290,9 +290,115 @@ libab_result libab_create_value_raw(libab* ab, libab_ref* into,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) {
|
||||||
|
size_t index = 0;
|
||||||
libab_function* func = function;
|
libab_function* func = function;
|
||||||
libab_gc_visit(&func->scope, visitor, data);
|
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,
|
libab_result libab_create_function_internal(libab* ab, libab_ref* into,
|
||||||
@@ -385,6 +491,15 @@ libab_result libab_create_function_behavior(libab* ab, libab_ref* into,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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_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;
|
||||||
@@ -408,7 +523,7 @@ libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* t
|
|||||||
libab_ref_null(into);
|
libab_ref_null(into);
|
||||||
free(list);
|
free(list);
|
||||||
} else {
|
} else {
|
||||||
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
|
libab_gc_add(into, _gc_visit_function_list_children, &ab->containers);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -471,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);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user