Compare commits

...

66 Commits

Author SHA1 Message Date
06f17f491c Move variable setting code into utilities. 2018-09-13 23:57:33 -07:00
ca6075e8d5 Add a new method call operator, and more.
The '.' operator now represents method calls. A function f: (a, b)->c
can be called as a.f(b), which is equivalent to f(a, b). Besides
this change, all reserved operators now have a negative precedence
(it's relative, remember?), and some function names were changed.
2018-09-13 17:05:39 -07:00
4425b27b52 Make overloading code a utility function and call from interpreter.
This fixes #10.
2018-09-13 16:09:04 -07:00
25dd70f040 Fix segmentation fault during type initialization. 2018-09-13 15:08:57 -07:00
5617484aff Make parsing function public.
libab already provides a _run_tree ... you can't run_tree if there's
no tree.
2018-09-12 14:43:43 -07:00
b311c854ee Fix segmentation fault on function parsing error. 2018-09-12 14:32:28 -07:00
c4a7117704 Ensure operator does not try to take ownership of string. 2018-08-22 17:45:45 -07:00
899ac31210 Add a README. 2018-08-20 00:00:02 -07:00
01720914e0 Fix bug in table lookups. 2018-08-18 17:30:33 -07:00
8c9acafc93 Fix bug in shunting yard implementation. 2018-08-17 19:10:48 -07:00
37593abe40 Fix GC bug in overloaded functions. 2018-08-14 18:51:00 -07:00
0065fe5e65 Add utility functions to create libab instances on the heap. 2018-08-12 00:46:37 -07:00
de0ad13785 Remove function call prints from interactive. 2018-08-11 22:42:36 -07:00
3d0e4776fc Fix bugs related to partial application types. 2018-08-11 22:26:11 -07:00
3fc7f46680 Increment tree refcount. 2018-08-11 21:19:02 -07:00
cf57c4a29a Remove deliberate memory leak.
It was used to test the GC.
2018-08-11 20:29:08 -07:00
59b03d0a94 Fix partial application memory leak. 2018-08-11 20:27:52 -07:00
ffcbab9d94 Remove unused files. 2018-08-11 20:11:32 -07:00
8847643c2e Merge branch 'gc' 2018-08-11 20:09:56 -07:00
76ea606099 Finish basic implementation of garbage collection. 2018-08-11 20:01:43 -07:00
f4ecb82c46 Intermediate commit before visitor refactor. 2018-08-11 18:22:18 -07:00
80e7c95915 Make small adjustments to GC functions. 2018-08-11 16:00:00 -07:00
f257d0b2de Remove freed refcount from any list it's part of. 2018-08-11 01:42:30 -07:00
9eae28928a Move GC code to separate source file. 2018-08-11 01:40:30 -07:00
ec2421e5d7 Begin working on a garbage collector. 2018-08-11 01:29:48 -07:00
0b7b49d03d Fix memory leak caused by not freeing type. 2018-08-11 00:42:15 -07:00
512d68000f Link math library for atan2 and atan 2018-08-11 00:41:39 -07:00
71b6092654 Implement do ... while. 2018-08-10 20:06:02 -07:00
20fb078ad2 Change assignment behavior to update existing table entries. 2018-08-10 19:56:46 -07:00
d7ef8e236d Add more specific lookup functions. 2018-08-10 19:47:11 -07:00
450d12dc43 Add an equality function. 2018-08-10 19:21:55 -07:00
0824dee594 Add a while loop. 2018-08-10 19:16:47 -07:00
0a21c7fdf7 Add logical and and logical or operators. 2018-08-10 18:40:31 -07:00
aebba42196 Use the new public functions. 2018-08-10 18:40:21 -07:00
4a058384c1 Make some functions public. 2018-08-10 18:39:26 -07:00
b0c2eb5a5e Maintain the promise that references are null-ed on error. 2018-08-10 17:31:02 -07:00
3c0648e473 Fix the assumption that the stack only has infix operators. 2018-08-10 17:20:14 -07:00
8192d767f2 Add macro for declaring functions. 2018-08-10 16:59:44 -07:00
416686ca72 Add boolean logic functions and operators. 2018-08-10 16:54:53 -07:00
fdca2a8ca7 Add more sanitizing characters. 2018-08-10 16:54:39 -07:00
d0615d2c3e Implement the if statement. 2018-08-10 16:34:28 -07:00
b1ab168907 Do not exit on absence of print function. 2018-08-10 16:15:58 -07:00
3b79b5751a Add true and false keywords to the parser. 2018-08-10 16:06:30 -07:00
7c8c547540 Add true / false values to interpreter. 2018-08-10 15:29:56 -07:00
25f5d3469b Add a boolean type. 2018-08-10 00:52:12 -07:00
6b331cc3c4 Report error code from function call. 2018-06-22 00:44:59 -07:00
4540559097 Roll back incorrect bugfix. 2018-06-21 19:22:29 -07:00
48300cd86e Implement reserved operators. 2018-06-21 19:00:45 -07:00
a5429ae2c8 Maintain scope between lines executed. 2018-06-21 17:23:34 -07:00
03577269f2 Add various ways to call code. 2018-06-21 17:06:53 -07:00
7dfc55154e Require scope in interpreter calls. 2018-06-21 16:11:39 -07:00
13ccea10e4 Add scope to internal functions. 2018-06-21 14:25:11 -07:00
82747eae6a Output error codes. 2018-06-20 13:55:28 -07:00
6822c97750 Properly handle placeholder types. 2018-06-17 20:21:40 -07:00
827dba9013 Add the libab prefix to free functions. 2018-06-17 19:43:18 -07:00
f83b7d169c Resolve function types when they're created. 2018-06-17 19:01:15 -07:00
b9b6a8ec4b Get basetype from table or type parameters if not resolved. 2018-06-17 18:20:40 -07:00
05586069a7 Remove function resolving code. It will not be used. 2018-06-17 17:13:11 -07:00
22b738a4f0 Add code to call tree functions. 2018-06-17 02:03:34 -07:00
88ec979ba5 Add scope modes instead of a flag. 2018-06-17 01:25:41 -07:00
763cfdd7a3 Search scope as well as type map for type parameters. 2018-06-17 00:12:51 -07:00
065554bcdf Store type parameters into table during call. 2018-06-16 23:40:32 -07:00
27c79d44f5 Add a foreach function to ref_trie. 2018-06-16 20:51:54 -07:00
28f7cd1b30 Add creating tree functions. 2018-06-15 22:56:56 -07:00
695fbed235 Put free functions into common header / source file. 2018-06-15 22:54:58 -07:00
1158b29c1b Remove currently unused file. 2018-06-15 16:53:13 -07:00
31 changed files with 1959 additions and 343 deletions

View File

@@ -8,7 +8,7 @@ project(libabacus)
add_compile_options(-pedantic -Wall)
add_library(abacus STATIC src/lexer.c src/util.c src/table.c src/parser.c src/libabacus.c src/tree.c src/debug.c src/parsetype.c src/reserved.c src/trie.c src/refcount.c src/ref_vec.c src/ref_trie.c src/basetype.c src/value.c src/custom.c src/interpreter.c src/function_list.c)
add_library(abacus STATIC src/lexer.c src/util.c src/table.c src/parser.c src/libabacus.c src/tree.c src/debug.c src/parsetype.c src/reserved.c src/trie.c src/refcount.c src/ref_vec.c src/ref_trie.c src/basetype.c src/value.c src/custom.c src/interpreter.c src/function_list.c src/free_functions.c src/gc.c)
add_executable(libabacus src/main.c)
add_executable(interactive src/interactive.c)
add_subdirectory(external/liblex)
@@ -20,4 +20,4 @@ target_include_directories(libabacus PUBLIC include)
target_link_libraries(abacus lex)
target_link_libraries(libabacus abacus)
target_link_libraries(interactive abacus)
target_link_libraries(interactive abacus m)

74
README.md Normal file
View File

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

View File

@@ -11,7 +11,7 @@ struct libab_s;
* A function pointer that is called
* 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
@@ -135,8 +135,9 @@ void libab_behavior_free(libab_behavior* behavior);
* @param associativity the associativity (left = -1, right = 1) of the
* operator.
* @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);
/**
* Frees the given operator.

48
include/free_functions.h Normal file
View 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
View File

@@ -0,0 +1,56 @@
#ifndef LIBABACUS_GC_H
#define LIBABACUS_GC_H
#include "refcount.h"
#include "gc_functions.h"
/**
* Struct used to create an interface
* for a set of objects to be collected.
*/
struct libab_gc_list_s {
/**
* The head sentinel node.
*/
struct libab_ref_count_s head_sentinel;
/**
* The tail sentinel node.
*/
struct libab_ref_count_s tail_sentinel;
};
typedef struct libab_gc_list_s libab_gc_list;
/**
* Initializes a garbage collection tracking list.
* @param list the list to initialize.
*/
void libab_gc_list_init(libab_gc_list* list);
/**
* Visits the children of the current node, applying the given function to them.
* @param ref the reference whose children to visit.
* @param visitor the function to call for each child.
* @param data the data to pass to the visitor.
*/
void libab_gc_visit_children(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data);
/**
* Applies the given visitor function to this reference.
*/
void libab_gc_visit(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data);
/**
* Adds the given reference to the given garbage collection list,
* and specifies a function used to reach its children.
* @param ref the reference whose children to visit.
* @param visit_children the function used to reach the chilren of this reference.
* @param list the list to which to add the reference.
*/
void libab_gc_add(struct libab_ref_s* ref,
libab_visit_function_ptr visit_children,
libab_gc_list* list);
/**
* Performs garbage collection on a given list of container objects/
* @param list the list to run collection on.
*/
void libab_gc_run(libab_gc_list* list);
#endif

