Compare commits
66 Commits
5492aa6f63
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 06f17f491c | |||
| ca6075e8d5 | |||
| 4425b27b52 | |||
| 25dd70f040 | |||
| 5617484aff | |||
| b311c854ee | |||
| c4a7117704 | |||
| 899ac31210 | |||
| 01720914e0 | |||
| 8c9acafc93 | |||
| 37593abe40 | |||
| 0065fe5e65 | |||
| de0ad13785 | |||
| 3d0e4776fc | |||
| 3fc7f46680 | |||
| cf57c4a29a | |||
| 59b03d0a94 | |||
| ffcbab9d94 | |||
| 8847643c2e | |||
| 76ea606099 | |||
| f4ecb82c46 | |||
| 80e7c95915 | |||
| f257d0b2de | |||
| 9eae28928a | |||
| ec2421e5d7 | |||
| 0b7b49d03d | |||
| 512d68000f | |||
| 71b6092654 | |||
| 20fb078ad2 | |||
| d7ef8e236d | |||
| 450d12dc43 | |||
| 0824dee594 | |||
| 0a21c7fdf7 | |||
| aebba42196 | |||
| 4a058384c1 | |||
| b0c2eb5a5e | |||
| 3c0648e473 | |||
| 8192d767f2 | |||
| 416686ca72 | |||
| fdca2a8ca7 | |||
| d0615d2c3e | |||
| b1ab168907 | |||
| 3b79b5751a | |||
| 7c8c547540 | |||
| 25f5d3469b | |||
| 6b331cc3c4 | |||
| 4540559097 | |||
| 48300cd86e | |||
| a5429ae2c8 | |||
| 03577269f2 | |||
| 7dfc55154e | |||
| 13ccea10e4 | |||
| 82747eae6a | |||
| 6822c97750 | |||
| 827dba9013 | |||
| f83b7d169c | |||
| b9b6a8ec4b | |||
| 05586069a7 | |||
| 22b738a4f0 | |||
| 88ec979ba5 | |||
| 763cfdd7a3 | |||
| 065554bcdf | |||
| 27c79d44f5 | |||
| 28f7cd1b30 | |||
| 695fbed235 | |||
| 1158b29c1b |
@@ -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)
|
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
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.
|
||||||
@@ -11,7 +11,7 @@ struct libab_s;
|
|||||||
* A function pointer that is called
|
* A function pointer that is called
|
||||||
* to execute a certain type of function.
|
* to execute a certain type of function.
|
||||||
*/
|
*/
|
||||||
typedef libab_result (*libab_function_ptr)(struct libab_s*, libab_ref_vec*, libab_ref*);
|
typedef libab_result (*libab_function_ptr)(struct libab_s*, libab_ref*, libab_ref_vec*, libab_ref*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The variant of the operator that
|
* The variant of the operator that
|
||||||
@@ -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.
|
||||||
|
|||||||
48
include/free_functions.h
Normal file
48
include/free_functions.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef LIBABACUS_FREE_FUNCTIONS_H
|
||||||
|
#define LIBABACUS_FREE_FUNCTIONS_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free functions. Because a lot of the reference
|
||||||
|
* counting operations require free functions,
|
||||||
|
* and redeclaring them in mutliple files makes no
|
||||||
|
* sense (also, it doesn't link :^) ), we
|
||||||
|
* put them all here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees a libab_function.
|
||||||
|
* @param func the function to free.
|
||||||
|
*/
|
||||||
|
void libab_free_function(void* func);
|
||||||
|
/**
|
||||||
|
* Frees a libab_function_list.
|
||||||
|
* @param func_list the function list to free.
|
||||||
|
*/
|
||||||
|
void libab_free_function_list(void* func_list);
|
||||||
|
/**
|
||||||
|
* Frees a unit. This is a no-op.
|
||||||
|
* @param unit the unit to free.
|
||||||
|
*/
|
||||||
|
void libab_free_unit(void* unit);
|
||||||
|
/**
|
||||||
|
* Frees a boolean value.
|
||||||
|
* @param b the bool to free.
|
||||||
|
*/
|
||||||
|
void libab_free_bool(void* b);
|
||||||
|
/**
|
||||||
|
* Frees a parsetype.
|
||||||
|
* @param parsetype the parsetype to free.
|
||||||
|
*/
|
||||||
|
void libab_free_parsetype(void* parsetype);
|
||||||
|
/**
|
||||||
|
* Frees a table.
|
||||||
|
* @param table the table to free.
|
||||||
|
*/
|
||||||
|
void libab_free_table(void* table);
|
||||||
|
/**
|
||||||
|
* Frees a value.
|
||||||
|
* @param value the value to free.
|
||||||
|
*/
|
||||||
|
void libab_free_value(void* value);
|
||||||
|
|
||||||
|
#endif
|
||||||
56
include/gc.h
Normal file
56
include/gc.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef LIBABACUS_GC_H
|
||||||
|
#define LIBABACUS_GC_H
|
||||||
|
|
||||||
|
#include "refcount.h"
|
||||||
|
#include "gc_functions.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct used to create an interface
|
||||||
|
* for a set of objects to be collected.
|
||||||
|
*/
|
||||||
|
struct libab_gc_list_s {
|
||||||
|
/**
|
||||||
|
* The head sentinel node.
|
||||||
|
*/
|
||||||
|
struct libab_ref_count_s head_sentinel;
|
||||||
|
/**
|
||||||
|
* The tail sentinel node.
|
||||||
|
*/
|
||||||
|
struct libab_ref_count_s tail_sentinel;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct libab_gc_list_s libab_gc_list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a garbage collection tracking list.
|
||||||
|
* @param list the list to initialize.
|
||||||
|
*/
|
||||||
|
void libab_gc_list_init(libab_gc_list* list);
|
||||||
|
/**
|
||||||
|
* Visits the children of the current node, applying the given function to them.
|
||||||
|
* @param ref the reference whose children to visit.
|
||||||
|
* @param visitor the function to call for each child.
|
||||||
|
* @param data the data to pass to the visitor.
|
||||||
|
*/
|
||||||
|
void libab_gc_visit_children(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data);
|
||||||
|
/**
|
||||||
|
* Applies the given visitor function to this reference.
|
||||||
|
*/
|
||||||
|
void libab_gc_visit(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data);
|
||||||
|
/**
|
||||||
|
* Adds the given reference to the given garbage collection list,
|
||||||
|
* and specifies a function used to reach its children.
|
||||||
|
* @param ref the reference whose children to visit.
|
||||||
|
* @param visit_children the function used to reach the chilren of this reference.
|
||||||
|
* @param list the list to which to add the reference.
|
||||||
|
*/
|
||||||
|
void libab_gc_add(struct libab_ref_s* ref,
|
||||||
|
libab_visit_function_ptr visit_children,
|
||||||
|
libab_gc_list* list);
|
||||||
|
/**
|
||||||
|
* Performs garbage collection on a given list of container objects/
|
||||||
|
* @param list the list to run collection on.
|
||||||
|
*/
|
||||||
|
void libab_gc_run(libab_gc_list* list);
|
||||||
|
|
||||||
|
#endif
|
||||||
10
include/gc_functions.h
Normal file
10
include/gc_functions.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef LIBABACUS_GC_FUNCTIONS_H
|
||||||
|
#define LIBABACUS_GC_FUNCTIONS_H
|
||||||
|
|
||||||
|
struct libab_ref_count_s;
|
||||||
|
struct libab_ref_s;
|
||||||
|
|
||||||
|
typedef void (*libab_visitor_function_ptr)(struct libab_ref_count_s* , void*);
|
||||||
|
typedef void (*libab_visit_function_ptr)(void*, libab_visitor_function_ptr, void*);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,6 +8,16 @@
|
|||||||
|
|
||||||
struct libab_s;
|
struct libab_s;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope moe used to determine how the interpreter handles
|
||||||
|
* scoping.
|
||||||
|
*/
|
||||||
|
enum libab_interpreter_scope_mode_e {
|
||||||
|
SCOPE_NORMAL,
|
||||||
|
SCOPE_FORCE,
|
||||||
|
SCOPE_NONE
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interpreter struct used to encapsulate
|
* The interpreter struct used to encapsulate
|
||||||
* any interpreter-specific data.
|
* any interpreter-specific data.
|
||||||
@@ -18,8 +28,17 @@ struct libab_interpreter_s {
|
|||||||
* The unit value, which doesn't need more than one instance.
|
* The unit value, which doesn't need more than one instance.
|
||||||
*/
|
*/
|
||||||
libab_ref value_unit;
|
libab_ref value_unit;
|
||||||
|
/**
|
||||||
|
* The "true" boolean value, which doesn't need more than one instance.
|
||||||
|
*/
|
||||||
|
libab_ref value_true;
|
||||||
|
/**
|
||||||
|
* The "false" boolean value, which doesn't need more than one instance.
|
||||||
|
*/
|
||||||
|
libab_ref value_false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum libab_interpreter_scope_mode_e libab_interpreter_scope_mode;
|
||||||
typedef struct libab_interpreter_s libab_interpreter;
|
typedef struct libab_interpreter_s libab_interpreter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,30 +51,62 @@ libab_result libab_interpreter_init(libab_interpreter* intr, struct libab_s* ab)
|
|||||||
* Uses the interpreter to run the given parse tree.
|
* Uses the interpreter to run the given parse tree.
|
||||||
* @param intr the interpreter to use to run the code.
|
* @param intr the interpreter to use to run the code.
|
||||||
* @param tree the tree to run.
|
* @param tree the tree to run.
|
||||||
|
* @param scope the parent scope to use for running the tree.
|
||||||
|
* @param mode the scope mode to use.
|
||||||
* @param into the reference into which the result of the execution will be
|
* @param into the reference into which the result of the execution will be
|
||||||
* stored.
|
* stored.
|
||||||
* @return the result of the execution.
|
* @return the result of the execution.
|
||||||
*/
|
*/
|
||||||
libab_result libab_interpreter_run(libab_interpreter* intr, libab_tree* tree,
|
libab_result libab_interpreter_run(libab_interpreter* intr, libab_tree* tree,
|
||||||
|
libab_ref* scope,
|
||||||
|
libab_interpreter_scope_mode mode,
|
||||||
libab_ref* into);
|
libab_ref* into);
|
||||||
/**
|
/**
|
||||||
* Calls a function with the given parameters.
|
* Calls a function with the given parameters.
|
||||||
* @param intr the interpreter to use to call the function.
|
* @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 function the function to call.
|
||||||
* @param params the parameters to pass to the function.
|
* @param params the parameters to pass to the function.
|
||||||
* @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,
|
||||||
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.
|
||||||
* @param into the reference into which to store the unit value.
|
* @param into the reference into which to store the unit value.
|
||||||
*/
|
*/
|
||||||
void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into);
|
void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into);
|
||||||
|
/**
|
||||||
|
* Gets the true value from this interpreter.
|
||||||
|
* @param intr the interpreter from which to get the true value.
|
||||||
|
* @param into the reference into which to store the true value.
|
||||||
|
*/
|
||||||
|
void libab_interpreter_true_value(libab_interpreter* intr, libab_ref* into);
|
||||||
|
/**
|
||||||
|
* Gets the false value from this interpreter.
|
||||||
|
* @param intr the interpreter from which to get the false value.
|
||||||
|
* @param into the reference into which to store the false value.
|
||||||
|
*/
|
||||||
|
void libab_interpreter_false_value(libab_interpreter* intr, libab_ref* into);
|
||||||
/**
|
/**
|
||||||
* Frees the given interpreter.
|
* Frees the given interpreter.
|
||||||
* @param intr the interpreter to free.
|
* @param intr the interpreter to free.
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ enum libab_lexer_token_e {
|
|||||||
TOKEN_OP_PREFIX,
|
TOKEN_OP_PREFIX,
|
||||||
TOKEN_OP_POSTFIX,
|
TOKEN_OP_POSTFIX,
|
||||||
TOKEN_OP_RESERVED,
|
TOKEN_OP_RESERVED,
|
||||||
|
TOKEN_KW_TRUE,
|
||||||
|
TOKEN_KW_FALSE,
|
||||||
TOKEN_KW_IF,
|
TOKEN_KW_IF,
|
||||||
TOKEN_KW_ELSE,
|
TOKEN_KW_ELSE,
|
||||||
TOKEN_KW_WHILE,
|
TOKEN_KW_WHILE,
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -47,6 +48,10 @@ struct libab_s {
|
|||||||
* The number type instance.
|
* The number type instance.
|
||||||
*/
|
*/
|
||||||
libab_ref type_num;
|
libab_ref type_num;
|
||||||
|
/**
|
||||||
|
* The boolean type instance.
|
||||||
|
*/
|
||||||
|
libab_ref type_bool;
|
||||||
/**
|
/**
|
||||||
* The function list type instance.
|
* The function list type instance.
|
||||||
*/
|
*/
|
||||||
@@ -55,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
|
||||||
@@ -144,6 +155,12 @@ libab_result libab_create_type(libab* ab, libab_ref* into, const char* type);
|
|||||||
* @return the num basetype.
|
* @return the num basetype.
|
||||||
*/
|
*/
|
||||||
libab_basetype* libab_get_basetype_num(libab* ab);
|
libab_basetype* libab_get_basetype_num(libab* ab);
|
||||||
|
/**
|
||||||
|
* Finds and returns the built-in libabacus boolean type.
|
||||||
|
* @param ab the ab instance for which to return a type.
|
||||||
|
* @return the boolean basetype.
|
||||||
|
*/
|
||||||
|
libab_basetype* libab_get_basetype_bool(libab* ab);
|
||||||
/**
|
/**
|
||||||
* Finds and returns the built-in libabacus function type.
|
* Finds and returns the built-in libabacus function type.
|
||||||
* @param ab the ab instance for which to return a type.
|
* @param ab the ab instance for which to return a type.
|
||||||
@@ -169,6 +186,12 @@ libab_basetype* libab_get_basetype_unit(libab* ab);
|
|||||||
* @param into the reference to store the type into.
|
* @param into the reference to store the type into.
|
||||||
*/
|
*/
|
||||||
void libab_get_type_num(libab* ab, libab_ref* into);
|
void libab_get_type_num(libab* ab, libab_ref* into);
|
||||||
|
/**
|
||||||
|
* Get the type of a boolean in this libabacus instance.
|
||||||
|
* @param ab the instance to get the type for.
|
||||||
|
* @param into the reference to store the type into.
|
||||||
|
*/
|
||||||
|
void libab_get_type_bool(libab* ab, libab_ref* into);
|
||||||
/**
|
/**
|
||||||
* Get the type of the function list in this libabacus instance.
|
* Get the type of the function list in this libabacus instance.
|
||||||
* @param ab the instance to get the type for.
|
* @param ab the instance to get the type for.
|
||||||
@@ -188,7 +211,34 @@ void libab_get_type_unit(libab* ab, libab_ref* into);
|
|||||||
* @param into the reference into which to store the unit value.
|
* @param into the reference into which to store the unit value.
|
||||||
*/
|
*/
|
||||||
void libab_get_unit_value(libab* ab, libab_ref* into);
|
void libab_get_unit_value(libab* ab, libab_ref* into);
|
||||||
|
/**
|
||||||
|
* Gets the true value form this libab instance.
|
||||||
|
* @param ab the instance to get the true value from.
|
||||||
|
* @param into the reference into which to store the true value.
|
||||||
|
*/
|
||||||
|
void libab_get_true_value(libab* ab, libab_ref* into);
|
||||||
|
/**
|
||||||
|
* Gets the false value form this libab instance.
|
||||||
|
* @param ab the instance to get the false value from.
|
||||||
|
* @param into the reference into which to store the false value.
|
||||||
|
*/
|
||||||
|
void libab_get_false_value(libab* ab, libab_ref* into);
|
||||||
|
/**
|
||||||
|
* Get the boolean value corresponding to val from this
|
||||||
|
* libab instance.
|
||||||
|
* @param ab the instance to get the value from.
|
||||||
|
* @param val the true or false value to represent.
|
||||||
|
* @param into the reference into which to store the value.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
@@ -197,15 +247,53 @@ void libab_get_unit_value(libab* ab, libab_ref* into);
|
|||||||
* @return the result of the computation.
|
* @return the result of the computation.
|
||||||
*/
|
*/
|
||||||
libab_result libab_run(libab* ab, const char* string, libab_ref* value);
|
libab_result libab_run(libab* ab, const char* string, libab_ref* value);
|
||||||
|
/**
|
||||||
|
* Runs an already-compiled tree.
|
||||||
|
* @param ab the libabacus instance to use for executing code.
|
||||||
|
* @param tree the tree the run.
|
||||||
|
* @param value the reference into which to store the output.
|
||||||
|
* @return the result of the computation.
|
||||||
|
*/
|
||||||
|
libab_result libab_run_tree(libab* ab, libab_tree* tree, libab_ref* value);
|
||||||
/**
|
/**
|
||||||
* Calls a function with the given name and parameters.
|
* Calls a function with the given name and parameters.
|
||||||
* @param ab the libabacus instance to use to call the function.
|
* @param ab the libabacus instance to use to call the function.
|
||||||
* @param function the name of the function to call.
|
* @param function the name of the function to call.
|
||||||
* @param iunto the reference into which to store the result.
|
* @param into the reference into which to store the result.
|
||||||
* @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,
|
||||||
|
size_t param_count, ...);
|
||||||
|
/**
|
||||||
|
* Calls a string in a given surrounding scope.
|
||||||
|
* @param ab the libabacus instance to use to call the function.
|
||||||
|
* @param strign the string to run.
|
||||||
|
* @param scope the scope to use for calling the string.
|
||||||
|
* @param value the reference into which to store the output of the computation.
|
||||||
|
* @return the result of the computation.
|
||||||
|
*/
|
||||||
|
libab_result libab_run_scoped(libab* ab, const char* string, libab_ref* scope, libab_ref* value);
|
||||||
|
/**
|
||||||
|
* Calls a tree in a given scope.
|
||||||
|
* @param ab the libabacus instance to use to call the tree.
|
||||||
|
* @param tree the tree to call.
|
||||||
|
* @param scope the scope to use for the call.
|
||||||
|
* @param value the reference into which to store the output.
|
||||||
|
* @return the result of the call.
|
||||||
|
*/
|
||||||
|
libab_result libab_run_tree_scoped(libab* ab, libab_tree* tree, libab_ref* scope, libab_ref* value);
|
||||||
|
/**
|
||||||
|
* Calls a function with the given name and parameters using a given scope.
|
||||||
|
* @param ab the libabacus instance to use to call the function.
|
||||||
|
* @param function the name of the function to call.
|
||||||
|
* @param scope the scope in which to perform the call.
|
||||||
|
* @param into the reference into which to store the result.
|
||||||
|
* @param param_count the number of parameters given to this function.
|
||||||
|
* @return the result of the call.
|
||||||
|
*/
|
||||||
|
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, ...);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "refcount.h"
|
#include "refcount.h"
|
||||||
#include "result.h"
|
#include "result.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node in the trie.
|
* A node in the trie.
|
||||||
@@ -75,6 +76,16 @@ libab_result libab_ref_trie_put(libab_ref_trie* trie, const char* key,
|
|||||||
*/
|
*/
|
||||||
void libab_ref_trie_get(const libab_ref_trie* trie, const char* key,
|
void libab_ref_trie_get(const libab_ref_trie* trie, const char* key,
|
||||||
libab_ref* into);
|
libab_ref* into);
|
||||||
|
/**
|
||||||
|
* Calls the given function on every element in the reference-counted
|
||||||
|
* tree.
|
||||||
|
* @param trie the trie to run the operation on.
|
||||||
|
* @param func the function to call.
|
||||||
|
* return the result of the functions, and any necessary allocations.
|
||||||
|
*/
|
||||||
|
libab_result libab_ref_trie_foreach(const libab_ref_trie* trie,
|
||||||
|
libab_result (*func)(const libab_ref*, const char*, va_list),
|
||||||
|
...);
|
||||||
/**
|
/**
|
||||||
* Releases the trie, decrementing the refcounts of all
|
* Releases the trie, decrementing the refcounts of all
|
||||||
* the values stored inside.
|
* the values stored inside.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ struct libab_reserved_operator_s {
|
|||||||
* The associativity of this operator.
|
* The associativity of this operator.
|
||||||
*/
|
*/
|
||||||
int associativity;
|
int associativity;
|
||||||
|
/**
|
||||||
|
* The function this operator performs.
|
||||||
|
*/
|
||||||
|
libab_result (*function)(libab*, libab_ref*, libab_tree*,
|
||||||
|
libab_tree*, libab_ref*);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct libab_reserved_operator_s libab_reserved_operator;
|
typedef struct libab_reserved_operator_s libab_reserved_operator;
|
||||||
|
|||||||
@@ -94,6 +94,17 @@ libab_table_entry* libab_table_search(libab_table* table, const char* string);
|
|||||||
*/
|
*/
|
||||||
libab_operator* libab_table_search_operator(libab_table* table,
|
libab_operator* libab_table_search_operator(libab_table* table,
|
||||||
const char* string, int type);
|
const char* string, int type);
|
||||||
|
/**
|
||||||
|
* Searches for a given string in the table,
|
||||||
|
* returning the entry that holds it only if it is an operator.
|
||||||
|
* @param table the table to search.
|
||||||
|
* @param string the string to search for.
|
||||||
|
* @param type the type of operator to search for (infix, prefix, postfix)
|
||||||
|
* @return the entry, or NULL if it was not found.
|
||||||
|
*/
|
||||||
|
libab_table_entry* libab_table_search_entry_operator(libab_table* table,
|
||||||
|
const char* string,
|
||||||
|
int type);
|
||||||
/**
|
/**
|
||||||
* Searches for the given basetype in the table, returning a value
|
* Searches for the given basetype in the table, returning a value
|
||||||
* only if it's a basetype.
|
* only if it's a basetype.
|
||||||
@@ -103,6 +114,15 @@ libab_operator* libab_table_search_operator(libab_table* table,
|
|||||||
*/
|
*/
|
||||||
libab_basetype* libab_table_search_basetype(libab_table* table,
|
libab_basetype* libab_table_search_basetype(libab_table* table,
|
||||||
const char* string);
|
const char* string);
|
||||||
|
/**
|
||||||
|
* Searches for the given basetype in the table, returning a table
|
||||||
|
* entry only if it holds a basetype.
|
||||||
|
* @param table to table to search.
|
||||||
|
* @param string the string to search for.
|
||||||
|
* @return the entry holding the basetype, or NULL if it was not found.
|
||||||
|
*/
|
||||||
|
libab_table_entry* libab_table_search_entry_basetype(libab_table* table,
|
||||||
|
const char* string);
|
||||||
/**
|
/**
|
||||||
* Searches for the given value in the table.
|
* Searches for the given value in the table.
|
||||||
* @param table the table to search.
|
* @param table the table to search.
|
||||||
@@ -112,13 +132,30 @@ libab_basetype* libab_table_search_basetype(libab_table* table,
|
|||||||
void libab_table_search_value(libab_table* table, const char* string,
|
void libab_table_search_value(libab_table* table, const char* string,
|
||||||
libab_ref* ref);
|
libab_ref* ref);
|
||||||
/**
|
/**
|
||||||
* Searches for the given type parameter in the talb.e
|
* Searches for a value with the given name in the table,
|
||||||
|
* and returns an entry that holds it.
|
||||||
|
* @param table the table to search.
|
||||||
|
* @param string the tabe entry key.
|
||||||
|
* @return the table entry holding the value, or NULL if it was not found.
|
||||||
|
*/
|
||||||
|
libab_table_entry* libab_table_search_entry_value(libab_table* table,
|
||||||
|
const char* string);
|
||||||
|
/**
|
||||||
|
* Searches for the given type parameter in the table.
|
||||||
* @param table the table to search in.
|
* @param table the table to search in.
|
||||||
* @param string the key ot search for.
|
* @param string the key to search for.
|
||||||
* @param ref the reference to store the type into.
|
* @param ref the reference to store the type into.
|
||||||
*/
|
*/
|
||||||
void libab_table_search_type_param(libab_table* table, const char* string,
|
void libab_table_search_type_param(libab_table* table, const char* string,
|
||||||
libab_ref* ref);
|
libab_ref* ref);
|
||||||
|
/**
|
||||||
|
* Searches for the given type parameter in the table.
|
||||||
|
* @param table the table to search in.
|
||||||
|
* @param string the key to search for.
|
||||||
|
* @return the table entry holding the type parameter, or NULL.
|
||||||
|
*/
|
||||||
|
libab_table_entry* libab_table_search_entry_type_param(libab_table* table,
|
||||||
|
const char* string);
|
||||||
/**
|
/**
|
||||||
* Stores the given entry in the table under the given key.
|
* Stores the given entry in the table under the given key.
|
||||||
* @param table the table to store the entry into.
|
* @param table the table to store the entry into.
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ enum libab_tree_variant_e {
|
|||||||
TREE_POSTFIX_OP,
|
TREE_POSTFIX_OP,
|
||||||
TREE_BLOCK,
|
TREE_BLOCK,
|
||||||
TREE_VOID,
|
TREE_VOID,
|
||||||
|
TREE_TRUE,
|
||||||
|
TREE_FALSE,
|
||||||
TREE_IF,
|
TREE_IF,
|
||||||
TREE_WHILE,
|
TREE_WHILE,
|
||||||
TREE_DOWHILE,
|
TREE_DOWHILE,
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,8 +56,18 @@ libab_result libab_copy_string(char** destination, const char* source);
|
|||||||
* @param to_resolve the parsetype to resolve.
|
* @param to_resolve the parsetype to resolve.
|
||||||
* @param scope the scope to use for resolving the type info.
|
* @param scope the scope to use for resolving the type info.
|
||||||
*/
|
*/
|
||||||
libab_result libab_resolve_parsetype(libab_parsetype* to_resolve,
|
libab_result libab_resolve_parsetype_inplace(libab_parsetype* to_resolve,
|
||||||
libab_table* scope);
|
libab_table* scope);
|
||||||
|
/**
|
||||||
|
* Resolves the given parsetype, looking through the scope to find
|
||||||
|
* all referenced base types, and creates a copy with these basetypes.
|
||||||
|
* @param to_resolve the parsetype to resolve.
|
||||||
|
* @param scope the scope to use for resolving the type info.
|
||||||
|
* @return the result of the operation.
|
||||||
|
*/
|
||||||
|
libab_result libab_resolve_parsetype_copy(libab_parsetype* to_resolve,
|
||||||
|
libab_table* scope,
|
||||||
|
libab_ref* into);
|
||||||
/**
|
/**
|
||||||
* Creates a new type instance, and stores it into the given reference.
|
* Creates a new type instance, and stores it into the given reference.
|
||||||
* @param to_instantiate the basetype to instantiate.
|
* @param to_instantiate the basetype to instantiate.
|
||||||
@@ -68,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.
|
||||||
@@ -80,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.
|
||||||
@@ -89,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.
|
||||||
@@ -99,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);
|
||||||
@@ -111,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);
|
||||||
@@ -123,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);
|
||||||
@@ -133,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.
|
||||||
@@ -143,6 +177,13 @@ libab_result libab_create_function_list(libab_ref* into, libab_ref* type);
|
|||||||
*/
|
*/
|
||||||
libab_result libab_put_table_value(libab_table* table, const char* key,
|
libab_result libab_put_table_value(libab_table* table, const char* key,
|
||||||
libab_ref* value);
|
libab_ref* value);
|
||||||
|
/**
|
||||||
|
* Gets the basetype of a parsetype.
|
||||||
|
* @param type the parsetype to get the basetype of.
|
||||||
|
* @param scope the scope to use for searches.
|
||||||
|
* @return the basetype.
|
||||||
|
*/
|
||||||
|
libab_basetype* libab_get_basetype(libab_parsetype* type, libab_table* scope);
|
||||||
/**
|
/**
|
||||||
* Returns the data stored in the given reference to a libab_value.
|
* Returns the data stored in the given reference to a libab_value.
|
||||||
* This is not the same as libab_ref_get: libab_ref_get will return directly
|
* This is not the same as libab_ref_get: libab_ref_get will return directly
|
||||||
@@ -161,5 +202,26 @@ void* libab_unwrap_value(libab_ref* ref);
|
|||||||
* @return the value at the given index.
|
* @return the value at the given index.
|
||||||
*/
|
*/
|
||||||
void* libab_unwrap_param(libab_ref_vec* vec, size_t index);
|
void* libab_unwrap_param(libab_ref_vec* vec, size_t index);
|
||||||
|
/**
|
||||||
|
* Sanitizes a string to avoid liblex compilation errors.
|
||||||
|
* @param to the buffer to store the sanitized string to.
|
||||||
|
* @param from the string to sanitize.
|
||||||
|
* @param buffer_size the size of the to buffer.
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
|||||||
34
src/free_functions.c
Normal file
34
src/free_functions.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include "free_functions.h"
|
||||||
|
#include "custom.h"
|
||||||
|
#include "function_list.h"
|
||||||
|
#include "parsetype.h"
|
||||||
|
#include "table.h"
|
||||||
|
#include "value.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void libab_free_function(void* func) {
|
||||||
|
libab_function_free(func);
|
||||||
|
free(func);
|
||||||
|
}
|
||||||
|
void libab_free_function_list(void* function_list) {
|
||||||
|
libab_function_list_free(function_list);
|
||||||
|
free(function_list);
|
||||||
|
}
|
||||||
|
void libab_free_unit(void* unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
void libab_free_bool(void* b) {
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
void libab_free_parsetype(void* parsetype) {
|
||||||
|
libab_parsetype_free(parsetype);
|
||||||
|
free(parsetype);
|
||||||
|
}
|
||||||
|
void libab_free_table(void* table) {
|
||||||
|
libab_table_free(table);
|
||||||
|
free(table);
|
||||||
|
}
|
||||||
|
void libab_free_value(void* value) {
|
||||||
|
libab_value_free(value);
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
102
src/gc.c
Normal file
102
src/gc.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,10 @@
|
|||||||
#define TRY(expression) \
|
#define TRY(expression) \
|
||||||
if (result == LIBAB_SUCCESS) \
|
if (result == LIBAB_SUCCESS) \
|
||||||
result = expression;
|
result = expression;
|
||||||
|
#define FUNCTION(name) \
|
||||||
|
libab_result function_##name (libab* ab, libab_ref* scope, \
|
||||||
|
libab_ref_vec* params, libab_ref* into)
|
||||||
|
|
||||||
#define INTERACTIONS 5
|
#define INTERACTIONS 5
|
||||||
|
|
||||||
void* impl_parse(const char* string) {
|
void* impl_parse(const char* string) {
|
||||||
@@ -26,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);
|
||||||
}
|
}
|
||||||
@@ -38,38 +42,77 @@ libab_result create_double_value(libab* ab, double val, libab_ref* into) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_result function_atan(libab* ab, libab_ref_vec* params, libab_ref* into) {
|
|
||||||
printf("atan called\n");
|
FUNCTION(not) {
|
||||||
|
int* left = libab_unwrap_param(params, 0);
|
||||||
|
libab_get_bool_value(ab, !(*left), into);
|
||||||
|
return LIBAB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION(and) {
|
||||||
|
int* left = libab_unwrap_param(params, 0);
|
||||||
|
int* right = libab_unwrap_param(params, 1);
|
||||||
|
libab_get_bool_value(ab, *left & *right, into);
|
||||||
|
return LIBAB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION(or) {
|
||||||
|
int* left = libab_unwrap_param(params, 0);
|
||||||
|
int* right = libab_unwrap_param(params, 1);
|
||||||
|
libab_get_bool_value(ab, *left | *right, into);
|
||||||
|
return LIBAB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION(xor) {
|
||||||
|
int* left = libab_unwrap_param(params, 0);
|
||||||
|
int* right = libab_unwrap_param(params, 1);
|
||||||
|
libab_get_bool_value(ab, *left ^ *right, into);
|
||||||
|
return LIBAB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION(atan) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_result function_atan2(libab* ab, libab_ref_vec* params, libab_ref* into) {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_result function_print_num(libab* ab, libab_ref_vec* params, libab_ref* into) {
|
FUNCTION(equals_num) {
|
||||||
|
double* left = libab_unwrap_param(params, 0);
|
||||||
|
double* right = libab_unwrap_param(params, 1);
|
||||||
|
libab_get_bool_value(ab, *left == *right, into);
|
||||||
|
return LIBAB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION(print_num) {
|
||||||
double* param = libab_unwrap_param(params, 0);
|
double* param = libab_unwrap_param(params, 0);
|
||||||
printf("%f\n", *param);
|
printf("%f\n", *param);
|
||||||
libab_get_unit_value(ab, into);
|
libab_get_unit_value(ab, into);
|
||||||
return LIBAB_SUCCESS;
|
return LIBAB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_result function_print_unit(libab* ab, libab_ref_vec* params, libab_ref* into) {
|
FUNCTION(print_bool) {
|
||||||
|
int* param = libab_unwrap_param(params, 0);
|
||||||
|
printf("%s\n", *param ? "true" : "false");
|
||||||
|
libab_get_unit_value(ab, into);
|
||||||
|
return LIBAB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION(print_unit) {
|
||||||
printf("()\n");
|
printf("()\n");
|
||||||
libab_get_unit_value(ab, into);
|
libab_get_unit_value(ab, into);
|
||||||
return LIBAB_SUCCESS;
|
return LIBAB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OP_FUNCTION(name, expression) \
|
#define OP_FUNCTION(name, expression) \
|
||||||
libab_result name(libab* ab, libab_ref_vec* params, libab_ref* into) { \
|
libab_result name(libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) { \
|
||||||
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); \
|
||||||
@@ -88,12 +131,20 @@ libab_result register_functions(libab* ab) {
|
|||||||
libab_ref difficult_type;
|
libab_ref difficult_type;
|
||||||
libab_ref print_num_type;
|
libab_ref print_num_type;
|
||||||
libab_ref print_unit_type;
|
libab_ref print_unit_type;
|
||||||
|
libab_ref print_bool_type;
|
||||||
|
libab_ref bool_logic_type;
|
||||||
|
libab_ref bool_not_type;
|
||||||
|
libab_ref equals_num_type;
|
||||||
|
|
||||||
result = libab_create_type(ab, &trig_type, "(num)->num");
|
result = libab_create_type(ab, &trig_type, "(num)->num");
|
||||||
TRY(libab_create_type(ab, &atan2_type, "(num, num)->num"));
|
TRY(libab_create_type(ab, &atan2_type, "(num, num)->num"));
|
||||||
|
TRY(libab_create_type(ab, &equals_num_type, "(num, num)->bool"));
|
||||||
TRY(libab_create_type(ab, &difficult_type, "((num)->num)->num"));
|
TRY(libab_create_type(ab, &difficult_type, "((num)->num)->num"));
|
||||||
TRY(libab_create_type(ab, &print_num_type, "(num)->unit"));
|
TRY(libab_create_type(ab, &print_num_type, "(num)->unit"));
|
||||||
TRY(libab_create_type(ab, &print_unit_type, "(unit)->unit"));
|
TRY(libab_create_type(ab, &print_unit_type, "(unit)->unit"));
|
||||||
|
TRY(libab_create_type(ab, &print_bool_type, "(bool)->unit"));
|
||||||
|
TRY(libab_create_type(ab, &bool_logic_type, "(bool,bool)->bool"));
|
||||||
|
TRY(libab_create_type(ab, &bool_not_type, "(bool)->bool"));
|
||||||
|
|
||||||
TRY(libab_register_function(ab, "atan", &trig_type, function_atan));
|
TRY(libab_register_function(ab, "atan", &trig_type, function_atan));
|
||||||
TRY(libab_register_function(ab, "atan2", &atan2_type, function_atan2));
|
TRY(libab_register_function(ab, "atan2", &atan2_type, function_atan2));
|
||||||
@@ -101,29 +152,68 @@ libab_result register_functions(libab* ab) {
|
|||||||
TRY(libab_register_function(ab, "minus", &atan2_type, function_minus));
|
TRY(libab_register_function(ab, "minus", &atan2_type, function_minus));
|
||||||
TRY(libab_register_function(ab, "times", &atan2_type, function_times));
|
TRY(libab_register_function(ab, "times", &atan2_type, function_times));
|
||||||
TRY(libab_register_function(ab, "divide", &atan2_type, function_divide));
|
TRY(libab_register_function(ab, "divide", &atan2_type, function_divide));
|
||||||
|
TRY(libab_register_function(ab, "and", &bool_logic_type, function_and));
|
||||||
|
TRY(libab_register_function(ab, "or", &bool_logic_type, function_or));
|
||||||
|
TRY(libab_register_function(ab, "xor", &bool_logic_type, function_xor));
|
||||||
|
TRY(libab_register_function(ab, "not", &bool_not_type, function_not));
|
||||||
|
TRY(libab_register_function(ab, "equals", &equals_num_type, function_equals_num));
|
||||||
TRY(libab_register_function(ab, "print", &print_num_type, function_print_num));
|
TRY(libab_register_function(ab, "print", &print_num_type, function_print_num));
|
||||||
TRY(libab_register_function(ab, "print", &print_unit_type, function_print_unit));
|
TRY(libab_register_function(ab, "print", &print_unit_type, function_print_unit));
|
||||||
|
TRY(libab_register_function(ab, "print", &print_bool_type, function_print_bool));
|
||||||
|
TRY(libab_register_operator_infix(ab, "==", 0, -1, "equals"));
|
||||||
TRY(libab_register_operator_infix(ab, "+", 0, -1, "plus"));
|
TRY(libab_register_operator_infix(ab, "+", 0, -1, "plus"));
|
||||||
TRY(libab_register_operator_infix(ab, "-", 0, -1, "minus"));
|
TRY(libab_register_operator_infix(ab, "-", 0, -1, "minus"));
|
||||||
TRY(libab_register_operator_infix(ab, "*", 1, -1, "times"));
|
TRY(libab_register_operator_infix(ab, "*", 1, -1, "times"));
|
||||||
TRY(libab_register_operator_infix(ab, "/", 1, -1, "divide"));
|
TRY(libab_register_operator_infix(ab, "/", 1, -1, "divide"));
|
||||||
|
TRY(libab_register_operator_infix(ab, "&", 1, -1, "and"));
|
||||||
|
TRY(libab_register_operator_infix(ab, "|", 1, -1, "or"));
|
||||||
|
TRY(libab_register_operator_infix(ab, "^", 1, -1, "xor"));
|
||||||
|
TRY(libab_register_operator_prefix(ab, "!", "not"));
|
||||||
|
|
||||||
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(&bool_logic_type);
|
||||||
|
libab_ref_free(&bool_not_type);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result loop(libab* ab, int interaction_count, libab_ref* scope) {
|
||||||
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
char input_buffer[2048];
|
||||||
|
libab_ref eval_into;
|
||||||
|
libab_ref call_into;
|
||||||
|
libab_result eval_result;
|
||||||
|
|
||||||
|
while (interaction_count-- && result == LIBAB_SUCCESS) {
|
||||||
|
printf("(%d) > ", INTERACTIONS - interaction_count);
|
||||||
|
fgets(input_buffer, 2048, stdin);
|
||||||
|
eval_result = libab_run_scoped(ab, input_buffer, scope, &eval_into);
|
||||||
|
|
||||||
|
if (eval_result != LIBAB_SUCCESS) {
|
||||||
|
printf("Invalid input (error code %d).\n", eval_result);
|
||||||
|
} else {
|
||||||
|
result = libab_call_function_scoped(ab, "print", scope, &call_into, 1, &eval_into);
|
||||||
|
if(result == LIBAB_BAD_CALL) {
|
||||||
|
printf("(?)\n");
|
||||||
|
result = LIBAB_SUCCESS;
|
||||||
|
}
|
||||||
|
libab_ref_free(&call_into);
|
||||||
|
}
|
||||||
|
libab_ref_free(&eval_into);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
char input_buffer[2048];
|
|
||||||
int interaction_count = INTERACTIONS;
|
|
||||||
libab_ref eval_into;
|
|
||||||
libab_ref call_into;
|
|
||||||
libab_result result;
|
libab_result result;
|
||||||
libab_result eval_result;
|
libab_ref scope;
|
||||||
libab ab;
|
libab ab;
|
||||||
|
|
||||||
if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) {
|
if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) {
|
||||||
@@ -132,18 +222,12 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = register_functions(&ab);
|
result = register_functions(&ab);
|
||||||
while (interaction_count-- && result == LIBAB_SUCCESS) {
|
if(result == LIBAB_SUCCESS) {
|
||||||
printf("(%d) > ", INTERACTIONS - interaction_count);
|
result = libab_create_table(&ab, &scope, &ab.table);
|
||||||
fgets(input_buffer, 2048, stdin);
|
|
||||||
eval_result = libab_run(&ab, input_buffer, &eval_into);
|
|
||||||
|
|
||||||
if (eval_result != LIBAB_SUCCESS) {
|
|
||||||
printf("Invalid input.\n");
|
|
||||||
} else {
|
|
||||||
result = libab_run_function(&ab, "print", &call_into, 1, &eval_into);
|
|
||||||
libab_ref_free(&call_into);
|
|
||||||
}
|
}
|
||||||
libab_ref_free(&eval_into);
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
loop(&ab, INTERACTIONS, &scope);
|
||||||
|
libab_ref_free(&scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_free(&ab);
|
libab_free(&ab);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,8 @@ libab_result libab_lexer_init(libab_lexer* lexer) {
|
|||||||
const char* words[] = {".",
|
const char* words[] = {".",
|
||||||
"[a-zA-Z][a-zA-Z0-9_]*",
|
"[a-zA-Z][a-zA-Z0-9_]*",
|
||||||
"[0-9]+(\\.[0-9]*)?",
|
"[0-9]+(\\.[0-9]*)?",
|
||||||
|
"true",
|
||||||
|
"false",
|
||||||
"if",
|
"if",
|
||||||
"else",
|
"else",
|
||||||
"while",
|
"while",
|
||||||
@@ -18,9 +20,9 @@ libab_result libab_lexer_init(libab_lexer* lexer) {
|
|||||||
"fun",
|
"fun",
|
||||||
"return"};
|
"return"};
|
||||||
libab_lexer_token tokens[] = {
|
libab_lexer_token tokens[] = {
|
||||||
TOKEN_CHAR, TOKEN_ID, TOKEN_NUM, TOKEN_KW_IF,
|
TOKEN_CHAR, TOKEN_ID, TOKEN_NUM, TOKEN_KW_TRUE,
|
||||||
TOKEN_KW_ELSE, TOKEN_KW_WHILE, TOKEN_KW_DO, TOKEN_KW_ARROW,
|
TOKEN_KW_FALSE, TOKEN_KW_IF, TOKEN_KW_ELSE, TOKEN_KW_WHILE,
|
||||||
TOKEN_KW_FUN, TOKEN_KW_RETURN };
|
TOKEN_KW_DO, TOKEN_KW_ARROW, TOKEN_KW_FUN, TOKEN_KW_RETURN};
|
||||||
const size_t count = sizeof(tokens) / sizeof(libab_lexer_token);
|
const size_t count = sizeof(tokens) / sizeof(libab_lexer_token);
|
||||||
|
|
||||||
eval_config_init(&lexer->config);
|
eval_config_init(&lexer->config);
|
||||||
|
|||||||
267
src/libabacus.c
267
src/libabacus.c
@@ -5,29 +5,18 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "free_functions.h"
|
||||||
|
|
||||||
void _free_function_list(void* function_list) {
|
static libab_basetype _basetype_function_list = {libab_free_function_list, NULL, 0};
|
||||||
libab_function_list_free(function_list);
|
|
||||||
free(function_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static libab_basetype _basetype_function_list = {_free_function_list, NULL, 0};
|
|
||||||
|
|
||||||
void _free_function(void* function) {
|
|
||||||
libab_function_free(function);
|
|
||||||
free(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
static libab_basetype_param _basetype_function_params[] = {{BT_LIST, NULL}};
|
static libab_basetype_param _basetype_function_params[] = {{BT_LIST, NULL}};
|
||||||
|
|
||||||
static libab_basetype _basetype_function = {_free_function,
|
static libab_basetype _basetype_function = {libab_free_function,
|
||||||
_basetype_function_params, 1};
|
_basetype_function_params, 1};
|
||||||
|
|
||||||
void _free_unit(void* unit) {
|
static libab_basetype _basetype_unit = { libab_free_unit, NULL, 0 };
|
||||||
|
|
||||||
}
|
static libab_basetype _basetype_bool = { libab_free_bool, NULL, 0 };
|
||||||
|
|
||||||
static libab_basetype _basetype_unit = { _free_unit, NULL, 0 };
|
|
||||||
|
|
||||||
libab_result _prepare_types(libab* ab, void (*free_function)(void*));
|
libab_result _prepare_types(libab* ab, void (*free_function)(void*));
|
||||||
|
|
||||||
@@ -38,16 +27,19 @@ 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_function_list);
|
libab_ref_null(&ab->type_function_list);
|
||||||
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);
|
||||||
|
libab_ref_free(&ab->type_bool);
|
||||||
libab_ref_free(&ab->type_function_list);
|
libab_ref_free(&ab->type_function_list);
|
||||||
libab_ref_free(&ab->type_unit);
|
libab_ref_free(&ab->type_unit);
|
||||||
result = _prepare_types(ab, free_function);
|
result = _prepare_types(ab, free_function);
|
||||||
@@ -72,6 +64,7 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*),
|
|||||||
if (result != LIBAB_SUCCESS) {
|
if (result != LIBAB_SUCCESS) {
|
||||||
libab_ref_free(&ab->table);
|
libab_ref_free(&ab->table);
|
||||||
libab_ref_free(&ab->type_num);
|
libab_ref_free(&ab->type_num);
|
||||||
|
libab_ref_free(&ab->type_bool);
|
||||||
libab_ref_free(&ab->type_function_list);
|
libab_ref_free(&ab->type_function_list);
|
||||||
libab_ref_free(&ab->type_unit);
|
libab_ref_free(&ab->type_unit);
|
||||||
|
|
||||||
@@ -92,16 +85,6 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*),
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sanitize(char* to, const char* from, size_t buffer_size) {
|
|
||||||
size_t index = 0;
|
|
||||||
while (*from && index < (buffer_size - 2)) {
|
|
||||||
if (*from == '+' || *from == '*' || *from == '\\')
|
|
||||||
to[index++] = '\\';
|
|
||||||
to[index++] = *(from++);
|
|
||||||
}
|
|
||||||
to[index] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void _initialize_behavior(libab_behavior* behavior, libab_ref* type,
|
void _initialize_behavior(libab_behavior* behavior, libab_ref* type,
|
||||||
libab_function_ptr func) {
|
libab_function_ptr func) {
|
||||||
behavior->variant = BIMPL_INTERNAL;
|
behavior->variant = BIMPL_INTERNAL;
|
||||||
@@ -119,14 +102,14 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == LIBAB_SUCCESS) {
|
if (result == LIBAB_SUCCESS) {
|
||||||
_sanitize(op_buffer, op, 8);
|
libab_sanitize(op_buffer, op, 8);
|
||||||
result = libab_convert_lex_result(
|
result = libab_convert_lex_result(
|
||||||
eval_config_add(&ab->lexer.config, op_buffer, TOKEN_OP));
|
eval_config_add(&ab->lexer.config, op_buffer, TOKEN_OP));
|
||||||
}
|
}
|
||||||
@@ -162,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, _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;
|
||||||
}
|
}
|
||||||
@@ -295,6 +203,7 @@ libab_result _prepare_types(libab* ab, void (*free_function)(void*)) {
|
|||||||
ab->basetype_num.free_function = free_function;
|
ab->basetype_num.free_function = free_function;
|
||||||
|
|
||||||
libab_ref_null(&ab->type_num);
|
libab_ref_null(&ab->type_num);
|
||||||
|
libab_ref_null(&ab->type_bool);
|
||||||
libab_ref_null(&ab->type_function_list);
|
libab_ref_null(&ab->type_function_list);
|
||||||
libab_ref_null(&ab->type_unit);
|
libab_ref_null(&ab->type_unit);
|
||||||
|
|
||||||
@@ -304,6 +213,12 @@ libab_result _prepare_types(libab* ab, void (*free_function)(void*)) {
|
|||||||
libab_instantiate_basetype(&ab->basetype_num, &ab->type_num, 0);
|
libab_instantiate_basetype(&ab->basetype_num, &ab->type_num, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result == LIBAB_SUCCESS) {
|
||||||
|
libab_ref_free(&ab->type_bool);
|
||||||
|
result =
|
||||||
|
libab_instantiate_basetype(&_basetype_bool, &ab->type_bool, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (result == LIBAB_SUCCESS) {
|
if (result == LIBAB_SUCCESS) {
|
||||||
libab_ref_free(&ab->type_function_list);
|
libab_ref_free(&ab->type_function_list);
|
||||||
result = libab_instantiate_basetype(&_basetype_function_list,
|
result = libab_instantiate_basetype(&_basetype_function_list,
|
||||||
@@ -319,6 +234,10 @@ libab_result _prepare_types(libab* ab, void (*free_function)(void*)) {
|
|||||||
result = libab_register_basetype(ab, "num", &ab->basetype_num);
|
result = libab_register_basetype(ab, "num", &ab->basetype_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
result = libab_register_basetype(ab, "bool", &_basetype_bool);
|
||||||
|
}
|
||||||
|
|
||||||
if (result == LIBAB_SUCCESS) {
|
if (result == LIBAB_SUCCESS) {
|
||||||
result = libab_register_basetype(ab, "function", &_basetype_function);
|
result = libab_register_basetype(ab, "function", &_basetype_function);
|
||||||
}
|
}
|
||||||
@@ -334,9 +253,11 @@ libab_result _prepare_types(libab* ab, void (*free_function)(void*)) {
|
|||||||
|
|
||||||
if (result != LIBAB_SUCCESS) {
|
if (result != LIBAB_SUCCESS) {
|
||||||
libab_ref_free(&ab->type_num);
|
libab_ref_free(&ab->type_num);
|
||||||
|
libab_ref_free(&ab->type_bool);
|
||||||
libab_ref_free(&ab->type_function_list);
|
libab_ref_free(&ab->type_function_list);
|
||||||
libab_ref_free(&ab->type_unit);
|
libab_ref_free(&ab->type_unit);
|
||||||
libab_ref_null(&ab->type_num);
|
libab_ref_null(&ab->type_num);
|
||||||
|
libab_ref_null(&ab->type_bool);
|
||||||
libab_ref_null(&ab->type_function_list);
|
libab_ref_null(&ab->type_function_list);
|
||||||
libab_ref_null(&ab->type_unit);
|
libab_ref_null(&ab->type_unit);
|
||||||
}
|
}
|
||||||
@@ -353,7 +274,7 @@ libab_result libab_create_type(libab* ab, libab_ref* into, const char* type) {
|
|||||||
result = libab_parser_parse_type(&ab->parser, &tokens, type, into);
|
result = libab_parser_parse_type(&ab->parser, &tokens, type, into);
|
||||||
}
|
}
|
||||||
if (result == LIBAB_SUCCESS) {
|
if (result == LIBAB_SUCCESS) {
|
||||||
result = libab_resolve_parsetype(libab_ref_get(into),
|
result = libab_resolve_parsetype_inplace(libab_ref_get(into),
|
||||||
libab_ref_get(&ab->table));
|
libab_ref_get(&ab->table));
|
||||||
}
|
}
|
||||||
ll_foreach(&tokens, NULL, compare_always, libab_lexer_foreach_match_free);
|
ll_foreach(&tokens, NULL, compare_always, libab_lexer_foreach_match_free);
|
||||||
@@ -363,6 +284,8 @@ libab_result libab_create_type(libab* ab, libab_ref* into, const char* type) {
|
|||||||
|
|
||||||
libab_basetype* libab_get_basetype_num(libab* ab) { return &ab->basetype_num; }
|
libab_basetype* libab_get_basetype_num(libab* ab) { return &ab->basetype_num; }
|
||||||
|
|
||||||
|
libab_basetype* libab_get_basetype_bool(libab* ab) { return &_basetype_bool; }
|
||||||
|
|
||||||
libab_basetype* libab_get_basetype_function(libab* ab) {
|
libab_basetype* libab_get_basetype_function(libab* ab) {
|
||||||
return &_basetype_function;
|
return &_basetype_function;
|
||||||
}
|
}
|
||||||
@@ -379,6 +302,10 @@ void libab_get_type_num(libab* ab, libab_ref* into) {
|
|||||||
libab_ref_copy(&ab->type_num, into);
|
libab_ref_copy(&ab->type_num, into);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void libab_get_type_bool(libab* ab, libab_ref* into) {
|
||||||
|
libab_ref_copy(&ab->type_bool, into);
|
||||||
|
}
|
||||||
|
|
||||||
void libab_get_type_function_list(libab* ab, libab_ref* into) {
|
void libab_get_type_function_list(libab* ab, libab_ref* into) {
|
||||||
libab_ref_copy(&ab->type_function_list, into);
|
libab_ref_copy(&ab->type_function_list, into);
|
||||||
}
|
}
|
||||||
@@ -391,33 +318,66 @@ void libab_get_unit_value(libab* ab, libab_ref* into) {
|
|||||||
libab_interpreter_unit_value(&ab->intr, into);
|
libab_interpreter_unit_value(&ab->intr, into);
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_result libab_run(libab* ab, const char* string, libab_ref* value) {
|
void libab_get_true_value(libab* ab, libab_ref* into) {
|
||||||
|
libab_interpreter_true_value(&ab->intr, into);
|
||||||
|
}
|
||||||
|
|
||||||
|
void libab_get_false_value(libab* ab, libab_ref* into) {
|
||||||
|
libab_interpreter_false_value(&ab->intr, into);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
libab_tree* root;
|
|
||||||
|
|
||||||
ll_init(&tokens);
|
ll_init(&tokens);
|
||||||
libab_ref_null(value);
|
*into = NULL;
|
||||||
|
|
||||||
result = libab_lexer_lex(&ab->lexer, string, &tokens);
|
result = libab_lexer_lex(&ab->lexer, string, &tokens);
|
||||||
|
|
||||||
if (result == LIBAB_SUCCESS) {
|
if(result == LIBAB_SUCCESS) {
|
||||||
result = libab_parser_parse(&ab->parser, &tokens, string, &root);
|
result = libab_parser_parse(&ab->parser, &tokens, string, into);
|
||||||
}
|
|
||||||
|
|
||||||
if (result == LIBAB_SUCCESS) {
|
|
||||||
libab_ref_free(value);
|
|
||||||
result = libab_interpreter_run(&ab->intr, root, value);
|
|
||||||
libab_tree_free_recursive(root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ll_foreach(&tokens, NULL, compare_always, libab_lexer_foreach_match_free);
|
ll_foreach(&tokens, NULL, compare_always, libab_lexer_foreach_match_free);
|
||||||
ll_free(&tokens);
|
ll_free(&tokens);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result _handle_va_params(libab* ab, libab_ref_vec* into, size_t param_count, va_list args) {
|
||||||
|
libab_result result = libab_ref_vec_init(into);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
while(result == LIBAB_SUCCESS && param_count--) {
|
||||||
|
result = libab_ref_vec_insert(into, va_arg(args, libab_ref*));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != LIBAB_SUCCESS) {
|
||||||
|
libab_ref_vec_free(into);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result libab_run(libab* ab, const char* string, libab_ref* value) {
|
||||||
|
libab_result result;
|
||||||
|
libab_tree* root;
|
||||||
|
|
||||||
|
libab_ref_null(value);
|
||||||
|
result = libab_parse(ab, string, &root);
|
||||||
|
|
||||||
|
if (result == LIBAB_SUCCESS) {
|
||||||
|
libab_ref_free(value);
|
||||||
|
result = libab_interpreter_run(&ab->intr, root, &ab->table, SCOPE_FORCE, value);
|
||||||
|
libab_tree_free_recursive(root);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -426,16 +386,10 @@ libab_result libab_run_function(libab* ab, const char* function,
|
|||||||
|
|
||||||
va_start(args, param_count);
|
va_start(args, param_count);
|
||||||
libab_ref_null(into);
|
libab_ref_null(into);
|
||||||
result = libab_ref_vec_init(¶ms);
|
result = _handle_va_params(ab, ¶ms, param_count, args);
|
||||||
if(result == LIBAB_SUCCESS) {
|
|
||||||
while(result == LIBAB_SUCCESS && param_count--) {
|
|
||||||
result = libab_ref_vec_insert(¶ms, va_arg(args, libab_ref*));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result == LIBAB_SUCCESS) {
|
if(result == LIBAB_SUCCESS) {
|
||||||
libab_ref_free(into);
|
libab_ref_free(into);
|
||||||
result = libab_interpreter_run_function(&ab->intr, 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);
|
||||||
}
|
}
|
||||||
@@ -444,13 +398,60 @@ libab_result libab_run_function(libab* ab, const char* function,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libab_result libab_run_tree(libab* ab, libab_tree* tree, libab_ref* value) {
|
||||||
|
return libab_interpreter_run(&ab->intr, tree, &ab->table, SCOPE_FORCE, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result libab_run_scoped(libab* ab, const char* string, libab_ref* scope, libab_ref* into) {
|
||||||
|
libab_result result;
|
||||||
|
libab_tree* root;
|
||||||
|
|
||||||
|
libab_ref_null(into);
|
||||||
|
result = libab_parse(ab, string, &root);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
libab_ref_free(into);
|
||||||
|
result = libab_interpreter_run(&ab->intr, root, scope, SCOPE_NONE, into);
|
||||||
|
libab_tree_free_recursive(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result libab_call_function_scoped(libab* ab, const char* function, libab_ref* scope, libab_ref* into,
|
||||||
|
size_t param_count, ...) {
|
||||||
|
libab_ref_vec params;
|
||||||
|
libab_result result;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, param_count);
|
||||||
|
libab_ref_null(into);
|
||||||
|
result = _handle_va_params(ab, ¶ms, param_count, args);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
libab_ref_free(into);
|
||||||
|
result = libab_interpreter_call_function(&ab->intr, scope, function, ¶ms, into);
|
||||||
|
|
||||||
|
libab_ref_vec_free(¶ms);
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result libab_run_tree_scoped(libab* ab, libab_tree* tree, libab_ref* scope, libab_ref* into) {
|
||||||
|
return libab_interpreter_run(&ab->intr, tree, scope, SCOPE_NONE, into);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
libab_ref_free(&ab->type_bool);
|
||||||
libab_ref_free(&ab->type_function_list);
|
libab_ref_free(&ab->type_function_list);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/parser.c
49
src/parser.c
@@ -406,6 +406,38 @@ libab_result _parse_void(struct parser_state* state, libab_tree** store_into) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libab_result _parse_true(struct parser_state* state, libab_tree** store_into) {
|
||||||
|
libab_result result = _parser_consume_type(state, TOKEN_KW_TRUE);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
if ((*store_into = malloc(sizeof(**store_into)))) {
|
||||||
|
(*store_into)->variant = TREE_TRUE;
|
||||||
|
} else {
|
||||||
|
result = LIBAB_MALLOC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != LIBAB_SUCCESS) {
|
||||||
|
*store_into = NULL;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result _parse_false(struct parser_state* state, libab_tree** store_into) {
|
||||||
|
libab_result result = _parser_consume_type(state, TOKEN_KW_FALSE);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
if ((*store_into = malloc(sizeof(**store_into)))) {
|
||||||
|
(*store_into)->variant = TREE_FALSE;
|
||||||
|
} else {
|
||||||
|
result = LIBAB_MALLOC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != LIBAB_SUCCESS) {
|
||||||
|
*store_into = NULL;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
libab_result _parse_if(struct parser_state* state, libab_tree** store_into) {
|
libab_result _parse_if(struct parser_state* state, libab_tree** store_into) {
|
||||||
libab_result result = LIBAB_SUCCESS;
|
libab_result result = LIBAB_SUCCESS;
|
||||||
libab_tree* condition = NULL;
|
libab_tree* condition = NULL;
|
||||||
@@ -493,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)) {
|
||||||
@@ -736,6 +769,10 @@ libab_result _parse_atom(struct parser_state* state, libab_tree** store_into) {
|
|||||||
result = _parse_fun(state, store_into);
|
result = _parse_fun(state, store_into);
|
||||||
} else if (_parser_is_type(state, TOKEN_KW_RETURN)) {
|
} else if (_parser_is_type(state, TOKEN_KW_RETURN)) {
|
||||||
result = _parse_return(state, store_into);
|
result = _parse_return(state, store_into);
|
||||||
|
} else if (_parser_is_type(state, TOKEN_KW_TRUE)) {
|
||||||
|
result = _parse_true(state, store_into);
|
||||||
|
} else if (_parser_is_type(state, TOKEN_KW_FALSE)) {
|
||||||
|
result = _parse_false(state, store_into);
|
||||||
} else {
|
} else {
|
||||||
result = LIBAB_UNEXPECTED;
|
result = LIBAB_UNEXPECTED;
|
||||||
}
|
}
|
||||||
@@ -1019,15 +1056,16 @@ 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)) {
|
||||||
_parser_find_operator_infix(state, op_stack.tail->data,
|
libab_lexer_match* other_token = op_stack.tail->data;
|
||||||
&other_operator);
|
if(other_token->type == TOKEN_OP_INFIX || other_token->type == TOKEN_OP_RESERVED) {
|
||||||
|
_parser_find_operator_infix(state, other_token, &other_operator);
|
||||||
|
}
|
||||||
|
|
||||||
if (((libab_lexer_match*)op_stack.tail->data)->type ==
|
if (other_token->type == TOKEN_OP_PREFIX ||
|
||||||
TOKEN_OP_PREFIX ||
|
|
||||||
(operator.associativity == - 1 &&
|
(operator.associativity == - 1 &&
|
||||||
operator.precedence <= other_operator.precedence) ||
|
operator.precedence <= other_operator.precedence) ||
|
||||||
(operator.associativity == 1 &&
|
(operator.associativity == 1 &&
|
||||||
operator.precedence<other_operator.precedence)) {
|
operator.precedence < other_operator.precedence)) {
|
||||||
libab_lexer_match* match = ll_poptail(&op_stack);
|
libab_lexer_match* match = ll_poptail(&op_stack);
|
||||||
result = _parser_append_op_node(state, match, &out_stack);
|
result = _parser_append_op_node(state, match, &out_stack);
|
||||||
} else {
|
} else {
|
||||||
@@ -1071,7 +1109,6 @@ libab_result _parse_expression(struct parser_state* state,
|
|||||||
result = LIBAB_UNEXPECTED;
|
result = LIBAB_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ll_foreach(&op_stack, NULL, compare_always, _parser_foreach_free_tree);
|
|
||||||
ll_foreach(&out_stack, NULL, compare_always, _parser_foreach_free_tree);
|
ll_foreach(&out_stack, NULL, compare_always, _parser_foreach_free_tree);
|
||||||
ll_free(&op_stack);
|
ll_free(&op_stack);
|
||||||
ll_free(&out_stack);
|
ll_free(&out_stack);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,65 @@ void libab_ref_trie_get(const libab_ref_trie* trie, const char* key,
|
|||||||
libab_ref_null(into);
|
libab_ref_null(into);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libab_result _ref_trie_foreach(libab_ref_trie_node* node,
|
||||||
|
char** str, size_t* str_size, size_t depth,
|
||||||
|
libab_result (*func)(const libab_ref*, const char*, va_list),
|
||||||
|
va_list args) {
|
||||||
|
va_list args_copy;
|
||||||
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
if(node == NULL) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(depth + 1 >= *str_size) {
|
||||||
|
char* new_str = realloc(*str, (*str_size) *= 2);
|
||||||
|
if(new_str) {
|
||||||
|
*str = new_str;
|
||||||
|
} else {
|
||||||
|
result = LIBAB_MALLOC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == LIBAB_SUCCESS) {
|
||||||
|
(*str)[depth] = node->key;
|
||||||
|
(*str)[depth + 1] = '\0';
|
||||||
|
|
||||||
|
if(libab_ref_get(&node->ref)) {
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
result = func(&node->ref, (*str), args_copy);
|
||||||
|
va_end(args_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == LIBAB_SUCCESS)
|
||||||
|
result = _ref_trie_foreach(node->child, str, str_size, depth + 1, func, args);
|
||||||
|
if(result == LIBAB_SUCCESS)
|
||||||
|
result = _ref_trie_foreach(node->next, str, str_size, depth, func, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result libab_ref_trie_foreach(const libab_ref_trie* trie,
|
||||||
|
libab_result (*func)(const libab_ref*, const char*, va_list),
|
||||||
|
...) {
|
||||||
|
va_list args;
|
||||||
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
char* str;
|
||||||
|
size_t string_size = 4;
|
||||||
|
|
||||||
|
if((str = malloc(sizeof(*str) * 4))) {
|
||||||
|
va_start(args, func);
|
||||||
|
result = _ref_trie_foreach(trie->head, &str, &string_size, 0, func, args);
|
||||||
|
va_end(args);
|
||||||
|
} else {
|
||||||
|
result = LIBAB_MALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(str);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void libab_ref_trie_free(libab_ref_trie* trie) {
|
void libab_ref_trie_free(libab_ref_trie* trie) {
|
||||||
_libab_ref_trie_free(trie->head);
|
_libab_ref_trie_free(trie->head);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
179
src/reserved.c
179
src/reserved.c
@@ -1,12 +1,175 @@
|
|||||||
#include "reserved.h"
|
#include "reserved.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "value.h"
|
||||||
|
#include "libabacus.h"
|
||||||
|
|
||||||
static const libab_reserved_operator libab_reserved_operators[] = {{
|
libab_result _behavior_assign(libab* ab, libab_ref* scope,
|
||||||
|
libab_tree* left, libab_tree* right,
|
||||||
|
libab_ref* into) {
|
||||||
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
|
||||||
|
if(left->variant == TREE_ID) {
|
||||||
|
result = libab_run_tree_scoped(ab, right, scope, into);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
result = libab_set_variable(libab_ref_get(scope), left->string_value, into);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != LIBAB_SUCCESS) {
|
||||||
|
libab_ref_free(into);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = LIBAB_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != LIBAB_SUCCESS) {
|
||||||
|
libab_ref_null(into);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_tree* to_run, int* into) {
|
||||||
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
libab_ref output;
|
||||||
|
libab_value* value;
|
||||||
|
libab_parsetype* type;
|
||||||
|
|
||||||
|
result = libab_run_tree_scoped(ab, to_run, scope, &output);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
value = libab_ref_get(&output);
|
||||||
|
type = libab_ref_get(&value->type);
|
||||||
|
if(type->data_u.base != libab_get_basetype_bool(ab)) {
|
||||||
|
result = LIBAB_BAD_CALL;
|
||||||
|
} else {
|
||||||
|
*into = *((int*) libab_ref_get(&value->data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libab_ref_free(&output);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result _behavior_land(libab* ab, libab_ref* scope,
|
||||||
|
libab_tree* left, libab_tree* right,
|
||||||
|
libab_ref* into) {
|
||||||
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
int temp;
|
||||||
|
result = _expect_boolean(ab, scope, left, &temp);
|
||||||
|
if(result == LIBAB_SUCCESS && temp) {
|
||||||
|
result = _expect_boolean(ab, scope, right, &temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
libab_get_bool_value(ab, temp, into);
|
||||||
|
} else {
|
||||||
|
libab_ref_null(into);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
libab_result _behavior_lor(libab* ab, libab_ref* scope,
|
||||||
|
libab_tree* left, libab_tree* right,
|
||||||
|
libab_ref* into) {
|
||||||
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
int temp = 0;
|
||||||
|
result = _expect_boolean(ab, scope, left, &temp);
|
||||||
|
if(result == LIBAB_SUCCESS && !temp) {
|
||||||
|
result = _expect_boolean(ab, scope, right, &temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
libab_get_bool_value(ab, temp, into);
|
||||||
|
} else {
|
||||||
|
libab_ref_null(into);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".",
|
||||||
|
-2,
|
||||||
|
-1,
|
||||||
|
_behavior_method
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"&&", /* Logical and */
|
||||||
|
-1, /* Low precedence */
|
||||||
|
-1, /* Left associative. */
|
||||||
|
_behavior_land
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"||", /* Logical or */
|
||||||
|
-1, /* Low precedence */
|
||||||
|
-1, /* Left associative. */
|
||||||
|
_behavior_lor
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const size_t element_count =
|
static const size_t element_count =
|
||||||
sizeof(libab_reserved_operators) / sizeof(libab_reserved_operator);
|
sizeof(libab_reserved_operators) / sizeof(libab_reserved_operator);
|
||||||
|
|
||||||
@@ -21,20 +184,24 @@ const libab_reserved_operator* libab_find_reserved_operator(const char* name) {
|
|||||||
|
|
||||||
libab_result libab_register_reserved_operators(libab_lexer* lexer) {
|
libab_result libab_register_reserved_operators(libab_lexer* lexer) {
|
||||||
libab_result result = LIBAB_SUCCESS;
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
char buffer[16];
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < element_count && result == LIBAB_SUCCESS; i++) {
|
for (i = 0; i < element_count && result == LIBAB_SUCCESS; i++) {
|
||||||
|
libab_sanitize(buffer, libab_reserved_operators[i].op, 16);
|
||||||
result = libab_convert_lex_result(eval_config_add(
|
result = libab_convert_lex_result(eval_config_add(
|
||||||
&lexer->config, libab_reserved_operators[i].op, TOKEN_OP_RESERVED));
|
&lexer->config, buffer, TOKEN_OP_RESERVED));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_result libab_remove_reserved_operators(libab_lexer* lexer) {
|
libab_result libab_remove_reserved_operators(libab_lexer* lexer) {
|
||||||
libab_result result = LIBAB_SUCCESS;
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
char buffer[16];
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < element_count && result == LIBAB_SUCCESS; i++) {
|
for (i = 0; i < element_count && result == LIBAB_SUCCESS; i++) {
|
||||||
|
libab_sanitize(buffer, libab_reserved_operators[i].op, 16);
|
||||||
result = libab_convert_lex_result(eval_config_remove(
|
result = libab_convert_lex_result(eval_config_remove(
|
||||||
&lexer->config, libab_reserved_operators[i].op, TOKEN_OP_RESERVED));
|
&lexer->config, buffer, TOKEN_OP_RESERVED));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/table.c
37
src/table.c
@@ -54,6 +54,12 @@ int libab_table_compare_type_param(const void* left, const void* right) {
|
|||||||
|
|
||||||
libab_operator* libab_table_search_operator(libab_table* table,
|
libab_operator* libab_table_search_operator(libab_table* table,
|
||||||
const char* string, int type) {
|
const char* string, int type) {
|
||||||
|
libab_table_entry* entry =
|
||||||
|
libab_table_search_entry_operator(table, string, type);
|
||||||
|
return entry ? &entry->data_u.op : NULL;
|
||||||
|
}
|
||||||
|
libab_table_entry* libab_table_search_entry_operator(libab_table* table,
|
||||||
|
const char* string, int type) {
|
||||||
libab_table_entry* entry = NULL;
|
libab_table_entry* entry = NULL;
|
||||||
if (type == OPERATOR_PREFIX) {
|
if (type == OPERATOR_PREFIX) {
|
||||||
entry = libab_table_search_filter(table, string, NULL,
|
entry = libab_table_search_filter(table, string, NULL,
|
||||||
@@ -61,41 +67,56 @@ libab_operator* libab_table_search_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);
|
||||||
}
|
}
|
||||||
return entry ? &entry->data_u.op : NULL;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_basetype* libab_table_search_basetype(libab_table* table,
|
libab_basetype* libab_table_search_basetype(libab_table* table,
|
||||||
const char* string) {
|
const char* string) {
|
||||||
libab_table_entry* entry = libab_table_search_filter(
|
libab_table_entry* entry =
|
||||||
table, string, NULL, libab_table_compare_basetype);
|
libab_table_search_entry_basetype(table, string);
|
||||||
return entry ? entry->data_u.basetype : NULL;
|
return entry ? entry->data_u.basetype : NULL;
|
||||||
}
|
}
|
||||||
|
libab_table_entry* libab_table_search_entry_basetype(libab_table* table,
|
||||||
|
const char* string) {
|
||||||
|
return libab_table_search_filter(table, string, NULL,
|
||||||
|
libab_table_compare_basetype);
|
||||||
|
}
|
||||||
|
|
||||||
void libab_table_search_value(libab_table* table, const char* string,
|
void libab_table_search_value(libab_table* table, const char* string,
|
||||||
libab_ref* ref) {
|
libab_ref* ref) {
|
||||||
libab_table_entry* entry = libab_table_search_filter(
|
libab_table_entry* entry =
|
||||||
table, string, NULL, libab_table_compare_value);
|
libab_table_search_entry_value(table, string);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
libab_ref_copy(&entry->data_u.value, ref);
|
libab_ref_copy(&entry->data_u.value, ref);
|
||||||
} else {
|
} else {
|
||||||
libab_ref_null(ref);
|
libab_ref_null(ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
libab_table_entry* libab_table_search_entry_value(libab_table* table,
|
||||||
|
const char* string) {
|
||||||
|
return libab_table_search_filter(table, string, NULL,
|
||||||
|
libab_table_compare_value);
|
||||||
|
}
|
||||||
|
|
||||||
void libab_table_search_type_param(libab_table* table, const char* string,
|
void libab_table_search_type_param(libab_table* table, const char* string,
|
||||||
libab_ref* ref) {
|
libab_ref* ref) {
|
||||||
libab_table_entry* entry = libab_table_search_filter(
|
libab_table_entry* entry =
|
||||||
table, string, NULL, libab_table_compare_type_param);
|
libab_table_search_entry_type_param(table, string);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
libab_ref_copy(&entry->data_u.type_param, ref);
|
libab_ref_copy(&entry->data_u.type_param, ref);
|
||||||
} else {
|
} else {
|
||||||
libab_ref_null(ref);
|
libab_ref_null(ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
libab_table_entry* libab_table_search_entry_type_param(libab_table* table,
|
||||||
|
const char* string) {
|
||||||
|
return libab_table_search_filter(
|
||||||
|
table, string, NULL, libab_table_compare_type_param);
|
||||||
|
}
|
||||||
|
|
||||||
libab_result libab_table_put(libab_table* table, const char* string,
|
libab_result libab_table_put(libab_table* table, const char* string,
|
||||||
libab_table_entry* entry) {
|
libab_table_entry* entry) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ int libab_tree_has_string(libab_tree_variant variant) {
|
|||||||
int libab_tree_has_scope(libab_tree_variant variant) {
|
int libab_tree_has_scope(libab_tree_variant variant) {
|
||||||
return variant == TREE_BASE || variant == TREE_BLOCK ||
|
return variant == TREE_BASE || variant == TREE_BLOCK ||
|
||||||
variant == TREE_IF || variant == TREE_WHILE ||
|
variant == TREE_IF || variant == TREE_WHILE ||
|
||||||
variant == TREE_DOWHILE || variant == TREE_FUN;
|
variant == TREE_DOWHILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int libab_tree_has_type(libab_tree_variant variant) {
|
int libab_tree_has_type(libab_tree_variant variant) {
|
||||||
|
|||||||
11
src/types.c
11
src/types.c
@@ -1,11 +0,0 @@
|
|||||||
#include "types.h"
|
|
||||||
|
|
||||||
libab_result libab_array_init(libab_array* array) {
|
|
||||||
return libab_ref_vec_init(&array->elems);
|
|
||||||
}
|
|
||||||
|
|
||||||
libab_result libab_array_insert(libab_array* array, libab_ref* value) {
|
|
||||||
return libab_ref_vec_insert(&array->elems, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void libab_array_free(libab_array* array) { libab_ref_vec_free(&array->elems); }
|
|
||||||
318
src/util.c
318
src/util.c
@@ -2,6 +2,8 @@
|
|||||||
#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"
|
||||||
|
|
||||||
libab_result libab_convert_lex_result(liblex_result to_convert) {
|
libab_result libab_convert_lex_result(liblex_result to_convert) {
|
||||||
libab_result result = LIBAB_SUCCESS;
|
libab_result result = LIBAB_SUCCESS;
|
||||||
@@ -44,7 +46,7 @@ libab_result _libab_check_parsetype(libab_parsetype* to_check) {
|
|||||||
libab_result result = LIBAB_SUCCESS;
|
libab_result result = LIBAB_SUCCESS;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
libab_result libab_resolve_parsetype(libab_parsetype* to_resolve,
|
libab_result libab_resolve_parsetype_inplace(libab_parsetype* to_resolve,
|
||||||
libab_table* scope) {
|
libab_table* scope) {
|
||||||
libab_result result = LIBAB_SUCCESS;
|
libab_result result = LIBAB_SUCCESS;
|
||||||
int resolve_name, check_parents;
|
int resolve_name, check_parents;
|
||||||
@@ -60,7 +62,7 @@ libab_result libab_resolve_parsetype(libab_parsetype* to_resolve,
|
|||||||
|
|
||||||
if (resolve_name && result == LIBAB_SUCCESS) {
|
if (resolve_name && result == LIBAB_SUCCESS) {
|
||||||
libab_basetype* basetype =
|
libab_basetype* basetype =
|
||||||
libab_table_search_basetype(scope, to_resolve->data_u.name);
|
libab_get_basetype(to_resolve, scope);
|
||||||
if (basetype) {
|
if (basetype) {
|
||||||
free(to_resolve->data_u.name);
|
free(to_resolve->data_u.name);
|
||||||
to_resolve->data_u.base = basetype;
|
to_resolve->data_u.base = basetype;
|
||||||
@@ -80,7 +82,7 @@ libab_result libab_resolve_parsetype(libab_parsetype* to_resolve,
|
|||||||
|
|
||||||
if (to_resolve->variant & LIBABACUS_TYPE_F_PARENT) {
|
if (to_resolve->variant & LIBABACUS_TYPE_F_PARENT) {
|
||||||
while (result == LIBAB_SUCCESS && index < to_resolve->children.size) {
|
while (result == LIBAB_SUCCESS && index < to_resolve->children.size) {
|
||||||
result = libab_resolve_parsetype(
|
result = libab_resolve_parsetype_inplace(
|
||||||
libab_ref_get(&to_resolve->children.data[index]), scope);
|
libab_ref_get(&to_resolve->children.data[index]), scope);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
@@ -89,14 +91,69 @@ libab_result libab_resolve_parsetype(libab_parsetype* to_resolve,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _libab_free_parsetype(void* parsetype) {
|
libab_result libab_resolve_parsetype_copy(libab_parsetype* to_resolve,
|
||||||
libab_parsetype_free(parsetype);
|
libab_table* scope,
|
||||||
free(parsetype);
|
libab_ref* into) {
|
||||||
}
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
libab_parsetype* parsetype;
|
||||||
|
int is_placeholer = to_resolve->variant & LIBABACUS_TYPE_F_PLACE;
|
||||||
|
if((parsetype = malloc(sizeof(*parsetype)))) {
|
||||||
|
parsetype->variant = to_resolve->variant;
|
||||||
|
if(!is_placeholer) {
|
||||||
|
parsetype->variant |= LIBABACUS_TYPE_F_RESOLVED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = LIBAB_MALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
void _libab_parsetype_free(void* parsetype) {
|
if(result == LIBAB_SUCCESS) {
|
||||||
libab_parsetype_free(parsetype);
|
if(!is_placeholer) {
|
||||||
|
libab_basetype* parent_basetype = libab_get_basetype(to_resolve, scope);
|
||||||
|
if(parent_basetype) {
|
||||||
|
parsetype->data_u.base = parent_basetype;
|
||||||
|
} else {
|
||||||
|
result = LIBAB_UNKNOWN_TYPE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = libab_copy_string(&parsetype->data_u.name, to_resolve->data_u.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(result == LIBAB_SUCCESS && (to_resolve->variant & LIBABACUS_TYPE_F_PARENT)) {
|
||||||
|
result = libab_ref_vec_init(&parsetype->children);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == LIBAB_SUCCESS && (to_resolve->variant & LIBABACUS_TYPE_F_PARENT)) {
|
||||||
|
size_t i;
|
||||||
|
libab_ref temp;
|
||||||
|
libab_ref new_type;
|
||||||
|
for(i = 0; i < to_resolve->children.size && result == LIBAB_SUCCESS; i++) {
|
||||||
|
libab_ref_vec_index(&to_resolve->children, i, &temp);
|
||||||
|
result = libab_resolve_parsetype_copy(libab_ref_get(&temp), scope, &new_type);
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
libab_ref_vec_insert(&parsetype->children, &new_type);
|
||||||
|
}
|
||||||
|
libab_ref_free(&new_type);
|
||||||
|
libab_ref_free(&temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != LIBAB_SUCCESS) {
|
||||||
|
libab_ref_vec_free(&parsetype->children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result == LIBAB_SUCCESS) {
|
||||||
|
result = libab_ref_new(into, parsetype, libab_free_parsetype);
|
||||||
|
if(result != LIBAB_SUCCESS) libab_parsetype_free(parsetype);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != LIBAB_SUCCESS) {
|
||||||
free(parsetype);
|
free(parsetype);
|
||||||
|
libab_ref_null(into);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
|
libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
|
||||||
@@ -114,7 +171,7 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result == LIBAB_SUCCESS) {
|
if (result == LIBAB_SUCCESS) {
|
||||||
result = libab_ref_new(into, parsetype, _libab_parsetype_free);
|
result = libab_ref_new(into, parsetype, libab_free_parsetype);
|
||||||
if (result != LIBAB_SUCCESS) {
|
if (result != LIBAB_SUCCESS) {
|
||||||
libab_parsetype_free(parsetype);
|
libab_parsetype_free(parsetype);
|
||||||
}
|
}
|
||||||
@@ -130,21 +187,40 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _free_table(void* data) {
|
void _gc_visit_table_entry(libab_table_entry* entry, libab_visitor_function_ptr visitor, void* data) {
|
||||||
libab_table_free(data);
|
if (entry->variant == ENTRY_VALUE) {
|
||||||
free(data);
|
libab_gc_visit(&entry->data_u.value, visitor, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
libab_result libab_create_table(libab_ref* into, libab_ref* parent) {
|
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)))) {
|
||||||
libab_table_init(table);
|
libab_table_init(table);
|
||||||
libab_table_set_parent(table, parent);
|
libab_table_set_parent(table, parent);
|
||||||
result = libab_ref_new(into, table, _free_table);
|
result = libab_ref_new(into, table, libab_free_table);
|
||||||
|
|
||||||
if (result != LIBAB_SUCCESS) {
|
if (result != LIBAB_SUCCESS) {
|
||||||
_free_table(table);
|
libab_free_table(table);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = LIBAB_MALLOC;
|
result = LIBAB_MALLOC;
|
||||||
@@ -152,25 +228,27 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _free_value(void* value) {
|
void _gc_visit_value_children(void* val, libab_visitor_function_ptr visitor, void* data) {
|
||||||
libab_value_free(value);
|
libab_value* value = val;
|
||||||
free(value);
|
libab_gc_visit(&value->data, visitor, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
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)))) {
|
||||||
libab_value_init_ref(value, data, type);
|
libab_value_init_ref(value, data, type);
|
||||||
result = libab_ref_new(into, value, _free_value);
|
result = libab_ref_new(into, value, libab_free_value);
|
||||||
|
|
||||||
if (result != LIBAB_SUCCESS) {
|
if (result != LIBAB_SUCCESS) {
|
||||||
_free_value(value);
|
libab_free_value(value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = LIBAB_MALLOC;
|
result = LIBAB_MALLOC;
|
||||||
@@ -178,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;
|
||||||
|
|
||||||
@@ -194,7 +274,7 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result == LIBAB_SUCCESS) {
|
if (result == LIBAB_SUCCESS) {
|
||||||
result = libab_ref_new(into, value, _free_value);
|
result = libab_ref_new(into, value, libab_free_value);
|
||||||
if (result != LIBAB_SUCCESS) {
|
if (result != LIBAB_SUCCESS) {
|
||||||
libab_value_free(value);
|
libab_value_free(value);
|
||||||
}
|
}
|
||||||
@@ -203,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) {
|
||||||
@@ -231,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) {
|
||||||
@@ -259,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) {
|
||||||
@@ -287,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;
|
||||||
|
|
||||||
@@ -314,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;
|
||||||
@@ -341,6 +551,22 @@ libab_result libab_put_table_value(libab_table* table, const char* key,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libab_basetype* libab_get_basetype(libab_parsetype* type, libab_table* scope) {
|
||||||
|
libab_ref type_param;
|
||||||
|
libab_basetype* to_return;
|
||||||
|
if(type->variant & LIBABACUS_TYPE_F_RESOLVED) {
|
||||||
|
to_return = type->data_u.base;
|
||||||
|
} else {
|
||||||
|
to_return = libab_table_search_basetype(scope, type->data_u.name);
|
||||||
|
if(to_return == NULL) {
|
||||||
|
libab_table_search_type_param(scope, type->data_u.name, &type_param);
|
||||||
|
to_return = ((libab_parsetype*)libab_ref_get(&type_param))->data_u.base;
|
||||||
|
libab_ref_free(&type_param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return to_return;
|
||||||
|
}
|
||||||
|
|
||||||
void* libab_unwrap_value(libab_ref* ref) {
|
void* libab_unwrap_value(libab_ref* ref) {
|
||||||
libab_value* value = libab_ref_get(ref);
|
libab_value* value = libab_ref_get(ref);
|
||||||
return libab_ref_get(&value->data);
|
return libab_ref_get(&value->data);
|
||||||
@@ -354,3 +580,35 @@ void* libab_unwrap_param(libab_ref_vec* vec, size_t index) {
|
|||||||
libab_ref_free(&temp);
|
libab_ref_free(&temp);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void libab_sanitize(char* to, const char* from, size_t buffer_size) {
|
||||||
|
size_t index = 0;
|
||||||
|
while (*from && index < (buffer_size - 2)) {
|
||||||
|
if (*from == '+' || *from == '*' || *from == '\\' ||
|
||||||
|
*from == '|' || *from == '[' || *from == ']' || *from == '(' ||
|
||||||
|
*from == ')' || *from == '.')
|
||||||
|
to[index++] = '\\';
|
||||||
|
to[index++] = *(from++);
|
||||||
|
}
|
||||||
|
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