Compare commits

...

5 Commits

Author SHA1 Message Date
ca6075e8d5 Add a new method call operator, and more.
The '.' operator now represents method calls. A function f: (a, b)->c
can be called as a.f(b), which is equivalent to f(a, b). Besides
this change, all reserved operators now have a negative precedence
(it's relative, remember?), and some function names were changed.
2018-09-13 17:05:39 -07:00
4425b27b52 Make overloading code a utility function and call from interpreter.
This fixes #10.
2018-09-13 16:09:04 -07:00
25dd70f040 Fix segmentation fault during type initialization. 2018-09-13 15:08:57 -07:00
5617484aff Make parsing function public.
libab already provides a _run_tree ... you can't run_tree if there's
no tree.
2018-09-12 14:43:43 -07:00
b311c854ee Fix segmentation fault on function parsing error. 2018-09-12 14:32:28 -07:00
10 changed files with 217 additions and 96 deletions

View File

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

View File

@@ -232,6 +232,13 @@ void libab_get_false_value(libab* ab, libab_ref* into);
*/ */
void libab_get_bool_value(libab* ab, int val, libab_ref* into); void libab_get_bool_value(libab* ab, int val, libab_ref* into);
/**
* Parses the given piece of code using the given libabacus instance.
* @param ab the instance to use to parse the code.
* @param string the source code to parse.
* @param into the value to store the newly parsed tree into.
*/
libab_result libab_parse(libab* ab, const char* string, libab_tree** into);
/** /**
* Executes the given string of code. * Executes the given string of code.
* @param ab the libabacus instance to use for executing code. * @param ab the libabacus instance to use for executing code.
@@ -256,7 +263,7 @@ libab_result libab_run_tree(libab* ab, libab_tree* tree, libab_ref* value);
* @param param_count the number of parameters given to this function. * @param param_count the number of parameters given to this function.
* @return the result of the call. * @return the result of the call.
*/ */
libab_result libab_run_function(libab* ab, const char* function, libab_result libab_call_function(libab* ab, const char* function,
libab_ref* into, libab_ref* into,
size_t param_count, ...); size_t param_count, ...);
/** /**
@@ -286,7 +293,7 @@ libab_result libab_run_tree_scoped(libab* ab, libab_tree* tree, libab_ref* scope
* @param param_count the number of parameters given to this function. * @param param_count the number of parameters given to this function.
* @return the result of the call. * @return the result of the call.
*/ */
libab_result libab_run_function_scoped(libab* ab, const char* function, libab_ref* scope, libab_result libab_call_function_scoped(libab* ab, const char* function, libab_ref* scope,
libab_ref* into, libab_ref* into,
size_t param_count, ...); size_t param_count, ...);

View File

@@ -103,6 +103,17 @@ libab_result libab_create_value_ref(libab* ab, libab_ref* into,
*/ */
libab_result libab_create_value_raw(libab* ab, libab_ref* into, libab_result libab_create_value_raw(libab* ab, libab_ref* into,
void* data, libab_ref* type); void* data, libab_ref* type);
/**
* Overloads a function of the given name.
* @param table the table to insert the function into.
* @param name the name of the function.
* @param function the function to register.
* @return the result of the overload.
*/
libab_result libab_overload_function(libab* ab,
libab_table* table,
const char* name,
libab_ref* function);
/** /**
* Allocates a function that uses internal code to run. * Allocates a function that uses internal code to run.
* @param into the reference into which to store the new function. * @param into the reference into which to store the new function.

View File

@@ -198,7 +198,7 @@ libab_result loop(libab* ab, int interaction_count, libab_ref* scope) {
if (eval_result != LIBAB_SUCCESS) { if (eval_result != LIBAB_SUCCESS) {
printf("Invalid input (error code %d).\n", eval_result); printf("Invalid input (error code %d).\n", eval_result);
} else { } else {
result = libab_run_function_scoped(ab, "print", scope, &call_into, 1, &eval_into); result = libab_call_function_scoped(ab, "print", scope, &call_into, 1, &eval_into);
if(result == LIBAB_BAD_CALL) { if(result == LIBAB_BAD_CALL) {
printf("(?)\n"); printf("(?)\n");
result = LIBAB_SUCCESS; result = LIBAB_SUCCESS;

View File

@@ -1224,7 +1224,7 @@ libab_result _interpreter_run(struct interpreter_state* state, libab_tree* tree,
_interpreter_create_function_value(state, tree, scope, &function); _interpreter_create_function_value(state, tree, scope, &function);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
result = libab_put_table_value(libab_ref_get(scope), result = libab_overload_function(state->ab, libab_ref_get(scope),
tree->string_value, &function); tree->string_value, &function);
if(result != LIBAB_SUCCESS) { if(result != LIBAB_SUCCESS) {
libab_ref_free(&function); libab_ref_free(&function);
@@ -1297,7 +1297,7 @@ libab_result libab_interpreter_run(libab_interpreter* intr, libab_tree* tree,
return result; return result;
} }
libab_result libab_interpreter_run_function(libab_interpreter* intr, libab_result libab_interpreter_call_function(libab_interpreter* intr,
libab_ref* scope, libab_ref* scope,
const char* function, const char* function,
libab_ref_vec* params, libab_ref_vec* params,
@@ -1322,6 +1322,21 @@ libab_result libab_interpreter_run_function(libab_interpreter* intr,
return result; return result;
} }
libab_result libab_interpreter_call_value(libab_interpreter* intr,
libab_ref* scope,
libab_ref* function,
libab_ref_vec* params,
libab_ref* into) {
struct interpreter_state state;
libab_result result = LIBAB_SUCCESS;
_interpreter_init(&state, intr, scope);
result = _interpreter_try_call(&state, function, params, into);
_interpreter_free(&state);
return result;
}
void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into) { void libab_interpreter_unit_value(libab_interpreter* intr, libab_ref* into) {
libab_ref_copy(&intr->value_unit, into); libab_ref_copy(&intr->value_unit, into);
} }

View File

@@ -161,92 +161,16 @@ libab_result _create_value_function_internal(libab* ab,
return result; return result;
} }
libab_result _create_value_function_list(libab* ab, libab_ref* into, libab_ref* type) {
libab_ref list_ref;
libab_result result = libab_create_function_list(ab, &list_ref, type);
libab_ref_null(into);
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_create_value_ref(ab, into, &list_ref, type);
}
libab_ref_free(&list_ref);
return result;
}
libab_result _libab_register_function_existing(libab* ab,
libab_table_entry* entry,
libab_ref* function_val) {
libab_value* old_value;
libab_parsetype* old_type;
libab_result result = LIBAB_SUCCESS;
old_value = libab_ref_get(&entry->data_u.value);
old_type = libab_ref_get(&old_value->type);
if (old_type->data_u.base == &_basetype_function_list) {
libab_function_list* list = libab_ref_get(&old_value->data);
result = libab_function_list_insert(list, function_val);
} else if (old_type->data_u.base == &_basetype_function) {
libab_ref new_list;
result =
_create_value_function_list(ab, &new_list, &ab->type_function_list);
if (result == LIBAB_SUCCESS) {
libab_function_list* list =
libab_ref_get(&((libab_value*)libab_ref_get(&new_list))->data);
result = libab_function_list_insert(list, &entry->data_u.value);
if (result == LIBAB_SUCCESS) {
result = libab_function_list_insert(list, function_val);
}
}
if (result == LIBAB_SUCCESS) {
libab_ref_swap(&entry->data_u.value, &new_list);
}
libab_ref_free(&new_list);
} else {
libab_ref_swap(&entry->data_u.value, function_val);
}
return result;
}
libab_result _libab_register_function_new(libab* ab, const char* name,
libab_ref* function_val) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* entry;
if ((entry = malloc(sizeof(*entry)))) {
entry->variant = ENTRY_VALUE;
libab_ref_copy(function_val, &entry->data_u.value);
result = libab_table_put(libab_ref_get(&ab->table), name, entry);
if (result != LIBAB_SUCCESS) {
libab_table_entry_free(entry);
free(entry);
}
} else {
result = LIBAB_MALLOC;
}
return result;
}
libab_result libab_register_function(libab* ab, const char* name, libab_result libab_register_function(libab* ab, const char* name,
libab_ref* type, libab_function_ptr func) { libab_ref* type, libab_function_ptr func) {
libab_table_entry* existing_entry;
libab_ref function_value; libab_ref function_value;
libab_result result = libab_result result =
_create_value_function_internal(ab, &function_value, type, func, &ab->table); _create_value_function_internal(ab, &function_value, type, func, &ab->table);
if (result == LIBAB_SUCCESS) { if (result == LIBAB_SUCCESS) {
existing_entry = libab_table_search_filter( libab_overload_function(ab, libab_ref_get(&ab->table), name, &function_value);
libab_ref_get(&ab->table), name, NULL, libab_table_compare_value);
if (existing_entry) {
result = _libab_register_function_existing(ab, existing_entry,
&function_value);
} else {
result = _libab_register_function_new(ab, name, &function_value);
}
libab_ref_free(&function_value);
} }
libab_ref_free(&function_value);
return result; return result;
} }
@@ -406,7 +330,7 @@ void libab_get_bool_value(libab* ab, int val, libab_ref* into) {
val ? libab_get_true_value(ab, into) : libab_get_false_value(ab, into); val ? libab_get_true_value(ab, into) : libab_get_false_value(ab, into);
} }
libab_result _create_tree(libab* ab, const char* string, libab_tree** into) { libab_result libab_parse(libab* ab, const char* string, libab_tree** into) {
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
ll tokens; ll tokens;
@@ -442,7 +366,7 @@ libab_result libab_run(libab* ab, const char* string, libab_ref* value) {
libab_tree* root; libab_tree* root;
libab_ref_null(value); libab_ref_null(value);
result = _create_tree(ab, string, &root); result = libab_parse(ab, string, &root);
if (result == LIBAB_SUCCESS) { if (result == LIBAB_SUCCESS) {
libab_ref_free(value); libab_ref_free(value);
@@ -453,7 +377,7 @@ libab_result libab_run(libab* ab, const char* string, libab_ref* value) {
return result; return result;
} }
libab_result libab_run_function(libab* ab, const char* function, libab_result libab_call_function(libab* ab, const char* function,
libab_ref* into, libab_ref* into,
size_t param_count, ...) { size_t param_count, ...) {
libab_ref_vec params; libab_ref_vec params;
@@ -465,7 +389,7 @@ libab_result libab_run_function(libab* ab, const char* function,
result = _handle_va_params(ab, &params, param_count, args); result = _handle_va_params(ab, &params, param_count, args);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
libab_ref_free(into); libab_ref_free(into);
result = libab_interpreter_run_function(&ab->intr, &ab->table, function, &params, into); result = libab_interpreter_call_function(&ab->intr, &ab->table, function, &params, into);
libab_ref_vec_free(&params); libab_ref_vec_free(&params);
} }
@@ -483,7 +407,7 @@ libab_result libab_run_scoped(libab* ab, const char* string, libab_ref* scope, l
libab_tree* root; libab_tree* root;
libab_ref_null(into); libab_ref_null(into);
result = _create_tree(ab, string, &root); result = libab_parse(ab, string, &root);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
libab_ref_free(into); libab_ref_free(into);
result = libab_interpreter_run(&ab->intr, root, scope, SCOPE_NONE, into); result = libab_interpreter_run(&ab->intr, root, scope, SCOPE_NONE, into);
@@ -493,7 +417,7 @@ libab_result libab_run_scoped(libab* ab, const char* string, libab_ref* scope, l
return result; return result;
} }
libab_result libab_run_function_scoped(libab* ab, const char* function, libab_ref* scope, libab_ref* into, libab_result libab_call_function_scoped(libab* ab, const char* function, libab_ref* scope, libab_ref* into,
size_t param_count, ...) { size_t param_count, ...) {
libab_ref_vec params; libab_ref_vec params;
libab_result result; libab_result result;
@@ -504,7 +428,7 @@ libab_result libab_run_function_scoped(libab* ab, const char* function, libab_re
result = _handle_va_params(ab, &params, param_count, args); result = _handle_va_params(ab, &params, param_count, args);
if(result == LIBAB_SUCCESS) { if(result == LIBAB_SUCCESS) {
libab_ref_free(into); libab_ref_free(into);
result = libab_interpreter_run_function(&ab->intr, scope, function, &params, into); result = libab_interpreter_call_function(&ab->intr, scope, function, &params, into);
libab_ref_vec_free(&params); libab_ref_vec_free(&params);
} }

View File

@@ -525,6 +525,7 @@ libab_result _parse_fun(struct parser_state* state, libab_tree** store_into) {
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
int is_parenth, is_comma; int is_parenth, is_comma;
libab_tree* temp; libab_tree* temp;
*store_into = NULL;
result = _parser_consume_type(state, TOKEN_KW_FUN); result = _parser_consume_type(state, TOKEN_KW_FUN);
if (result == LIBAB_SUCCESS) { if (result == LIBAB_SUCCESS) {
if (_parser_is_type(state, TOKEN_ID)) { if (_parser_is_type(state, TOKEN_ID)) {

View File

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

View File

@@ -41,6 +41,61 @@ libab_result _behavior_assign(libab* ab, libab_ref* scope,
return result; return result;
} }
libab_result _behavior_method(libab* ab, libab_ref* scope,
libab_tree* left, libab_tree* right,
libab_ref* into) {
libab_result result = LIBAB_SUCCESS;
libab_ref param;
libab_ref callee;
libab_ref_vec params;
int free_params = 0;
size_t index = 0;
libab_ref_null(&callee);
if(right->variant == TREE_CALL) {
result = libab_ref_vec_init(&params);
} else {
result = LIBAB_BAD_CALL;
}
if(result == LIBAB_SUCCESS) {
free_params = 1;
result = libab_run_tree_scoped(ab, left, scope, &param);
if(result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &param);
}
libab_ref_free(&param);
}
for(; index < right->children.size - 1 && result == LIBAB_SUCCESS; index++) {
result = libab_run_tree_scoped(ab, vec_index(&right->children, index),
scope, &param);
if(result == LIBAB_SUCCESS) {
result = libab_ref_vec_insert(&params, &param);
}
libab_ref_free(&param);
}
if(result == LIBAB_SUCCESS) {
libab_ref_free(&callee);
result = libab_run_tree_scoped(ab, vec_index(&right->children, right->children.size - 1),
scope, &callee);
}
if(result == LIBAB_SUCCESS) {
result = libab_interpreter_call_value(&ab->intr, scope, &callee, &params, into);
} else {
libab_ref_null(into);
}
if(free_params) {
libab_ref_vec_free(&params);
}
libab_ref_free(&callee);
return result;
}
libab_result _expect_boolean(libab* ab, libab_ref* scope, libab_result _expect_boolean(libab* ab, libab_ref* scope,
libab_tree* to_run, int* into) { libab_tree* to_run, int* into) {
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
@@ -103,19 +158,25 @@ libab_result _behavior_lor(libab* ab, libab_ref* scope,
static const libab_reserved_operator libab_reserved_operators[] = { static const libab_reserved_operator libab_reserved_operators[] = {
{ {
"=", /* Assignment */ "=", /* Assignment */
0, /* Lowest precedence */ -3, /* Lowest precedence */
1, /* Right associative, a = b = 6 should be a = (b = 6) */ 1, /* Right associative, a = b = 6 should be a = (b = 6) */
_behavior_assign _behavior_assign
}, },
{
".",
-2,
-1,
_behavior_method
},
{ {
"&&", /* Logical and */ "&&", /* Logical and */
0, /* Low precedence */ -1, /* Low precedence */
-1, /* Left associative. */ -1, /* Left associative. */
_behavior_land _behavior_land
}, },
{ {
"||", /* Logical or */ "||", /* Logical or */
0, /* Low precedence */ -1, /* Low precedence */
-1, /* Left associative. */ -1, /* Left associative. */
_behavior_lor _behavior_lor
}, },

