Compare commits

..

47 Commits

Author SHA1 Message Date
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
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
5492aa6f63 Change free condition for tree. 2018-06-13 23:28:42 -07:00
59f306f59e Avoid hard crashes due to unfinished interpreter function. 2018-06-13 23:28:33 -07:00
30 changed files with 1637 additions and 250 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)

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

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,21 +51,27 @@ 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_ref* scope,
const char* function,
libab_ref_vec* params,
libab_ref* into);
@@ -56,6 +81,18 @@ libab_result libab_interpreter_run_function(libab_interpreter* intr,
* @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,6 +211,26 @@ 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);
/**
* Executes the given string of code.
@@ -197,17 +240,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_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_run_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

@@ -0,0 +1,8 @@
#ifndef LIBABACUS_REFCOUNT_INTERNAL_H
#define LIBABACUS_REFCOUNT_INTERNAL_H
#include "refcount.h"
void libab_ref_count_changed(libab_ref_count* count);
#endif

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,8 @@ libab_result libab_create_value_ref(libab_ref* into, libab_ref* data,
* @param type the type to give the value.
* @return the result of necessary allocations.
*/
libab_result libab_create_value_raw(libab_ref* into, void* data,
libab_ref* type);
libab_result libab_create_value_raw(libab* ab, libab_ref* into,
void* data, libab_ref* type);
/**
* Allocates a function that uses internal code to run.
* @param into the reference into which to store the new function.
@@ -99,7 +111,7 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
* @param scope the scope in which this function was declared.
* @return libab_result the result of any necessary allocations.
*/
libab_result libab_create_function_internal(libab_ref* into,
libab_result libab_create_function_internal(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_function_ptr fun,
libab_ref* scope);
@@ -111,7 +123,7 @@ libab_result libab_create_function_internal(libab_ref* into,
* @param scope the scope in which this function was declared.
* @return libab_result the result of any necessary allocations.
*/
libab_result libab_create_function_tree(libab_ref* into,
libab_result libab_create_function_tree(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_tree* tree,
libab_ref* scope);
@@ -123,7 +135,7 @@ libab_result libab_create_function_tree(libab_ref* into,
* @param scope the scope in which this function was declared.
* @return libab_result the result of any necessary allocations.
*/
libab_result libab_create_function_behavior(libab_ref* into,
libab_result libab_create_function_behavior(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_behavior* behavior,
libab_ref* scope);
@@ -133,7 +145,7 @@ libab_result libab_create_function_behavior(libab_ref* into,
* @param the function_list type.
* @return the result of the allocations.
*/
libab_result libab_create_function_list(libab_ref* into, libab_ref* type);
libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* type);
/**
* Creates a new table entry that holds the given value.
* @param table the table to store the entry into.
@@ -143,6 +155,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 +180,12 @@ 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);
#endif

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

103
src/gc.c Normal file
View File

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

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,34 +42,76 @@ 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) {
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) {
printf("atan called\n");
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) {
FUNCTION(atan2) {
printf("atan2 called\n");
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; \
@@ -88,12 +134,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 +155,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(&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_run_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_ref test;
libab ab;
if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) {
@@ -132,18 +225,14 @@ 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_table_search_value(libab_ref_get(&scope), "test", &test);
printf("%p\n", libab_ref_get(&test));
libab_ref_free(&scope);
}
libab_free(&ab);

View File

@@ -1,16 +1,55 @@
#include "libabacus.h"
#include "util.h"
#include "value.h"
#include "free_functions.h"
#include "reserved.h"
libab_result _create_bool_value(libab* ab, int val, libab_ref* into) {
libab_ref type_bool;
int* new_bool;
libab_result result = LIBAB_SUCCESS;
libab_get_type_bool(ab, &type_bool);
new_bool = malloc(sizeof(*new_bool));
if(new_bool) {
*new_bool = val;
result = libab_create_value_raw(ab, into, new_bool, &type_bool);
if(result != LIBAB_SUCCESS) {
free(new_bool);
}
} else {
result = LIBAB_MALLOC;
libab_ref_null(into);
}
libab_ref_free(&type_bool);
return result;
}
libab_result libab_interpreter_init(libab_interpreter* intr, libab* ab) {
libab_result result;
libab_ref unit_data;
intr->ab = ab;
libab_ref_null(&intr->value_true);
libab_ref_null(&intr->value_false);
libab_ref_null(&unit_data);
result = libab_create_value_ref(&intr->value_unit, &unit_data, &ab->type_unit);
result = libab_create_value_ref(ab, &intr->value_unit, &unit_data, &ab->type_unit);
if(result == LIBAB_SUCCESS) {
libab_ref_free(&intr->value_true);
result = _create_bool_value(ab, 1, &intr->value_true);
}
if(result == LIBAB_SUCCESS) {
libab_ref_free(&intr->value_false);
result = _create_bool_value(ab, 0, &intr->value_false);
}
libab_ref_free(&unit_data);
if(result != LIBAB_SUCCESS) {
libab_ref_free(&intr->value_unit);
libab_ref_free(&intr->value_true);
libab_ref_free(&intr->value_false);
}
return result;
}
@@ -20,9 +59,10 @@ struct interpreter_state {
};
void _interpreter_init(struct interpreter_state* state,
libab_interpreter* intr) {
libab_interpreter* intr,
libab_ref* scope) {
state->ab = intr->ab;
state->base_table = libab_ref_get(&intr->ab->table);
state->base_table = libab_ref_get(scope);
}
void _interpreter_free(struct interpreter_state* state) {}
@@ -35,7 +75,7 @@ libab_result _interpreter_create_num_val(struct interpreter_state* state,
if ((data = state->ab->impl.parse_num(from))) {
libab_ref_free(into);
result = libab_create_value_raw(into, data, &state->ab->type_num);
result = libab_create_value_raw(state->ab, into, data, &state->ab->type_num);
if (result != LIBAB_SUCCESS) {
((libab_parsetype*)libab_ref_get(&state->ab->type_num))
@@ -73,6 +113,28 @@ int _interpreter_type_contains_placeholders(libab_ref* type) {
return placeholder;
}
void _interpreter_search_type_param(libab_ref_trie* params,
libab_ref* scope,
const char* name,
libab_ref* into) {
libab_ref_trie_get(params, name, into);
if(libab_ref_get(into) == NULL) {
libab_table_search_type_param(libab_ref_get(scope), name, into);
}
}
libab_parsetype* _interpreter_search_type_param_raw(libab_ref_trie* params,
libab_ref* scope,
const char* name) {
libab_ref into;
libab_parsetype* to_return;
_interpreter_search_type_param(params, scope, name, &into);
to_return = libab_ref_get(&into);
libab_ref_free(&into);
return to_return;
}
/**
* Compares the two types, filling in any missing type parameters
* in the respective type tries.
@@ -85,13 +147,13 @@ int _interpreter_type_contains_placeholders(libab_ref* type) {
libab_result _interpreter_compare_types(libab_ref* left_type,
libab_ref* right_type,
libab_ref_trie* left_params,
libab_ref_trie* right_params) {
libab_ref_trie* right_params,
libab_ref* scope) {
libab_result result = LIBAB_SUCCESS;
int left_placeholder;
int right_placeholder;
libab_parsetype* left = libab_ref_get(left_type);
libab_parsetype* right = libab_ref_get(right_type);
libab_ref param_type;
left_placeholder = left->variant & LIBABACUS_TYPE_F_PLACE;
right_placeholder = right->variant & LIBABACUS_TYPE_F_PLACE;
@@ -100,9 +162,7 @@ libab_result _interpreter_compare_types(libab_ref* left_type,
} else {
if (left_placeholder) {
const char* name = left->data_u.name;
libab_ref_trie_get(left_params, name, &param_type);
left = libab_ref_get(&param_type);
libab_ref_free(&param_type);
left = _interpreter_search_type_param_raw(left_params, scope, name);
if (left == NULL) {
if (!_interpreter_type_contains_placeholders(right_type)) {
result = libab_ref_trie_put(left_params, name, right_type);
@@ -112,9 +172,7 @@ libab_result _interpreter_compare_types(libab_ref* left_type,
}
} else if (right_placeholder) {
const char* name = right->data_u.name;
libab_ref_trie_get(right_params, name, &param_type);
right = libab_ref_get(&param_type);
libab_ref_free(&param_type);
right = _interpreter_search_type_param_raw(right_params, scope, name);
if (right == NULL) {
if (!_interpreter_type_contains_placeholders(left_type)) {
result = libab_ref_trie_put(right_params, name, left_type);
@@ -128,6 +186,7 @@ libab_result _interpreter_compare_types(libab_ref* left_type,
size_t index = 0;
libab_ref temp_left;
libab_ref temp_right;
result = (left->data_u.base == right->data_u.base)
? LIBAB_SUCCESS
: LIBAB_MISMATCHED_TYPE;
@@ -148,7 +207,7 @@ libab_result _interpreter_compare_types(libab_ref* left_type,
libab_ref_vec_index(&left->children, index, &temp_left);
libab_ref_vec_index(&right->children, index, &temp_right);
result = _interpreter_compare_types(
&temp_left, &temp_right, left_params, right_params);
&temp_left, &temp_right, left_params, right_params, scope);
libab_ref_free(&temp_left);
libab_ref_free(&temp_right);
}
@@ -159,11 +218,6 @@ libab_result _interpreter_compare_types(libab_ref* left_type,
return result;
}
void _free_parsetype(void* parsetype) {
libab_parsetype_free(parsetype);
free(parsetype);
}
/**
* Copies a type, substituting type parameters for their copies
* from the parameter trie.
@@ -174,6 +228,7 @@ void _free_parsetype(void* parsetype) {
*/
libab_result _interpreter_copy_resolved_type(libab_ref* type,
libab_ref_trie* params,
libab_ref* scope,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
libab_parsetype* copy;
@@ -181,7 +236,7 @@ libab_result _interpreter_copy_resolved_type(libab_ref* type,
original = libab_ref_get(type);
if (original->variant & LIBABACUS_TYPE_F_PLACE) {
libab_ref_trie_get(params, original->data_u.name, into);
_interpreter_search_type_param(params, scope, original->data_u.name, into);
} else if ((copy = malloc(sizeof(*copy)))) {
size_t index = 0;
copy->variant = original->variant;
@@ -194,7 +249,7 @@ libab_result _interpreter_copy_resolved_type(libab_ref* type,
index++) {
libab_ref_vec_index(&original->children, index, &temp_child);
result = _interpreter_copy_resolved_type(&temp_child, params,
&child_copy);
scope, &child_copy);
if (result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&copy->children, &child_copy);
}
@@ -208,9 +263,9 @@ libab_result _interpreter_copy_resolved_type(libab_ref* type,
}
if (result == LIBAB_SUCCESS) {
result = libab_ref_new(into, copy, _free_parsetype);
result = libab_ref_new(into, copy, libab_free_parsetype);
if (result != LIBAB_SUCCESS) {
_free_parsetype(copy);
libab_free_parsetype(copy);
}
}
}
@@ -234,10 +289,11 @@ libab_result _interpreter_copy_resolved_type(libab_ref* type,
*/
libab_result _interpreter_resolve_type_params(libab_ref* type,
libab_ref_trie* params,
libab_ref* scope,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
if (_interpreter_type_contains_placeholders(type)) {
result = _interpreter_copy_resolved_type(type, params, into);
result = _interpreter_copy_resolved_type(type, params, scope, into);
} else {
libab_ref_copy(type, into);
}
@@ -254,7 +310,9 @@ libab_result _interpreter_resolve_type_params(libab_ref* type,
*/
libab_result _interpreter_check_types(libab_ref_vec* reference_types,
libab_ref_vec* params,
libab_ref_vec* types) {
libab_ref_vec* types,
libab_ref* scope,
libab_ref_trie* param_map) {
libab_result result = LIBAB_SUCCESS;
libab_ref_trie function_params;
@@ -277,11 +335,11 @@ libab_result _interpreter_check_types(libab_ref_vec* reference_types,
right_temp =
&((libab_value*)libab_ref_get(&right_value_temp))->type;
result = _interpreter_compare_types(
&left_temp, right_temp, &function_params, &child_params);
&left_temp, right_temp, &function_params, &child_params, scope);
if (result == LIBAB_SUCCESS) {
result = _interpreter_resolve_type_params(
right_temp, &child_params, &produced_type);
right_temp, &child_params, scope, &produced_type);
if (result != LIBAB_SUCCESS) {
libab_ref_free(&produced_type);
}
@@ -299,9 +357,10 @@ libab_result _interpreter_check_types(libab_ref_vec* reference_types,
}
}
libab_ref_trie_free(&function_params);
if (result != LIBAB_SUCCESS) {
if(result == LIBAB_SUCCESS) {
*param_map = function_params;
} else {
libab_ref_trie_free(&function_params);
libab_ref_vec_clear(types);
}
@@ -320,23 +379,29 @@ libab_result _interpreter_check_types(libab_ref_vec* reference_types,
*/
libab_result _interpreter_find_match(libab_function_list* function_values,
libab_ref_vec* params,
libab_ref_vec* new_types, libab_ref* match,
libab_ref_vec* new_types,
libab_ref_trie* param_map,
libab_ref* match,
int partial) {
libab_result result = LIBAB_SUCCESS;
size_t index = 0;
size_t list_size = libab_function_list_size(function_values);
int found_match = 0;
libab_ref_trie temp_param_map;
libab_ref_vec temp_new_types;
libab_ref temp_function_value;
libab_value* temp_value;
libab_parsetype* temp_function_type;
libab_function* temp_function;
libab_ref_null(match);
result = libab_ref_vec_init(&temp_new_types);
for (; index < list_size && result == LIBAB_SUCCESS; index++) {
libab_function_list_index(function_values, index, &temp_function_value);
temp_function_type = libab_ref_get(
&((libab_value*)libab_ref_get(&temp_function_value))->type);
temp_value = libab_ref_get(&temp_function_value);
temp_function_type = libab_ref_get(&temp_value->type);
temp_function = libab_ref_get(&temp_value->data);
if (((temp_function_type->children.size == params->size + 1) &&
!partial) ||
@@ -344,7 +409,7 @@ libab_result _interpreter_find_match(libab_function_list* function_values,
partial)) {
/* We found a function that has the correct number of parameters. */
result = _interpreter_check_types(
&temp_function_type->children, params, &temp_new_types);
&temp_function_type->children, params, &temp_new_types, &temp_function->scope, &temp_param_map);
if (result == LIBAB_MISMATCHED_TYPE) {
/* Mismatch is OK. */
result = LIBAB_SUCCESS;
@@ -356,6 +421,7 @@ libab_result _interpreter_find_match(libab_function_list* function_values,
* new_types, and use new memory for temp list. */
found_match = 1;
*new_types = temp_new_types;
*param_map = temp_param_map;
libab_ref_free(match);
libab_ref_copy(&temp_function_value, match);
result = libab_ref_vec_init(&temp_new_types);
@@ -367,13 +433,17 @@ libab_result _interpreter_find_match(libab_function_list* function_values,
* initialized, and the call is ambigous. Free all data. */
libab_ref_vec_free(new_types);
libab_ref_vec_free(&temp_new_types);
libab_ref_trie_free(param_map);
libab_ref_trie_free(&temp_param_map);
result = LIBAB_AMBIGOUS_CALL;
}
} else {
/* Something bad happened. Free data as best as we can. */
libab_ref_vec_free(&temp_new_types);
if (found_match)
if (found_match) {
libab_ref_vec_free(new_types);
libab_ref_trie_free(param_map);
}
}
}
@@ -396,13 +466,14 @@ libab_result _interpreter_find_match(libab_function_list* function_values,
* @param type the new type.
* @param into the reference into which to store the new value.
*/
libab_result _interpreter_cast_param(libab_ref* param, libab_ref* type,
libab_result _interpreter_cast_param(libab* ab, libab_ref* param,
libab_ref* type,
libab_ref_vec* into) {
libab_result result = LIBAB_SUCCESS;
libab_value* old_value = libab_ref_get(param);
libab_ref new_value;
result = libab_create_value_ref(&new_value, &old_value->data, type);
result = libab_create_value_ref(ab, &new_value, &old_value->data, type);
if (result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(into, &new_value);
}
@@ -418,7 +489,8 @@ libab_result _interpreter_cast_param(libab_ref* param, libab_ref* type,
* @param into the pre-initialized vector to store the new values into.
* @return the result of any allocations.
*/
libab_result _interpreter_cast_params(libab_ref_vec* params,
libab_result _interpreter_cast_params(libab* ab,
libab_ref_vec* params,
libab_ref_vec* new_types,
libab_ref_vec* into) {
libab_result result = LIBAB_SUCCESS;
@@ -430,7 +502,7 @@ libab_result _interpreter_cast_params(libab_ref_vec* params,
libab_ref_vec_index(params, index, &temp_param);
libab_ref_vec_index(new_types, index, &temp_type);
result = _interpreter_cast_param(&temp_param, &temp_type, into);
result = _interpreter_cast_param(ab, &temp_param, &temp_type, into);
libab_ref_free(&temp_param);
libab_ref_free(&temp_type);
@@ -439,16 +511,48 @@ libab_result _interpreter_cast_params(libab_ref_vec* params,
return result;
}
libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
libab_ref* into, libab_ref* scope,
libab_interpreter_scope_mode scope_mode);
/**
* Calls a tree-based function with the given parameters.
* @param tree the tree function to call.
* @param the parameters to give to the function.
* @param scope the scope used for the call.
* @param into the reference to store the result into;
* @return the result of the call.
*/
libab_result _interpreter_call_tree(libab_tree* tree, libab_ref_vec* params,
libab_result _interpreter_call_tree(struct interpreter_state* state,
libab_tree* tree,
libab_ref_vec* params,
libab_ref* scope,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
libab_ref new_scope;
libab_tree* child;
libab_ref param;
libab_table* new_scope_raw;
size_t i;
libab_result result = libab_create_table(state->ab, &new_scope, scope);
if(result == LIBAB_SUCCESS) {
new_scope_raw = libab_ref_get(&new_scope);
for(i = 0; i < tree->children.size - 1 && result == LIBAB_SUCCESS; i++) {
child = vec_index(&tree->children, i);
libab_ref_vec_index(params, i, &param);
result = libab_put_table_value(new_scope_raw, child->string_value, &param);
libab_ref_free(&param);
}
}
if(result == LIBAB_SUCCESS) {
result = _interpreter_run(state,
vec_index(&tree->children, tree->children.size - 1),
into, &new_scope, SCOPE_NONE);
}
libab_ref_free(&new_scope);
return result;
}
@@ -463,12 +567,13 @@ libab_result _interpreter_call_tree(libab_tree* tree, libab_ref_vec* params,
libab_result _interpreter_call_behavior(struct interpreter_state* state,
libab_behavior* behavior,
libab_ref_vec* params,
libab_ref* scope,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
if (behavior->variant == BIMPL_INTERNAL) {
result = behavior->data_u.internal(state->ab, params, into);
result = behavior->data_u.internal(state->ab, scope, params, into);
} else {
result = _interpreter_call_tree(behavior->data_u.tree, params, into);
result = _interpreter_call_tree(state, behavior->data_u.tree, params, scope, into);
}
return result;
}
@@ -478,20 +583,24 @@ libab_result _interpreter_call_behavior(struct interpreter_state* state,
* @param function the function to copy.
* @param into the reference to store the copy into.
*/
libab_result _interpreter_copy_function_basic(libab_ref* function,
libab_result _interpreter_copy_function_basic(libab* ab,
libab_ref* function,
libab_ref* scope,
libab_ref* into) {
libab_function* func = libab_ref_get(function);
void (*free_function)(void*) = function->count->free_func;
return libab_create_function_behavior(into, free_function, &func->behavior, &func->scope);
return libab_create_function_behavior(ab, into, free_function, &func->behavior, scope);
}
libab_result _interpreter_copy_function_with_params(libab_ref* function,
libab_result _interpreter_copy_function_with_params(libab* ab,
libab_ref* function,
libab_ref_vec* params,
libab_ref* scope,
libab_ref* into) {
int index = 0;
libab_ref param;
libab_function* func;
libab_result result = _interpreter_copy_function_basic(function, into);
libab_result result = _interpreter_copy_function_basic(ab, function, scope, into);
func = libab_ref_get(into);
for(; index < params->size && result == LIBAB_SUCCESS; index++) {
@@ -555,6 +664,7 @@ libab_result _interpreter_copy_type_offset(libab_ref* type,
libab_result _interpreter_partially_apply(struct interpreter_state* state,
libab_ref* function,
libab_ref_vec* params,
libab_ref* scope,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
libab_value* value;
@@ -563,14 +673,14 @@ libab_result _interpreter_partially_apply(struct interpreter_state* state,
value = libab_ref_get(function);
libab_ref_null(&new_type);
result = _interpreter_copy_function_with_params(&value->data, params, &new_function);
result = _interpreter_copy_function_with_params(state->ab, &value->data, params, scope, &new_function);
if(result == LIBAB_SUCCESS) {
libab_ref_free(&new_type);
result = _interpreter_copy_type_offset(&value->type, 0, &new_type);
}
if(result == LIBAB_SUCCESS) {
result = libab_create_value_ref(into, &new_function, &new_type);
result = libab_create_value_ref(state->ab, into, &new_function, &new_type);
} else {
libab_ref_null(into);
}
@@ -581,6 +691,45 @@ libab_result _interpreter_partially_apply(struct interpreter_state* state,
return result;
}
libab_result _interpreter_foreach_insert_param(const libab_ref* param,
const char* key,
va_list args) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* entry;
if ((entry = malloc(sizeof(*entry)))) {
entry->variant = ENTRY_TYPE_PARAM;
libab_ref_copy(param, &entry->data_u.type_param);
} else {
result = LIBAB_MALLOC;
}
if(result == LIBAB_SUCCESS) {
result = libab_table_put(libab_ref_get(va_arg(args, libab_ref*)), key, entry);
if(result != LIBAB_SUCCESS) {
libab_ref_free(&entry->data_u.type_param);
free(entry);
}
}
return result;
}
libab_result _interpreter_create_scope(libab* ab,
libab_ref* into,
libab_ref* parent_scope,
libab_ref_trie* param_map) {
libab_result result = libab_create_table(ab, into, parent_scope);
if (result == LIBAB_SUCCESS) {
result = libab_ref_trie_foreach(param_map, _interpreter_foreach_insert_param, into);
if(result != LIBAB_SUCCESS) {
libab_ref_free(into);
libab_ref_null(into);
}
}
return result;
}
/**
* Calls a function with the given, compatible paramters.
* @param state the state to use to call the function.
@@ -592,21 +741,32 @@ libab_result _interpreter_partially_apply(struct interpreter_state* state,
libab_result _interpreter_perform_function_call(struct interpreter_state* state,
libab_ref* to_call,
libab_ref_vec* params,
libab_ref_trie* param_map,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
libab_value* function_value;
libab_function* function;
libab_parsetype* function_type;
libab_ref new_scope;
size_t new_params;
function_value = libab_ref_get(to_call);
function = libab_ref_get(&function_value->data);
function_type = libab_ref_get(&function_value->type);
new_params = params->size - function->params.size;
if (function_type->children.size - new_params == 1) {
result = _interpreter_call_behavior(state, &function->behavior, params, into);
result = _interpreter_create_scope(state->ab, &new_scope, &function->scope, param_map);
if(result != LIBAB_SUCCESS) {
libab_ref_null(into);
} else if (function_type->children.size - new_params == 1) {
result = _interpreter_call_behavior(state, &function->behavior, params, &new_scope, into);
} else {
result = _interpreter_partially_apply(state, to_call, params, into);
result = _interpreter_partially_apply(state, to_call, params, &new_scope, into);
}
libab_ref_free(&new_scope);
return result;
}
@@ -621,7 +781,9 @@ libab_result _interpreter_perform_function_call(struct interpreter_state* state,
*/
libab_result _interpreter_cast_and_perform_function_call(
struct interpreter_state* state,
libab_ref* to_call, libab_ref_vec* params, libab_ref_vec* new_types,
libab_ref* to_call, libab_ref_vec* params,
libab_ref_vec* new_types,
libab_ref_trie* param_map,
libab_ref* into) {
libab_result result;
libab_ref_vec new_params;
@@ -632,11 +794,11 @@ libab_result _interpreter_cast_and_perform_function_call(
function = libab_ref_get(&function_value->data);
result = libab_ref_vec_init_copy(&new_params, &function->params);
if (result == LIBAB_SUCCESS) {
result = _interpreter_cast_params(params, new_types, &new_params);
result = _interpreter_cast_params(state->ab, params, new_types, &new_params);
if (result == LIBAB_SUCCESS) {
result = _interpreter_perform_function_call(state, to_call,
&new_params, into);
&new_params, param_map, into);
}
libab_ref_vec_free(&new_params);
@@ -659,13 +821,14 @@ libab_result _interpreter_call_function_list(struct interpreter_state* state,
libab_result result = LIBAB_SUCCESS;
libab_ref_vec new_types;
libab_ref to_call;
libab_ref_trie param_map;
libab_ref_null(into);
result =
_interpreter_find_match(list, params, &new_types, &to_call, 0);
_interpreter_find_match(list, params, &new_types, &param_map, &to_call, 0);
if (result == LIBAB_SUCCESS) {
if (libab_ref_get(&to_call) == NULL) {
result = _interpreter_find_match(list, params, &new_types,
result = _interpreter_find_match(list, params, &new_types, &param_map,
&to_call, 1);
}
}
@@ -677,7 +840,8 @@ libab_result _interpreter_call_function_list(struct interpreter_state* state,
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = _interpreter_cast_and_perform_function_call(state, &to_call, params,
&new_types, into);
&new_types, &param_map, into);
libab_ref_trie_free(&param_map);
libab_ref_vec_free(&new_types);
}
@@ -700,22 +864,26 @@ libab_result _interpreter_call_function(struct interpreter_state* state,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
libab_ref_vec temp_new_types;
libab_ref_trie param_map;
libab_value* function_value;
libab_parsetype* function_type;
libab_function* function_instance;
function_value = libab_ref_get(function);
function_type = libab_ref_get(&function_value->type);
function_instance = libab_ref_get(&function_value->data);
libab_ref_null(into);
result = libab_ref_vec_init(&temp_new_types);
if (result == LIBAB_SUCCESS) {
result = _interpreter_check_types(&function_type->children,
params, &temp_new_types);
params, &temp_new_types, &function_instance->scope, &param_map);
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = _interpreter_cast_and_perform_function_call(
state, function, params, &temp_new_types, into);
state, function, params, &temp_new_types, &param_map, into);
libab_ref_trie_free(&param_map);
}
libab_ref_vec_free(&temp_new_types);
@@ -756,10 +924,6 @@ libab_result _interpreter_try_call(struct interpreter_state* state,
return result;
}
libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
libab_ref* into, libab_ref* scope,
int force_scope);
libab_result _interpreter_require_value(libab_ref* scope, const char* name,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
@@ -780,6 +944,7 @@ libab_result _interpreter_call_operator(struct interpreter_state* state,
libab_ref_vec params;
libab_ref temp;
libab_ref_null(into);
libab_ref_null(&function_value);
va_start(args, scope);
result = libab_ref_vec_init(&params);
@@ -787,7 +952,7 @@ libab_result _interpreter_call_operator(struct interpreter_state* state,
if (result == LIBAB_SUCCESS) {
/* Get first parameter. */
result =
_interpreter_run(state, va_arg(args, libab_tree*), &temp, scope, 0);
_interpreter_run(state, va_arg(args, libab_tree*), &temp, scope, SCOPE_NORMAL);
if (result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &temp);
@@ -798,7 +963,7 @@ libab_result _interpreter_call_operator(struct interpreter_state* state,
/* If infix, get second parameter. */
if (result == LIBAB_SUCCESS && to_call->variant == OPERATOR_INFIX) {
result = _interpreter_run(state, va_arg(args, libab_tree*), &temp,
scope, 0);
scope, SCOPE_NORMAL);
if (result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &temp);
@@ -813,6 +978,7 @@ libab_result _interpreter_call_operator(struct interpreter_state* state,
}
if(result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = _interpreter_try_call(state, &function_value, &params, into);
}
@@ -824,7 +990,7 @@ libab_result _interpreter_call_operator(struct interpreter_state* state,
return result;
}
libab_result _interpreter_run_function_node(struct interpreter_state* state,
libab_result _interpreter_run_call_node(struct interpreter_state* state,
libab_tree* tree, libab_ref* into,
libab_ref* scope) {
libab_result result = LIBAB_SUCCESS;
@@ -840,7 +1006,7 @@ libab_result _interpreter_run_function_node(struct interpreter_state* state,
count++) {
libab_ref_free(&param);
child = vec_index(&tree->children, count);
result = _interpreter_run(state, child, &param, scope, 0);
result = _interpreter_run(state, child, &param, scope, SCOPE_NORMAL);
if (result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &param);
@@ -855,7 +1021,7 @@ libab_result _interpreter_run_function_node(struct interpreter_state* state,
if (result == LIBAB_SUCCESS) {
result = _interpreter_run(
state, vec_index(&tree->children, tree->children.size - 1), &callee,
scope, 0);
scope, SCOPE_NORMAL);
if (result != LIBAB_SUCCESS) {
libab_ref_vec_free(&params);
}
@@ -872,27 +1038,161 @@ libab_result _interpreter_run_function_node(struct interpreter_state* state,
return result;
}
int _interpreter_compare_function_param(
const void* left, const void* right) {
const libab_tree* data = right;
return data->variant == TREE_FUN_PARAM;
}
libab_result _interpreter_resolve_and_insert_param(
libab_parsetype* type, libab_table* scope, libab_ref_vec* into) {
libab_result result = LIBAB_SUCCESS;
libab_ref copy;
result = libab_resolve_parsetype_copy(type, scope, &copy);
if(result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(into, &copy);
}
libab_ref_free(&copy);
return result;
}
int _interpreter_foreach_insert_function_param(
void* data, va_list args) {
libab_tree* tree = data;
libab_ref_vec* into = va_arg(args, libab_ref_vec*);
libab_ref* scope = va_arg(args, libab_ref*);
return _interpreter_resolve_and_insert_param(libab_ref_get(&tree->type),
libab_ref_get(scope),
into);
}
libab_result _interpreter_create_function_type(
struct interpreter_state* state, libab_tree* tree, libab_ref* scope, libab_parsetype** type) {
libab_result result = LIBAB_SUCCESS;
libab_basetype* funciton_type = libab_get_basetype_function(state->ab);
if((*type = malloc(sizeof(**type)))) {
(*type)->variant = LIBABACUS_TYPE_F_PARENT | LIBABACUS_TYPE_F_RESOLVED;
(*type)->data_u.base = funciton_type;
result = libab_ref_vec_init(&(*type)->children);
} else {
result = LIBAB_MALLOC;
}
if(result == LIBAB_SUCCESS) {
result = vec_foreach(&tree->children, NULL, _interpreter_compare_function_param,
_interpreter_foreach_insert_function_param, &(*type)->children, scope);
if(result == LIBAB_SUCCESS) {
result = _interpreter_resolve_and_insert_param(libab_ref_get(&tree->type),
libab_ref_get(scope), &(*type)->children);
}
if(result != LIBAB_SUCCESS) {
libab_ref_vec_free(&(*type)->children);
}
}
if(result != LIBAB_SUCCESS) {
free(*type);
*type = NULL;
}
return result;
}
libab_result _interpreter_wrap_function_type(
struct interpreter_state* state, libab_tree* tree, libab_ref* scope, libab_ref* into) {
libab_parsetype* type;
libab_result result = _interpreter_create_function_type(state, tree, scope, &type);
if(result == LIBAB_SUCCESS) {
result = libab_ref_new(into, type, libab_free_parsetype);
}
if(result != LIBAB_SUCCESS) {
libab_ref_null(into);
}
return result;
}
libab_result _interpreter_create_function_value(
struct interpreter_state* state, libab_tree* tree,
libab_ref* scope, libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
libab_ref function, type;
libab_ref_null(&type);
libab_ref_null(into);
result = libab_create_function_tree(state->ab, &function, libab_free_function, tree, scope);
if(result == LIBAB_SUCCESS) {
libab_ref_free(&type);
result = _interpreter_wrap_function_type(state, tree, scope, &type);
}
if(result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_create_value_ref(state->ab, into, &function, &type);
}
if(result != LIBAB_SUCCESS) {
libab_ref_free(into);
libab_ref_null(into);
}
libab_ref_free(&function);
libab_ref_free(&type);
return result;
}
libab_result _interpreter_expect_boolean(struct interpreter_state* state,
libab_tree* tree, int* into,
libab_ref* scope,
libab_interpreter_scope_mode mode) {
libab_ref output;
libab_result result = _interpreter_run(state, tree, &output, scope, mode);
libab_value* value;
libab_parsetype* type;
if(result == LIBAB_SUCCESS) {
value = libab_ref_get(&output);
type = libab_ref_get(&value->type);
if(type->data_u.base != libab_get_basetype_bool(state->ab)) {
result = LIBAB_BAD_CALL;
}
if(result == LIBAB_SUCCESS) {
*into = *((int*) libab_ref_get(&value->data));
}
}
libab_ref_free(&output);
return result;
}
libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
libab_ref* into, libab_ref* scope,
int force_scope) {
libab_interpreter_scope_mode mode) {
#define RUN_CHECK(i) _interpreter_expect_boolean(state, \
vec_index(&tree->children, i), &value, scope, SCOPE_NORMAL)
libab_result result = LIBAB_SUCCESS;
libab_ref new_scope;
int needs_scope = libab_tree_has_scope(tree->variant) || force_scope;
int needs_scope = (mode == SCOPE_FORCE) ||
(mode == SCOPE_NORMAL && libab_tree_has_scope(tree->variant));
if (needs_scope) {
result = libab_create_table(&new_scope, scope);
result = libab_create_table(state->ab, &new_scope, scope);
scope = &new_scope;
}
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
} else if (tree->variant == TREE_BASE || tree->variant == TREE_BLOCK) {
size_t index = 0;
libab_get_unit_value(state->ab, into);
while (result == LIBAB_SUCCESS && index < tree->children.size) {
libab_ref_free(into);
result = _interpreter_run(state, vec_index(&tree->children, index),
into, scope, 0);
into, scope, SCOPE_NORMAL);
index++;
}
} else if (tree->variant == TREE_NUM) {
@@ -902,7 +1202,7 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
} else if (tree->variant == TREE_ID) {
result = _interpreter_require_value(scope, tree->string_value, into);
} else if (tree->variant == TREE_CALL) {
result = _interpreter_run_function_node(state, tree, into, scope);
result = _interpreter_run_call_node(state, tree, into, scope);
} else if (tree->variant == TREE_OP) {
libab_operator* to_call = libab_table_search_operator(
libab_ref_get(scope), tree->string_value, OPERATOR_INFIX);
@@ -919,6 +1219,62 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
libab_ref_get(scope), tree->string_value, OPERATOR_POSTFIX);
result = _interpreter_call_operator(state, to_call, into, scope,
vec_index(&tree->children, 0));
} else if (tree->variant == TREE_FUN) {
libab_ref function;
result =
_interpreter_create_function_value(state, tree, scope, &function);
if(result == LIBAB_SUCCESS) {
result = libab_put_table_value(libab_ref_get(scope),
tree->string_value, &function);
if(result != LIBAB_SUCCESS) {
libab_ref_free(&function);
libab_ref_null(&function);
}
}
libab_ref_copy(&function, into);
libab_ref_free(&function);
} else if(tree->variant == TREE_RESERVED_OP) {
const libab_reserved_operator* op =
libab_find_reserved_operator(tree->string_value);
result = op->function(state->ab, scope,
vec_index(&tree->children, 0),
vec_index(&tree->children, 1),
into);
} else if(tree->variant == TREE_TRUE) {
libab_get_true_value(state->ab, into);
} else if(tree->variant == TREE_FALSE) {
libab_get_false_value(state->ab, into);
} else if (tree->variant == TREE_IF) {
int value;
result = _interpreter_expect_boolean(state,
vec_index(&tree->children, 0), &value, scope, SCOPE_NORMAL);
if(result == LIBAB_SUCCESS) {
result = _interpreter_run(state, vec_index(&tree->children,
value ? 1 : 2), into, scope, SCOPE_FORCE);
} else {
libab_ref_null(into);
}
} else if(tree->variant == TREE_WHILE) {
int value;
libab_get_unit_value(state->ab, into);
while(result == LIBAB_SUCCESS && (result = RUN_CHECK(0)) == LIBAB_SUCCESS && value) {
libab_ref_free(into);
result = _interpreter_run(state, vec_index(&tree->children, 1),
into, scope, SCOPE_FORCE);
}
} else if(tree->variant == TREE_DOWHILE) {
int value;
libab_get_unit_value(state->ab, into);
do {
libab_ref_free(into);
result = _interpreter_run(state, vec_index(&tree->children, 0),
into, scope, SCOPE_FORCE);
} while(result == LIBAB_SUCCESS && (result = RUN_CHECK(1)) == LIBAB_SUCCESS && value);
} else {
libab_get_unit_value(state->ab, into);
}
if (needs_scope) {
@@ -929,18 +1285,21 @@ libab_result _interpreter_run(struct interpreter_state* state, 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) {
struct interpreter_state state;
libab_result result;
_interpreter_init(&state, intr);
result = _interpreter_run(&state, tree, into, &state.ab->table, 1);
_interpreter_init(&state, intr, scope);
result = _interpreter_run(&state, tree, into, scope, mode);
_interpreter_free(&state);
return result;
}
libab_result libab_interpreter_run_function(libab_interpreter* intr,
libab_ref* scope,
const char* function,
libab_ref_vec* params,
libab_ref* into) {
@@ -948,14 +1307,14 @@ libab_result libab_interpreter_run_function(libab_interpreter* intr,
libab_ref function_value;
libab_result result;
_interpreter_init(&state, intr);
_interpreter_init(&state, intr, scope);
libab_ref_null(into);
result = _interpreter_require_value(&state.ab->table,
result = _interpreter_require_value(scope,
function, &function_value);
if(result == LIBAB_SUCCESS) {
libab_ref_free(into);
_interpreter_try_call(&state, &function_value, params, into);
result = _interpreter_try_call(&state, &function_value, params, into);
}
_interpreter_free(&state);
@@ -968,6 +1327,16 @@ void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into) {
libab_ref_copy(&intr->value_unit, into);
}
void libab_interpreter_true_value(libab_interpreter* intr, libab_ref* into) {
libab_ref_copy(&intr->value_true, into);
}
void libab_interpreter_false_value(libab_interpreter* intr, libab_ref* into) {
libab_ref_copy(&intr->value_false, into);
}
void libab_interpreter_free(libab_interpreter* intr) {
libab_ref_free(&intr->value_unit);
libab_ref_free(&intr->value_true);
libab_ref_free(&intr->value_false);
}

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;
@@ -126,7 +109,7 @@ libab_result _register_operator(libab* ab, const char* op,
}
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,28 +145,29 @@ libab_result libab_register_operator_postfix(libab* ab, const char* op,
return _register_operator(ab, op, OPERATOR_POSTFIX, 0, 0, function);
}
libab_result _create_value_function_internal(libab_ref* into, libab_ref* type,
libab_result _create_value_function_internal(libab* ab,
libab_ref* into, libab_ref* type,
libab_function_ptr func,
libab_ref* scope) {
libab_ref function_ref;
libab_result result =
libab_create_function_internal(&function_ref, _free_function, func, scope);
libab_create_function_internal(ab, &function_ref, libab_free_function, func, scope);
libab_ref_null(into);
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_create_value_ref(into, &function_ref, type);
result = libab_create_value_ref(ab, into, &function_ref, type);
}
libab_ref_free(&function_ref);
return result;
}
libab_result _create_value_function_list(libab_ref* into, libab_ref* type) {
libab_result _create_value_function_list(libab* ab, libab_ref* into, libab_ref* type) {
libab_ref list_ref;
libab_result result = libab_create_function_list(&list_ref, type);
libab_result result = libab_create_function_list(ab, &list_ref, type);
libab_ref_null(into);
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_create_value_ref(into, &list_ref, type);
result = libab_create_value_ref(ab, into, &list_ref, type);
}
libab_ref_free(&list_ref);
return result;
@@ -205,7 +189,7 @@ libab_result _libab_register_function_existing(libab* ab,
} else if (old_type->data_u.base == &_basetype_function) {
libab_ref new_list;
result =
_create_value_function_list(&new_list, &ab->type_function_list);
_create_value_function_list(ab, &new_list, &ab->type_function_list);
if (result == LIBAB_SUCCESS) {
libab_function_list* list =
libab_ref_get(&((libab_value*)libab_ref_get(&new_list))->data);
@@ -250,7 +234,7 @@ libab_result libab_register_function(libab* ab, const char* name,
libab_table_entry* existing_entry;
libab_ref function_value;
libab_result result =
_create_value_function_internal(&function_value, type, func, &ab->table);
_create_value_function_internal(ab, &function_value, type, func, &ab->table);
if (result == LIBAB_SUCCESS) {
existing_entry = libab_table_search_filter(
@@ -295,6 +279,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 +289,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 +310,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 +329,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 +350,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 +360,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 +378,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,28 +394,61 @@ 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 _create_tree(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 = _create_tree(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;
}
@@ -426,16 +462,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_run_function(&ab->intr, &ab->table, function, &params, into);
libab_ref_vec_free(&params);
}
@@ -444,13 +474,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 = _create_tree(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_run_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_run_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;
@@ -736,6 +768,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,11 +1055,13 @@ 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) {
_parser_find_operator_infix(state, op_stack.tail->data,
&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 &&
@@ -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

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

16
src/refcount_internal.c Normal file
View File

@@ -0,0 +1,16 @@
#include "refcount_internal.h"
#include <stdlib.h>
void libab_ref_count_changed(libab_ref_count* count) {
if (count->strong == 0) {
count->strong--;
if (count->free_func) {
count->free_func(count->data);
}
}
if (count->weak == 0) {
if(count->prev) count->prev->next = count->next;
if(count->next) count->next->prev = count->prev;
free(count);
}
}

View File

@@ -1,12 +1,126 @@
#include "reserved.h"
#include "string.h"
#include "util.h"
#include "value.h"
#include "libabacus.h"
libab_result _update_entry(libab_table* table, const char* name, libab_ref* value) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* value_entry = libab_table_search_entry_value(table, name);
if(value_entry) {
libab_ref_free(&value_entry->data_u.value);
libab_ref_copy(value, &value_entry->data_u.value);
} else {
result = libab_put_table_value(table, name, value);
}
return result;
}
libab_result _behavior_assign(libab* ab, libab_ref* scope,
libab_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 = _update_entry(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 _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 */
0, /* Lowest precedence */
1, /* Right associative, a = b = 6 should be a = (b = 6) */
_behavior_assign
},
{
"&&", /* Logical and */
0, /* Low precedence */
-1, /* Left associative. */
_behavior_land
},
{
"||", /* Logical or */
0, /* 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 +135,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,
@@ -65,37 +71,52 @@ libab_operator* libab_table_search_operator(libab_table* table,
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) {
@@ -48,7 +48,8 @@ int _tree_foreach_free(void* data, va_list args) {
}
int _tree_needs_free(libab_tree* tree) {
return ((tree->variant == TREE_FUN && --tree->int_value) | (tree->variant != TREE_FUN));
return ((tree->variant == TREE_FUN && --(tree->int_value) == 0) |
(tree->variant != TREE_FUN));
}
void libab_tree_free_recursive(libab_tree* tree) {

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,19 @@ libab_result libab_create_value_raw(libab_ref* into, void* data,
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(value);
} else {
libab_gc_add(into, _gc_visit_value_children, &ab->containers);
}
return result;
}
libab_result libab_create_function_internal(libab_ref* into,
void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) {
libab_function* func = function;
libab_gc_visit(&func->scope, visitor, data);
}
libab_result libab_create_function_internal(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_function_ptr fun,
libab_ref* scope) {
@@ -231,12 +318,14 @@ libab_result libab_create_function_internal(libab_ref* into,
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
}
return result;
}
libab_result libab_create_function_tree(libab_ref* into,
libab_result libab_create_function_tree(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_tree* tree,
libab_ref* scope) {
@@ -259,12 +348,14 @@ libab_result libab_create_function_tree(libab_ref* into,
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
}
return result;
}
libab_result libab_create_function_behavior(libab_ref* into,
libab_result libab_create_function_behavior(libab* ab, libab_ref* into,
void (*free_function)(void*),
libab_behavior* behavior,
libab_ref* scope) {
@@ -287,12 +378,14 @@ libab_result libab_create_function_behavior(libab_ref* into,
if(result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(new_function);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
}
return result;
}
libab_result libab_create_function_list(libab_ref* into, libab_ref* type) {
libab_result libab_create_function_list(libab* ab, libab_ref* into, libab_ref* type) {
libab_function_list* list;
libab_result result = LIBAB_SUCCESS;
@@ -314,6 +407,8 @@ libab_result libab_create_function_list(libab_ref* into, libab_ref* type) {
if (result != LIBAB_SUCCESS) {
libab_ref_null(into);
free(list);
} else {
libab_gc_add(into, _gc_visit_function_children, &ab->containers);
}
return result;
@@ -341,6 +436,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 +465,15 @@ 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 == ')')
to[index++] = '\\';
to[index++] = *(from++);
}
to[index] = '\0';
}