10
include/gc_functions.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef LIBABACUS_GC_FUNCTIONS_H
#define LIBABACUS_GC_FUNCTIONS_H
struct libab_ref_count_s;
struct libab_ref_s;
typedef void (*libab_visitor_function_ptr)(struct libab_ref_count_s* , void*);
typedef void (*libab_visit_function_ptr)(void*, libab_visitor_function_ptr, void*);
#endif

View File

@@ -8,6 +8,16 @@
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
* any interpreter-specific data.
@@ -18,8 +28,17 @@ struct libab_interpreter_s {
* The unit value, which doesn't need more than one instance.
*/
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;
/**
@@ -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.
* @param intr the interpreter to use to run the code.
* @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
* stored.
* @return the result of the execution.
*/
libab_result libab_interpreter_run(libab_interpreter* intr, libab_tree* tree,
libab_ref* scope,
libab_interpreter_scope_mode mode,
libab_ref* into);
/**
* Calls a function 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_run_function(libab_interpreter* intr,
libab_result libab_interpreter_call_function(libab_interpreter* intr,
libab_ref* scope,
const char* function,
libab_ref_vec* params,
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.
* @param intr the interpreter from which to get 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);
/**
* 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.
* @param intr the interpreter to free.

View File

@@ -60,6 +60,8 @@ enum libab_lexer_token_e {
TOKEN_OP_PREFIX,
TOKEN_OP_POSTFIX,
TOKEN_OP_RESERVED,
TOKEN_KW_TRUE,
TOKEN_KW_FALSE,
TOKEN_KW_IF,
TOKEN_KW_ELSE,
TOKEN_KW_WHILE,

View File

@@ -9,6 +9,7 @@
#include "parser.h"
#include "result.h"
#include "table.h"
#include "gc.h"
/**
* The main struct of libabacus,
@@ -47,6 +48,10 @@ struct libab_s {
* The number type instance.
*/
libab_ref type_num;
/**
* The boolean type instance.
*/
libab_ref type_bool;
/**
* The function list type instance.
*/
@@ -55,6 +60,12 @@ struct libab_s {
* The unit type instance.
*/
libab_ref type_unit;
/**
* List of containers references
* that should be tracked by the
* garbage collector for cycles.
*/
libab_gc_list containers;
/**
* Internal; the number basetype. This cannot be a static
@@ -144,6 +155,12 @@ libab_result libab_create_type(libab* ab, libab_ref* into, const char* type);
* @return the num basetype.
*/
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.
* @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.
*/
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.
* @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.
*/
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.
* @param ab the libabacus instance to use for executing code.
@@ -197,17 +247,55 @@ void libab_get_unit_value(libab* ab, libab_ref* into);
* @return the result of the computation.
*/
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.
* @param ab the libabacus instance to use to call the function.
* @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.
* @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,
size_t param_count, ...);
/**
* Releases all the resources allocated by libabacus.

View File

@@ -3,6 +3,7 @@
#include "refcount.h"
#include "result.h"
#include <stdarg.h>
/**
* 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,
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
* the values stored inside.

View File

@@ -2,6 +2,7 @@
#define LIBABACUS_REFCOUNT_H
#include "result.h"
#include "gc_functions.h"
/**
* A struct for holding
@@ -10,6 +11,10 @@
* to free the value.
*/
struct libab_ref_count_s {
/**
* The value this reference holds.
*/
void* data;
/**
* The fucntion to free the value.
* Can be NULL for no-op.
@@ -25,6 +30,26 @@ struct libab_ref_count_s {
* that still exist, even to a freed instance.
*/
int weak;
/**
* The number of outside references.
* This is used for garbage collection.
*/
int gc;
/**
* Previous pointer for garbage collection
* linked list.
*/
struct libab_ref_count_s* prev;
/**
* Next pointer for garbage collection
* linked list.
*/
struct libab_ref_count_s* next;
/**
* Function used to visit child containers,
* used by GC.
*/
libab_visit_function_ptr visit_children;
};
/**
@@ -44,10 +69,6 @@ struct libab_ref_s {
* of how many references are pointing to the value.
*/
struct libab_ref_count_s* count;
/**
* The value this reference holds.
*/
void* data;
};
typedef struct libab_ref_s libab_ref;