View File

@@ -290,6 +290,94 @@ libab_result libab_create_value_raw(libab* ab, libab_ref* into,
return result; return result;
} }
libab_result _create_value_function_list(libab* ab, libab_ref* into, libab_ref* type) {
libab_ref list_ref;
libab_result result = libab_create_function_list(ab, &list_ref, type);
libab_ref_null(into);
if (result == LIBAB_SUCCESS) {
libab_ref_free(into);
result = libab_create_value_ref(ab, into, &list_ref, type);
}
libab_ref_free(&list_ref);
return result;
}
libab_result _register_function_existing(libab* ab,
libab_table_entry* entry,
libab_ref* function_val) {
libab_value* old_value;
libab_parsetype* old_type;
libab_result result = LIBAB_SUCCESS;
old_value = libab_ref_get(&entry->data_u.value);
old_type = libab_ref_get(&old_value->type);
if (old_type->data_u.base == libab_get_basetype_function_list(ab)) {
libab_function_list* list = libab_ref_get(&old_value->data);
result = libab_function_list_insert(list, function_val);
} else if (old_type->data_u.base == libab_get_basetype_function(ab)) {
libab_ref new_list;
result =
_create_value_function_list(ab, &new_list, &ab->type_function_list);
if (result == LIBAB_SUCCESS) {
libab_function_list* list =
libab_ref_get(&((libab_value*)libab_ref_get(&new_list))->data);
result = libab_function_list_insert(list, &entry->data_u.value);
if (result == LIBAB_SUCCESS) {
result = libab_function_list_insert(list, function_val);
}
}
if (result == LIBAB_SUCCESS) {
libab_ref_swap(&entry->data_u.value, &new_list);
}
libab_ref_free(&new_list);
} else {
libab_ref_swap(&entry->data_u.value, function_val);
}
return result;
}
libab_result _register_function_new(libab* ab, const char* name,
libab_ref* function_val) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* entry;
if ((entry = malloc(sizeof(*entry)))) {
entry->variant = ENTRY_VALUE;
libab_ref_copy(function_val, &entry->data_u.value);
result = libab_table_put(libab_ref_get(&ab->table), name, entry);
if (result != LIBAB_SUCCESS) {
libab_table_entry_free(entry);
free(entry);
}
} else {
result = LIBAB_MALLOC;
}
return result;
}
libab_result libab_overload_function(libab* ab,
libab_table* table,
const char* name,
libab_ref* function) {
libab_result result = LIBAB_SUCCESS;
libab_table_entry* existing_entry = libab_table_search_filter(
table, name, NULL, libab_table_compare_value);
if (existing_entry) {
result = _register_function_existing(ab, existing_entry,
function);
} else {
result = _register_function_new(ab, name, function);
}
return result;
}
void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) { void _gc_visit_function_children(void* function, libab_visitor_function_ptr visitor, void* data) {
size_t index = 0; size_t index = 0;
libab_function* func = function; libab_function* func = function;
@@ -484,7 +572,7 @@ void libab_sanitize(char* to, const char* from, size_t buffer_size) {
while (*from && index < (buffer_size - 2)) { while (*from && index < (buffer_size - 2)) {
if (*from == '+' || *from == '*' || *from == '\\' || if (*from == '+' || *from == '*' || *from == '\\' ||
*from == '|' || *from == '[' || *from == ']' || *from == '(' || *from == '|' || *from == '[' || *from == ']' || *from == '(' ||
*from == ')') *from == ')' || *from == '.')
to[index++] = '\\'; to[index++] = '\\';
to[index++] = *(from++); to[index++] = *(from++);
} }