From ca6075e8d5114475ce128d1459118c4cd2151a74 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 13 Sep 2018 17:05:39 -0700 Subject: [PATCH] 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. --- include/interpreter.h | 16 ++++++++++- include/libabacus.h | 4 +-- src/interactive.c | 2 +- src/interpreter.c | 17 ++++++++++- src/libabacus.c | 8 +++--- src/reserved.c | 67 +++++++++++++++++++++++++++++++++++++++++-- src/util.c | 2 +- 7 files changed, 103 insertions(+), 13 deletions(-) diff --git a/include/interpreter.h b/include/interpreter.h index 5fde633..12a6f85 100644 --- a/include/interpreter.h +++ b/include/interpreter.h @@ -70,11 +70,25 @@ libab_result libab_interpreter_run(libab_interpreter* intr, libab_tree* tree, * @param into the reference to store the result into. * @return the result of the call. */ -libab_result libab_interpreter_run_function(libab_interpreter* intr, +libab_result libab_interpreter_call_function(libab_interpreter* intr, libab_ref* scope, const char* function, libab_ref_vec* params, libab_ref* into); +/** + * Calls a function value with the given parameters. + * @param intr the interpreter to use to call the function. + * @param scope the scope in which the function should be searched for. + * @param function the function to call. + * @param params the parameters to pass to the function. + * @param into the reference to store the result into. + * @return the result of the call. + */ +libab_result libab_interpreter_call_value(libab_interpreter* intr, + libab_ref* scope, + libab_ref* function, + libab_ref_vec* params, + libab_ref* into); /** * Gets the unit value from this interpreter. * @param intr the interpreter from which to get the unit value. diff --git a/include/libabacus.h b/include/libabacus.h index 0690b57..eb666b0 100644 --- a/include/libabacus.h +++ b/include/libabacus.h @@ -263,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. * @return the result of the call. */ -libab_result libab_run_function(libab* ab, const char* function, +libab_result libab_call_function(libab* ab, const char* function, libab_ref* into, size_t param_count, ...); /** @@ -293,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. * @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, size_t param_count, ...); diff --git a/src/interactive.c b/src/interactive.c index 9fcd46d..5f20151 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -198,7 +198,7 @@ libab_result loop(libab* ab, int interaction_count, libab_ref* scope) { 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); + result = libab_call_function_scoped(ab, "print", scope, &call_into, 1, &eval_into); if(result == LIBAB_BAD_CALL) { printf("(?)\n"); result = LIBAB_SUCCESS; diff --git a/src/interpreter.c b/src/interpreter.c index 0c4a6cc..55a59ae 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -1297,7 +1297,7 @@ libab_result libab_interpreter_run(libab_interpreter* intr, libab_tree* tree, return result; } -libab_result libab_interpreter_run_function(libab_interpreter* intr, +libab_result libab_interpreter_call_function(libab_interpreter* intr, libab_ref* scope, const char* function, libab_ref_vec* params, @@ -1322,6 +1322,21 @@ libab_result libab_interpreter_run_function(libab_interpreter* intr, 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) { libab_ref_copy(&intr->value_unit, into); } diff --git a/src/libabacus.c b/src/libabacus.c index 32d475e..11f6f0b 100644 --- a/src/libabacus.c +++ b/src/libabacus.c @@ -377,7 +377,7 @@ libab_result libab_run(libab* ab, const char* string, libab_ref* value) { return result; } -libab_result libab_run_function(libab* ab, const char* function, +libab_result libab_call_function(libab* ab, const char* function, libab_ref* into, size_t param_count, ...) { libab_ref_vec params; @@ -389,7 +389,7 @@ libab_result libab_run_function(libab* ab, const char* function, result = _handle_va_params(ab, ¶ms, param_count, args); if(result == LIBAB_SUCCESS) { libab_ref_free(into); - result = libab_interpreter_run_function(&ab->intr, &ab->table, function, ¶ms, into); + result = libab_interpreter_call_function(&ab->intr, &ab->table, function, ¶ms, into); libab_ref_vec_free(¶ms); } @@ -417,7 +417,7 @@ libab_result libab_run_scoped(libab* ab, const char* string, libab_ref* scope, l 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, ...) { libab_ref_vec params; libab_result result; @@ -428,7 +428,7 @@ libab_result libab_run_function_scoped(libab* ab, const char* function, libab_re result = _handle_va_params(ab, ¶ms, param_count, args); if(result == LIBAB_SUCCESS) { libab_ref_free(into); - result = libab_interpreter_run_function(&ab->intr, scope, function, ¶ms, into); + result = libab_interpreter_call_function(&ab->intr, scope, function, ¶ms, into); libab_ref_vec_free(¶ms); } diff --git a/src/reserved.c b/src/reserved.c index a506665..5752d00 100644 --- a/src/reserved.c +++ b/src/reserved.c @@ -41,6 +41,61 @@ libab_result _behavior_assign(libab* ab, libab_ref* scope, return result; } +libab_result _behavior_method(libab* ab, libab_ref* scope, + libab_tree* left, libab_tree* right, + libab_ref* into) { + libab_result result = LIBAB_SUCCESS; + libab_ref param; + libab_ref callee; + libab_ref_vec params; + int free_params = 0; + size_t index = 0; + + libab_ref_null(&callee); + if(right->variant == TREE_CALL) { + result = libab_ref_vec_init(¶ms); + } else { + result = LIBAB_BAD_CALL; + } + + if(result == LIBAB_SUCCESS) { + free_params = 1; + result = libab_run_tree_scoped(ab, left, scope, ¶m); + if(result == LIBAB_SUCCESS) { + result = libab_ref_vec_insert(¶ms, ¶m); + } + libab_ref_free(¶m); + } + + for(; index < right->children.size - 1 && result == LIBAB_SUCCESS; index++) { + result = libab_run_tree_scoped(ab, vec_index(&right->children, index), + scope, ¶m); + if(result == LIBAB_SUCCESS) { + result = libab_ref_vec_insert(¶ms, ¶m); + } + libab_ref_free(¶m); + } + + if(result == LIBAB_SUCCESS) { + libab_ref_free(&callee); + result = libab_run_tree_scoped(ab, vec_index(&right->children, right->children.size - 1), + scope, &callee); + } + + if(result == LIBAB_SUCCESS) { + result = libab_interpreter_call_value(&ab->intr, scope, &callee, ¶ms, into); + } else { + libab_ref_null(into); + } + + if(free_params) { + libab_ref_vec_free(¶ms); + } + libab_ref_free(&callee); + + return result; +} + libab_result _expect_boolean(libab* ab, libab_ref* scope, libab_tree* to_run, int* into) { libab_result result = LIBAB_SUCCESS; @@ -103,19 +158,25 @@ libab_result _behavior_lor(libab* ab, libab_ref* scope, static const libab_reserved_operator libab_reserved_operators[] = { { "=", /* Assignment */ - 0, /* Lowest precedence */ + -3, /* Lowest precedence */ 1, /* Right associative, a = b = 6 should be a = (b = 6) */ _behavior_assign }, + { + ".", + -2, + -1, + _behavior_method + }, { "&&", /* Logical and */ - 0, /* Low precedence */ + -1, /* Low precedence */ -1, /* Left associative. */ _behavior_land }, { "||", /* Logical or */ - 0, /* Low precedence */ + -1, /* Low precedence */ -1, /* Left associative. */ _behavior_lor }, diff --git a/src/util.c b/src/util.c index 7ea6671..e4fa226 100644 --- a/src/util.c +++ b/src/util.c @@ -572,7 +572,7 @@ void libab_sanitize(char* to, const char* from, size_t buffer_size) { while (*from && index < (buffer_size - 2)) { if (*from == '+' || *from == '*' || *from == '\\' || *from == '|' || *from == '[' || *from == ']' || *from == '(' || - *from == ')') + *from == ')' || *from == '.') to[index++] = '\\'; to[index++] = *(from++); }