View File

@@ -23,6 +23,11 @@ struct libab_reserved_operator_s {
* The associativity of this operator.
*/
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;

View File

@@ -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,
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
* 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,
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.
* @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,
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 string the key ot search for.
* @param string the key to search for.
* @param ref the reference to store the type into.
*/
void libab_table_search_type_param(libab_table* table, const char* string,
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.
* @param table the table to store the entry into.

View File

@@ -19,6 +19,8 @@ enum libab_tree_variant_e {
TREE_POSTFIX_OP,
TREE_BLOCK,
TREE_VOID,
TREE_TRUE,
TREE_FALSE,
TREE_IF,
TREE_WHILE,
TREE_DOWHILE,

View File

@@ -7,6 +7,7 @@
#include "parsetype.h"
#include "result.h"
#include "table.h"
#include "libabacus.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 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);
/**
* 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.
* @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, ...);
/**
* Creates a new libab_table, and stores it into the given reference.
* @param ab the libabacus instance in which the table is being created.
* @param into the reference to store the table into.
* @param parent the parent reference to store.
* @return the result of the instantiation.
*/
libab_result libab_create_table(libab_ref* into, libab_ref* parent);
libab_result libab_create_table(libab* ab, libab_ref* into, libab_ref* parent);
/**
* Allocates a new reference counted value with the given type and data.
* @param into the reference to store the allocated data into.
@@ -80,8 +92,8 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent);
* @param type the type to give the value.
* @return the result of necessary allocations.
*/
libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
libab_ref* type);
libab_result libab_create_value_ref(libab* ab, libab_ref* into,
libab_ref* data, libab_ref* type);
/**
* Allocates a new reference counted value with the given type and data.
* @param into the reference to store the allocated data into.
@@ -89,8 +101,30 @@ libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
* @param type the type to give the value.
* @return the result of necessary allocations.
*/
libab_result libab_create_value_raw(libab_ref* into, void* data,
libab_ref* type);
libab_result libab_create_value_raw(libab* ab, libab_ref* into,
void* data, libab_ref* type);
/**
* 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.
* @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.
* @return libab_result the result of any necessary allocations.
*/
libab_result libab_create_function_internal(libab_ref* into,
libab_result libab_create_function_internal(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_function_ptr fun,
libab_ref* scope);
@@ -111,7 +145,7 @@ libab_result libab_create_function_internal(libab_ref* into,
* @param scope the scope in which this function was declared.
* @return libab_result the result of any necessary allocations.
*/
libab_result libab_create_function_tree(libab_ref* into,
libab_result libab_create_function_tree(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_tree* tree,
libab_ref* scope);
@@ -123,7 +157,7 @@ libab_result libab_create_function_tree(libab_ref* into,
* @param scope the scope in which this function was declared.
* @return libab_result the result of any necessary allocations.
*/
libab_result libab_create_function_behavior(libab_ref* into,
libab_result libab_create_function_behavior(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_behavior* behavior,
libab_ref* scope);
@@ -133,7 +167,7 @@ libab_result libab_create_function_behavior(libab_ref* into,
* @param the function_list type.
* @return the result of the allocations.
*/
libab_result libab_create_function_list(libab_ref* into, libab_ref* type);
libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* type);
/**
* Creates a new table entry that holds the given value.
* @param table the table to store the entry into.
@@ -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_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.
* 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.
*/
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

View File

@@ -1,4 +1,5 @@
#include "custom.h"
#include "util.h"
void libab_behavior_init_internal(libab_behavior* behavior,
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) {
into->variant = behavior->variant;
into->data_u = behavior->data_u;
if(into->variant == BIMPL_TREE) {
into->data_u.tree->int_value++;
}
}
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) {
libab_result result = LIBAB_SUCCESS;
char* into;
op->variant = variant;
op->precedence = precedence;
op->associativity = associativity;
op->function = function;
result = libab_copy_string(&into, function);
op->function = into;
return result;
}
void libab_operator_free(libab_operator* op) {
free((char*) op->function);
}
libab_result _function_init(libab_function* function, libab_ref* scope) {

34
src/free_functions.c Normal file
View 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
View File

@@ -0,0 +1,102 @@
#include "gc.h"
#include "refcount.h"
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
void libab_gc_list_init(libab_gc_list* list) {
memset(&list->head_sentinel, 0, sizeof(list->head_sentinel));
memset(&list->tail_sentinel, 0, sizeof(list->tail_sentinel));
list->head_sentinel.next = &list->tail_sentinel;
list->tail_sentinel.prev = &list->head_sentinel;
}
void _gc_count_visit_children(libab_ref_count* ref, libab_visitor_function_ptr func, void* data) {
if(ref->strong && ref->visit_children) ref->visit_children(ref->data, func, data);
}
void libab_gc_visit_children(libab_ref* ref, libab_visitor_function_ptr func, void* data) {
if(!ref->null) _gc_count_visit_children(ref->count, func, data);
}
void libab_gc_visit(struct libab_ref_s* ref, libab_visitor_function_ptr visitor, void* data) {
if(!ref->null) {
visitor(ref->count, data);
}
}
void _libab_gc_list_append(libab_gc_list* list,
libab_ref_count* node) {
libab_ref_count* before;
if(node->next) node->next->prev = node->prev;
if(node->prev) node->prev->next = node->next;
before = &list->tail_sentinel;
node->next = before;
node->prev = before->prev;
before->prev->next = node;
before->prev = node;
}
void libab_gc_add(libab_ref* ref,
libab_visit_function_ptr visit_children,
libab_gc_list* list) {
ref->count->visit_children = visit_children;
_libab_gc_list_append(list, ref->count);
}
void _gc_decrement(libab_ref_count* count, void* data) {
if(count->visit_children) count->gc--;
}
void _gc_save(libab_ref_count* count, void* data) {
libab_gc_list* list = data;
if(count->visit_children && count->gc >= 0) {
count->gc = -1;
_libab_gc_list_append(list, count);
_gc_count_visit_children(count, _gc_save, data);
}
}
void libab_gc_run(libab_gc_list* list) {
libab_gc_list safe;
libab_ref_count* head;
#define ITERATE(CODE) head = list->head_sentinel.next; \
while(head != &list->tail_sentinel) { \
libab_ref_count* node = head; \
CODE;\
head = head->next; \
}
libab_gc_list_init(&safe);
ITERATE(node->gc = node->weak);
ITERATE(_gc_count_visit_children(node, _gc_decrement, NULL));
head = list->head_sentinel.next;
while(head != &list->tail_sentinel) {
if(head->gc > 0) {
_gc_save(head, &safe);
head = &list->head_sentinel;
}
head = head->next;
}
ITERATE(
node->weak = -1;
node->strong = -1;
if(node->free_func) node->free_func(node->data);
);
while ((head = list->head_sentinel.next) != &list->tail_sentinel) {
head->prev->next = head->next;
head->next->prev = head->prev;
free(head);
}
if(safe.head_sentinel.next != &safe.tail_sentinel) {
list->head_sentinel.next = safe.head_sentinel.next;
list->head_sentinel.next->prev = &list->head_sentinel;
list->tail_sentinel.prev = safe.tail_sentinel.prev;
list->tail_sentinel.prev->next = &list->tail_sentinel;
} else {
list->head_sentinel.next = &list->tail_sentinel;
list->tail_sentinel.prev = &list->head_sentinel;
}
}

View File

@@ -7,6 +7,10 @@
#define TRY(expression) \
if (result == LIBAB_SUCCESS) \
result = expression;
#define FUNCTION(name) \
libab_result function_##name (libab* ab, libab_ref* scope, \
libab_ref_vec* params, libab_ref* into)
#define INTERACTIONS 5
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));
if(new_double) {
*new_double = val;
result = libab_create_value_raw(into, new_double, &type_num);
result = libab_create_value_raw(ab, into, new_double, &type_num);
if(result != LIBAB_SUCCESS) {
free(new_double);
}
@@ -38,38 +42,77 @@ libab_result create_double_value(libab* ab, double val, libab_ref* into) {
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);
return create_double_value(ab, atan(*val), into);
}
libab_result function_atan2(libab* ab, libab_ref_vec* params, libab_ref* into) {
printf("atan2 called\n");
FUNCTION(atan2) {
double* left = libab_unwrap_param(params, 0);
double* right = libab_unwrap_param(params, 1);
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);
printf("%f\n", *param);
libab_get_unit_value(ab, into);
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");
libab_get_unit_value(ab, into);
return LIBAB_SUCCESS;
}
#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; \
double right; \
double left; \
printf(#name " called\n"); \
left = *((double*)libab_unwrap_param(params, 0)); \
right = *((double*)libab_unwrap_param(params, 1)); \
create_double_value(ab, expression, into); \
@@ -88,12 +131,20 @@ libab_result register_functions(libab* ab) {
libab_ref difficult_type;
libab_ref print_num_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");
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, &print_num_type, "(num)->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, "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, "times", &atan2_type, function_times));
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_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, "minus"));
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, "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(&atan2_type);
libab_ref_free(&difficult_type);
libab_ref_free(&equals_num_type);
libab_ref_free(&print_num_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;
}
int main() {
char input_buffer[2048];
int interaction_count = INTERACTIONS;
libab_ref eval_into;
libab_ref call_into;
libab_result result;
libab_result eval_result;
libab_ref scope;
libab ab;
if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) {
@@ -132,18 +222,12 @@ int main() {
}
result = register_functions(&ab);
while (interaction_count-- && result == LIBAB_SUCCESS) {
printf("(%d) > ", INTERACTIONS - interaction_count);
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) {
result = libab_create_table(&ab, &scope, &ab.table);
}
if(result == LIBAB_SUCCESS) {
loop(&ab, INTERACTIONS, &scope);
libab_ref_free(&scope);
}
libab_free(&ab);

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,8 @@ libab_result libab_lexer_init(libab_lexer* lexer) {
const char* words[] = {".",
"[a-zA-Z][a-zA-Z0-9_]*",
"[0-9]+(\\.[0-9]*)?",
"true",
"false",
"if",
"else",
"while",
@@ -18,9 +20,9 @@ libab_result libab_lexer_init(libab_lexer* lexer) {
"fun",
"return"};
libab_lexer_token tokens[] = {
TOKEN_CHAR, TOKEN_ID, TOKEN_NUM, TOKEN_KW_IF,
TOKEN_KW_ELSE, TOKEN_KW_WHILE, TOKEN_KW_DO, TOKEN_KW_ARROW,
TOKEN_KW_FUN, TOKEN_KW_RETURN };
TOKEN_CHAR, TOKEN_ID, TOKEN_NUM, TOKEN_KW_TRUE,
TOKEN_KW_FALSE, TOKEN_KW_IF, TOKEN_KW_ELSE, TOKEN_KW_WHILE,
TOKEN_KW_DO, TOKEN_KW_ARROW, TOKEN_KW_FUN, TOKEN_KW_RETURN};
const size_t count = sizeof(tokens) / sizeof(libab_lexer_token);
eval_config_init(&lexer->config);

View File

@@ -5,29 +5,18 @@
#include "util.h"
#include "value.h"
#include <stdlib.h>
#include "free_functions.h"
void _free_function_list(void* function_list) {
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 _basetype_function_list = {libab_free_function_list, NULL, 0};
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};
void _free_unit(void* unit) {
static libab_basetype _basetype_unit = { libab_free_unit, NULL, 0 };
}
static libab_basetype _basetype_unit = { _free_unit, NULL, 0 };
static libab_basetype _basetype_bool = { libab_free_bool, NULL, 0 };
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;
libab_ref null_ref;
libab_result result;
libab_gc_list_init(&ab->containers);
libab_ref_null(&null_ref);
libab_ref_null(&ab->type_num);
libab_ref_null(&ab->type_bool);
libab_ref_null(&ab->type_function_list);
libab_ref_null(&ab->type_unit);
ab->impl.parse_num = parse_function;
result = libab_create_table(&ab->table, &null_ref);
result = libab_create_table(ab, &ab->table, &null_ref);
if (result == LIBAB_SUCCESS) {
libab_ref_free(&ab->type_num);
libab_ref_free(&ab->type_bool);
libab_ref_free(&ab->type_function_list);
libab_ref_free(&ab->type_unit);
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) {
libab_ref_free(&ab->table);
libab_ref_free(&ab->type_num);
libab_ref_free(&ab->type_bool);
libab_ref_free(&ab->type_function_list);
libab_ref_free(&ab->type_unit);
@@ -92,16 +85,6 @@ libab_result libab_init(libab* ab, void* (*parse_function)(const char*),
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,
libab_function_ptr func) {
behavior->variant = BIMPL_INTERNAL;
@@ -119,14 +102,14 @@ libab_result _register_operator(libab* ab, const char* op,
if ((new_entry = malloc(sizeof(*new_entry)))) {
new_entry->variant = ENTRY_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);
} else {
result = LIBAB_MALLOC;
}
if (result == LIBAB_SUCCESS) {
_sanitize(op_buffer, op, 8);
libab_sanitize(op_buffer, op, 8);
result = libab_convert_lex_result(
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);
}
libab_result _create_value_function_internal(libab_ref* into, libab_ref* type,
libab_result _create_value_function_internal(libab* ab,
libab_ref* into, libab_ref* type,
libab_function_ptr func,
libab_ref* scope) {
libab_ref function_ref;
libab_result result =
libab_create_function_internal(&function_ref, _free_function, func, scope);
libab_create_function_internal(ab, &function_ref, libab_free_function, func, scope);
libab_ref_null(into);
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_create_value_ref(into, &function_ref, type);
result = libab_create_value_ref(ab, into, &function_ref, type);
}
libab_ref_free(&function_ref);
return result;
}
libab_result _create_value_function_list(libab_ref* into, libab_ref* type) {
libab_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_ref* type, libab_function_ptr func) {
libab_table_entry* existing_entry;
libab_ref function_value;
libab_result result =
_create_value_function_internal(&function_value, type, func, &ab->table);
_create_value_function_internal(ab, &function_value, type, func, &ab->table);
if (result == LIBAB_SUCCESS) {
existing_entry = libab_table_search_filter(
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_overload_function(ab, libab_ref_get(&ab->table), name, &function_value);
}
libab_ref_free(&function_value);
return result;
}
@@ -295,6 +203,7 @@ libab_result _prepare_types(libab* ab, void (*free_function)(void*)) {
ab->basetype_num.free_function = free_function;
libab_ref_null(&ab->type_num);
libab_ref_null(&ab->type_bool);
libab_ref_null(&ab->type_function_list);
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);
}
if (result == LIBAB_SUCCESS) {
libab_ref_free(&ab->type_bool);
result =
libab_instantiate_basetype(&_basetype_bool, &ab->type_bool, 0);
}
if (result == LIBAB_SUCCESS) {
libab_ref_free(&ab->type_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);
}
if(result == LIBAB_SUCCESS) {
result = libab_register_basetype(ab, "bool", &_basetype_bool);
}
if (result == LIBAB_SUCCESS) {
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) {
libab_ref_free(&ab->type_num);
libab_ref_free(&ab->type_bool);
libab_ref_free(&ab->type_function_list);
libab_ref_free(&ab->type_unit);
libab_ref_null(&ab->type_num);
libab_ref_null(&ab->type_bool);
libab_ref_null(&ab->type_function_list);
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);
}
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));
}
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_bool(libab* ab) { return &_basetype_bool; }
libab_basetype* libab_get_basetype_function(libab* ab) {
return &_basetype_function;
}
@@ -379,6 +302,10 @@ void libab_get_type_num(libab* ab, libab_ref* 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) {
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_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;
ll tokens;
libab_tree* root;
ll_init(&tokens);
libab_ref_null(value);
*into = NULL;
result = libab_lexer_lex(&ab->lexer, string, &tokens);
if (result == LIBAB_SUCCESS) {
result = libab_parser_parse(&ab->parser, &tokens, string, &root);
}
if (result == LIBAB_SUCCESS) {
libab_ref_free(value);
result = libab_interpreter_run(&ab->intr, root, value);
libab_tree_free_recursive(root);
if(result == LIBAB_SUCCESS) {
result = libab_parser_parse(&ab->parser, &tokens, string, into);
}
ll_foreach(&tokens, NULL, compare_always, libab_lexer_foreach_match_free);
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;
}
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, ...) {
libab_ref_vec params;
@@ -426,16 +386,10 @@ libab_result libab_run_function(libab* ab, const char* function,
va_start(args, param_count);
libab_ref_null(into);
result = libab_ref_vec_init(&params);
result = _handle_va_params(ab, &params, param_count, args);
if(result == LIBAB_SUCCESS) {
while(result == LIBAB_SUCCESS && param_count--) {
result = libab_ref_vec_insert(&params, va_arg(args, libab_ref*));
}
if(result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_interpreter_run_function(&ab->intr, function, &params, into);
}
libab_ref_free(into);
result = libab_interpreter_call_function(&ab->intr, &ab->table, function, &params, into);
libab_ref_vec_free(&params);
}
@@ -444,13 +398,60 @@ libab_result libab_run_function(libab* ab, const char* function,
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, &params, param_count, args);
if(result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_interpreter_call_function(&ab->intr, scope, function, &params, into);
libab_ref_vec_free(&params);
}
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 result = LIBAB_SUCCESS;
libab_table_free(libab_ref_get(&ab->table));
libab_ref_free(&ab->table);
libab_ref_free(&ab->type_num);
libab_ref_free(&ab->type_bool);
libab_ref_free(&ab->type_function_list);
libab_ref_free(&ab->type_unit);
libab_parser_free(&ab->parser);
libab_interpreter_free(&ab->intr);
return libab_lexer_free(&ab->lexer);
result = libab_lexer_free(&ab->lexer);
libab_gc_run(&ab->containers);
return result;
}

View File

@@ -406,6 +406,38 @@ libab_result _parse_void(struct parser_state* state, libab_tree** store_into) {
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 result = LIBAB_SUCCESS;
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;
int is_parenth, is_comma;
libab_tree* temp;
*store_into = NULL;
result = _parser_consume_type(state, TOKEN_KW_FUN);
if (result == LIBAB_SUCCESS) {
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);
} else if (_parser_is_type(state, TOKEN_KW_RETURN)) {
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 {
result = LIBAB_UNEXPECTED;
}
@@ -1019,15 +1056,16 @@ libab_result _parse_expression(struct parser_state* state,
while (result == LIBAB_SUCCESS && op_stack.tail &&
_parser_match_is_op(op_stack.tail->data)) {
_parser_find_operator_infix(state, op_stack.tail->data,
&other_operator);
libab_lexer_match* other_token = op_stack.tail->data;
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 ==
TOKEN_OP_PREFIX ||
if (other_token->type == TOKEN_OP_PREFIX ||
(operator.associativity == - 1 &&
operator.precedence <= other_operator.precedence) ||
(operator.associativity == 1 &&
operator.precedence<other_operator.precedence)) {
operator.precedence < other_operator.precedence)) {
libab_lexer_match* match = ll_poptail(&op_stack);
result = _parser_append_op_node(state, match, &out_stack);
} else {
@@ -1071,7 +1109,6 @@ libab_result _parse_expression(struct parser_state* state,
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_free(&op_stack);
ll_free(&out_stack);

View File

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

View File

@@ -134,6 +134,65 @@ void libab_ref_trie_get(const libab_ref_trie* trie, const char* key,
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) {
_libab_ref_trie_free(trie->head);
}

View File

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

View File

@@ -1,12 +1,175 @@
#include "reserved.h"
#include "string.h"
#include "util.h"
#include "value.h"
#include "libabacus.h"
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(&params);
} else {
result = LIBAB_BAD_CALL;
}
if(result == LIBAB_SUCCESS) {
free_params = 1;
result = libab_run_tree_scoped(ab, left, scope, &param);
if(result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &param);
}
libab_ref_free(&param);
}
for(; index < right->children.size - 1 && result == LIBAB_SUCCESS; index++) {
result = libab_run_tree_scoped(ab, vec_index(&right->children, index),
scope, &param);
if(result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &param);
}
libab_ref_free(&param);
}
if(result == LIBAB_SUCCESS) {
libab_ref_free(&callee);
result = libab_run_tree_scoped(ab, vec_index(&right->children, right->children.size - 1),
scope, &callee);
}
if(result == LIBAB_SUCCESS) {
result = libab_interpreter_call_value(&ab->intr, scope, &callee, &params, into);
} else {
libab_ref_null(into);
}
if(free_params) {
libab_ref_vec_free(&params);
}
libab_ref_free(&callee);
return result;
}
libab_result _expect_boolean(libab* ab, libab_ref* scope,
libab_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 */
-3, /* Lowest precedence */
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 libab_reserved_operator libab_reserved_operators[] = {{
"=", /* Assignment */
0, /* Lowest precedence */
1 /* Right associative, a = b = 6 should be a = (b = 6) */
}};
static const size_t element_count =
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 result = LIBAB_SUCCESS;
char buffer[16];
size_t 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(
&lexer->config, libab_reserved_operators[i].op, TOKEN_OP_RESERVED));
&lexer->config, buffer, TOKEN_OP_RESERVED));
}
return result;
}
libab_result libab_remove_reserved_operators(libab_lexer* lexer) {
libab_result result = LIBAB_SUCCESS;
char buffer[16];
size_t 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(
&lexer->config, libab_reserved_operators[i].op, TOKEN_OP_RESERVED));
&lexer->config, buffer, TOKEN_OP_RESERVED));
}
return result;
}

View File

@@ -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,
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;
if (type == OPERATOR_PREFIX) {
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) {
entry = libab_table_search_filter(table, string, NULL,
libab_table_compare_op_infix);
} else if (type == OPERATOR_PREFIX) {
} else if (type == OPERATOR_POSTFIX) {
entry = libab_table_search_filter(table, string, NULL,
libab_table_compare_op_postfix);
}
return entry ? &entry->data_u.op : NULL;
return entry;
}
libab_basetype* libab_table_search_basetype(libab_table* table,
const char* string) {
libab_table_entry* entry = libab_table_search_filter(
table, string, NULL, libab_table_compare_basetype);
libab_table_entry* entry =
libab_table_search_entry_basetype(table, string);
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,
libab_ref* ref) {
libab_table_entry* entry = libab_table_search_filter(
table, string, NULL, libab_table_compare_value);
libab_table_entry* entry =
libab_table_search_entry_value(table, string);
if (entry) {
libab_ref_copy(&entry->data_u.value, ref);
} else {
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,
libab_ref* ref) {
libab_table_entry* entry = libab_table_search_filter(
table, string, NULL, libab_table_compare_type_param);
libab_table_entry* entry =
libab_table_search_entry_type_param(table, string);
if (entry) {
libab_ref_copy(&entry->data_u.type_param, ref);
} else {
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_table_entry* entry) {

View File

@@ -20,7 +20,7 @@ int libab_tree_has_string(libab_tree_variant variant) {
int libab_tree_has_scope(libab_tree_variant variant) {
return variant == TREE_BASE || variant == TREE_BLOCK ||
variant == TREE_IF || variant == TREE_WHILE ||
variant == TREE_DOWHILE || variant == TREE_FUN;
variant == TREE_DOWHILE;
}
int libab_tree_has_type(libab_tree_variant variant) {

View File

@@ -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); }

View File

@@ -2,6 +2,8 @@
#include "value.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include "free_functions.h"
libab_result libab_convert_lex_result(liblex_result to_convert) {
libab_result result = LIBAB_SUCCESS;
@@ -44,7 +46,7 @@ libab_result _libab_check_parsetype(libab_parsetype* to_check) {
libab_result result = LIBAB_SUCCESS;
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_result result = LIBAB_SUCCESS;
int resolve_name, check_parents;
@@ -60,7 +62,7 @@ libab_result libab_resolve_parsetype(libab_parsetype* to_resolve,
if (resolve_name && result == LIBAB_SUCCESS) {
libab_basetype* basetype =
libab_table_search_basetype(scope, to_resolve->data_u.name);
libab_get_basetype(to_resolve, scope);
if (basetype) {
free(to_resolve->data_u.name);
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) {
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);
index++;
}
@@ -89,14 +91,69 @@ libab_result libab_resolve_parsetype(libab_parsetype* to_resolve,
return result;
}
void _libab_free_parsetype(void* parsetype) {
libab_parsetype_free(parsetype);
free(parsetype);
}
libab_result libab_resolve_parsetype_copy(libab_parsetype* to_resolve,
libab_table* scope,
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) {
libab_parsetype_free(parsetype);
free(parsetype);
if(result == LIBAB_SUCCESS) {
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);
libab_ref_null(into);
}
return result;
}
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) {
result = libab_ref_new(into, parsetype, _libab_parsetype_free);
result = libab_ref_new(into, parsetype, libab_free_parsetype);
if (result != LIBAB_SUCCESS) {
libab_parsetype_free(parsetype);
}
@@ -130,21 +187,40 @@ libab_result libab_instantiate_basetype(libab_basetype* to_instantiate,
return result;
}
void _free_table(void* data) {
libab_table_free(data);
free(data);
void _gc_visit_table_entry(libab_table_entry* entry, libab_visitor_function_ptr visitor, void* data) {
if (entry->variant == ENTRY_VALUE) {
libab_gc_visit(&entry->data_u.value, visitor, data);
}
}
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_result result = LIBAB_SUCCESS;
if ((table = malloc(sizeof(*table)))) {
libab_table_init(table);
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) {
_free_table(table);
libab_free_table(table);
}
} else {
result = LIBAB_MALLOC;
@@ -152,25 +228,27 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent) {
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
} else {
libab_gc_add(into, _gc_visit_table_children, &ab->containers);
}
return result;
}
void _free_value(void* value) {
libab_value_free(value);
free(value);
void _gc_visit_value_children(void* val, libab_visitor_function_ptr visitor, void* data) {
libab_value* value = val;
libab_gc_visit(&value->data, visitor, data);
}
libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
libab_ref* type) {
libab_result libab_create_value_ref(libab* ab, libab_ref* into,
libab_ref* data, libab_ref* type) {
libab_value* value;
libab_result result = LIBAB_SUCCESS;
if ((value = malloc(sizeof(*value)))) {
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) {
_free_value(value);
libab_free_value(value);
}
} else {
result = LIBAB_MALLOC;
@@ -178,12 +256,14 @@ libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
} else {
libab_gc_add(into, _gc_visit_value_children, &ab->containers);
}
return result;
}
libab_result libab_create_value_raw(libab_ref* into, void* data,
libab_ref* type) {
libab_result libab_create_value_raw(libab* ab, libab_ref* into,
void* data, libab_ref* type) {
libab_value* value;
libab_result result = LIBAB_SUCCESS;
@@ -194,7 +274,7 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
}
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) {
libab_value_free(value);
}
@@ -203,12 +283,125 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(value);
} else {
libab_gc_add(into, _gc_visit_value_children, &ab->containers);
}
return result;
}
libab_result libab_create_function_internal(libab_ref* into,
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*),
libab_function_ptr fun,
libab_ref* scope) {
@@ -231,12 +424,14 @@ libab_result libab_create_function_internal(libab_ref* into,
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
}
return result;
}
libab_result libab_create_function_tree(libab_ref* into,
libab_result libab_create_function_tree(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_tree* tree,
libab_ref* scope) {
@@ -259,12 +454,14 @@ libab_result libab_create_function_tree(libab_ref* into,
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
}
return result;
}
libab_result libab_create_function_behavior(libab_ref* into,
libab_result libab_create_function_behavior(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_behavior* behavior,
libab_ref* scope) {
@@ -287,12 +484,23 @@ libab_result libab_create_function_behavior(libab_ref* into,
if(result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
}
return result;
}
libab_result libab_create_function_list(libab_ref* into, libab_ref* type) {
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_result result = LIBAB_SUCCESS;
@@ -314,6 +522,8 @@ libab_result libab_create_function_list(libab_ref* into, libab_ref* type) {
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(list);
} else {
libab_gc_add(into, _gc_visit_function_list_children, &ab->containers);
}
return result;
@@ -341,6 +551,22 @@ libab_result libab_put_table_value(libab_table* table, const char* key,
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) {
libab_value* value = libab_ref_get(ref);
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);
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);
}