2018-05-23 15:41:17 -07:00
|
|
|
#include "libabacus.h"
|
2018-05-26 20:43:36 -07:00
|
|
|
#include "util.h"
|
2018-05-26 21:55:30 -07:00
|
|
|
#include "value.h"
|
|
|
|
#include <stdio.h>
|
2018-06-02 16:06:13 -07:00
|
|
|
#include <math.h>
|
2018-05-23 15:41:17 -07:00
|
|
|
|
2018-05-26 21:55:30 -07:00
|
|
|
#define TRY(expression) \
|
|
|
|
if (result == LIBAB_SUCCESS) \
|
|
|
|
result = expression;
|
2018-08-10 16:59:44 -07:00
|
|
|
#define FUNCTION(name) \
|
|
|
|
libab_result function_##name (libab* ab, libab_ref* scope, \
|
|
|
|
libab_ref_vec* params, libab_ref* into)
|
|
|
|
|
2018-05-23 15:41:17 -07:00
|
|
|
#define INTERACTIONS 5
|
|
|
|
|
|
|
|
void* impl_parse(const char* string) {
|
|
|
|
double* data = malloc(sizeof(*data));
|
2018-05-26 21:55:30 -07:00
|
|
|
if (data) {
|
2018-05-23 15:41:17 -07:00
|
|
|
*data = strtod(string, NULL);
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2018-05-26 21:55:30 -07:00
|
|
|
void impl_free(void* data) { free(data); }
|
2018-05-23 15:41:17 -07:00
|
|
|
|
2018-05-27 00:12:13 -07:00
|
|
|
libab_result create_double_value(libab* ab, double val, libab_ref* into) {
|
|
|
|
libab_ref type_num;
|
|
|
|
libab_result result = LIBAB_SUCCESS;
|
|
|
|
libab_get_type_num(ab, &type_num);
|
|
|
|
double* new_double = malloc(sizeof(*new_double));
|
|
|
|
if(new_double) {
|
|
|
|
*new_double = val;
|
|
|
|
result = libab_create_value_raw(into, new_double, &type_num);
|
|
|
|
if(result != LIBAB_SUCCESS) {
|
|
|
|
free(new_double);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result = LIBAB_MALLOC;
|
|
|
|
libab_ref_null(into);
|
|
|
|
}
|
|
|
|
libab_ref_free(&type_num);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-08-10 19:21:55 -07:00
|
|
|
|
2018-08-10 18:40:21 -07:00
|
|
|
FUNCTION(not) {
|
|
|
|
int* left = libab_unwrap_param(params, 0);
|
|
|
|
libab_get_bool_value(ab, !(*left), into);
|
|
|
|
return LIBAB_SUCCESS;
|
2018-08-10 16:54:53 -07:00
|
|
|
}
|
|
|
|
|
2018-08-10 16:59:44 -07:00
|
|
|
FUNCTION(and) {
|
2018-08-10 16:54:53 -07:00
|
|
|
int* left = libab_unwrap_param(params, 0);
|
|
|
|
int* right = libab_unwrap_param(params, 1);
|
2018-08-10 18:40:21 -07:00
|
|
|
libab_get_bool_value(ab, *left & *right, into);
|
2018-08-10 16:54:53 -07:00
|
|
|
return LIBAB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-08-10 16:59:44 -07:00
|
|
|
FUNCTION(or) {
|
2018-08-10 16:54:53 -07:00
|
|
|
int* left = libab_unwrap_param(params, 0);
|
|
|
|
int* right = libab_unwrap_param(params, 1);
|
2018-08-10 18:40:21 -07:00
|
|
|
libab_get_bool_value(ab, *left | *right, into);
|
2018-08-10 16:54:53 -07:00
|
|
|
return LIBAB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-08-10 16:59:44 -07:00
|
|
|
FUNCTION(xor) {
|
2018-08-10 16:54:53 -07:00
|
|
|
int* left = libab_unwrap_param(params, 0);
|
|
|
|
int* right = libab_unwrap_param(params, 1);
|
2018-08-10 18:40:21 -07:00
|
|
|
libab_get_bool_value(ab, *left ^ *right, into);
|
2018-08-10 16:54:53 -07:00
|
|
|
return LIBAB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-08-10 16:59:44 -07:00
|
|
|
FUNCTION(atan) {
|
2018-06-02 16:06:13 -07:00
|
|
|
printf("atan called\n");
|
|
|
|
double* val = libab_unwrap_param(params, 0);
|
|
|
|
return create_double_value(ab, atan(*val), into);
|
|
|
|
}
|
|
|
|
|
2018-08-10 16:59:44 -07:00
|
|
|
FUNCTION(atan2) {
|
2018-06-02 16:06:13 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-08-10 19:21:55 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-08-10 16:59:44 -07:00
|
|
|
FUNCTION(print_num) {
|
2018-06-02 16:06:13 -07:00
|
|
|
double* param = libab_unwrap_param(params, 0);
|
|
|
|
printf("%f\n", *param);
|
|
|
|
libab_get_unit_value(ab, into);
|
|
|
|
return LIBAB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-08-10 16:59:44 -07:00
|
|
|
FUNCTION(print_bool) {
|
2018-08-10 00:52:12 -07:00
|
|
|
int* param = libab_unwrap_param(params, 0);
|
|
|
|
printf("%s\n", *param ? "true" : "false");
|
|
|
|
libab_get_unit_value(ab, into);
|
|
|
|
return LIBAB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-08-10 16:59:44 -07:00
|
|
|
FUNCTION(print_unit) {
|
2018-06-02 16:06:13 -07:00
|
|
|
printf("()\n");
|
|
|
|
libab_get_unit_value(ab, into);
|
|
|
|
return LIBAB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2018-06-01 15:33:45 -07:00
|
|
|
#define OP_FUNCTION(name, expression) \
|
2018-06-21 14:25:11 -07:00
|
|
|
libab_result name(libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) { \
|
2018-06-01 15:33:45 -07:00
|
|
|
libab_result result = LIBAB_SUCCESS; \
|
|
|
|
double right; \
|
|
|
|
double left; \
|
|
|
|
printf(#name " called\n"); \
|
|
|
|
left = *((double*)libab_unwrap_param(params, 0)); \
|
|
|
|
right = *((double*)libab_unwrap_param(params, 1)); \
|
|
|
|
create_double_value(ab, expression, into); \
|
|
|
|
return result;\
|
|
|
|
}
|
2018-05-26 20:43:36 -07:00
|
|
|
|
2018-06-01 15:33:45 -07:00
|
|
|
OP_FUNCTION(function_plus, left + right)
|
|
|
|
OP_FUNCTION(function_minus, left - right)
|
|
|
|
OP_FUNCTION(function_times, left * right)
|
|
|
|
OP_FUNCTION(function_divide, left / right)
|
2018-05-23 15:41:17 -07:00
|
|
|
|
|
|
|
libab_result register_functions(libab* ab) {
|
|
|
|
libab_result result = LIBAB_SUCCESS;
|
|
|
|
libab_ref trig_type;
|
|
|
|
libab_ref atan2_type;
|
|
|
|
libab_ref difficult_type;
|
2018-06-02 15:37:15 -07:00
|
|
|
libab_ref print_num_type;
|
2018-06-02 16:06:13 -07:00
|
|
|
libab_ref print_unit_type;
|
2018-08-10 00:52:12 -07:00
|
|
|
libab_ref print_bool_type;
|
2018-08-10 16:54:53 -07:00
|
|
|
libab_ref bool_logic_type;
|
2018-08-10 18:40:21 -07:00
|
|
|
libab_ref bool_not_type;
|
2018-08-10 19:21:55 -07:00
|
|
|
libab_ref equals_num_type;
|
2018-05-23 15:41:17 -07:00
|
|
|
|
|
|
|
result = libab_create_type(ab, &trig_type, "(num)->num");
|
|
|
|
TRY(libab_create_type(ab, &atan2_type, "(num, num)->num"));
|
2018-08-10 19:21:55 -07:00
|
|
|
TRY(libab_create_type(ab, &equals_num_type, "(num, num)->bool"));
|
2018-05-23 15:41:17 -07:00
|
|
|
TRY(libab_create_type(ab, &difficult_type, "((num)->num)->num"));
|
2018-06-02 15:37:15 -07:00
|
|
|
TRY(libab_create_type(ab, &print_num_type, "(num)->unit"));
|
2018-06-02 16:06:13 -07:00
|
|
|
TRY(libab_create_type(ab, &print_unit_type, "(unit)->unit"));
|
2018-08-10 00:52:12 -07:00
|
|
|
TRY(libab_create_type(ab, &print_bool_type, "(bool)->unit"));
|
2018-08-10 16:54:53 -07:00
|
|
|
TRY(libab_create_type(ab, &bool_logic_type, "(bool,bool)->bool"));
|
2018-08-10 18:40:21 -07:00
|
|
|
TRY(libab_create_type(ab, &bool_not_type, "(bool)->bool"));
|
2018-05-23 15:41:17 -07:00
|
|
|
|
|
|
|
TRY(libab_register_function(ab, "atan", &trig_type, function_atan));
|
|
|
|
TRY(libab_register_function(ab, "atan2", &atan2_type, function_atan2));
|
2018-06-01 15:33:45 -07:00
|
|
|
TRY(libab_register_function(ab, "plus", &atan2_type, function_plus));
|
|
|
|
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));
|
2018-08-10 16:54:53 -07:00
|
|
|
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));
|
2018-08-10 18:40:21 -07:00
|
|
|
TRY(libab_register_function(ab, "not", &bool_not_type, function_not));
|
2018-08-10 19:21:55 -07:00
|
|
|
TRY(libab_register_function(ab, "equals", &equals_num_type, function_equals_num));
|
2018-06-02 15:37:15 -07:00
|
|
|
TRY(libab_register_function(ab, "print", &print_num_type, function_print_num));
|
2018-06-02 16:06:13 -07:00
|
|
|
TRY(libab_register_function(ab, "print", &print_unit_type, function_print_unit));
|
2018-08-10 00:52:12 -07:00
|
|
|
TRY(libab_register_function(ab, "print", &print_bool_type, function_print_bool));
|
2018-08-10 19:21:55 -07:00
|
|
|
TRY(libab_register_operator_infix(ab, "==", 0, -1, "equals"));
|
2018-06-01 15:24:55 -07:00
|
|
|
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"));
|
2018-08-10 16:54:53 -07:00
|
|
|
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"));
|
2018-08-10 18:40:21 -07:00
|
|
|
TRY(libab_register_operator_prefix(ab, "!", "not"));
|
2018-05-23 15:41:17 -07:00
|
|
|
|
|
|
|
libab_ref_free(&trig_type);
|
|
|
|
libab_ref_free(&atan2_type);
|
|
|
|
libab_ref_free(&difficult_type);
|
2018-06-02 15:37:15 -07:00
|
|
|
libab_ref_free(&print_num_type);
|
2018-06-02 16:06:13 -07:00
|
|
|
libab_ref_free(&print_unit_type);
|
2018-08-10 00:52:12 -07:00
|
|
|
libab_ref_free(&print_bool_type);
|
2018-08-10 18:40:21 -07:00
|
|
|
libab_ref_free(&bool_logic_type);
|
|
|
|
libab_ref_free(&bool_not_type);
|
2018-05-23 15:41:17 -07:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-06-21 17:23:34 -07:00
|
|
|
libab_result loop(libab* ab, int interaction_count, libab_ref* scope) {
|
|
|
|
libab_result result = LIBAB_SUCCESS;
|
2018-05-23 15:41:17 -07:00
|
|
|
char input_buffer[2048];
|
|
|
|
libab_ref eval_into;
|
2018-06-01 23:39:23 -07:00
|
|
|
libab_ref call_into;
|
2018-05-23 15:41:17 -07:00
|
|
|
libab_result eval_result;
|
|
|
|
|
2018-05-26 21:55:30 -07:00
|
|
|
while (interaction_count-- && result == LIBAB_SUCCESS) {
|
2018-05-23 15:41:17 -07:00
|
|
|
printf("(%d) > ", INTERACTIONS - interaction_count);
|
|
|
|
fgets(input_buffer, 2048, stdin);
|
2018-06-21 17:23:34 -07:00
|
|
|
eval_result = libab_run_scoped(ab, input_buffer, scope, &eval_into);
|
2018-05-23 15:41:17 -07:00
|
|
|
|
2018-05-26 21:55:30 -07:00
|
|
|
if (eval_result != LIBAB_SUCCESS) {
|
2018-06-20 13:55:28 -07:00
|
|
|
printf("Invalid input (error code %d).\n", eval_result);
|
2018-06-01 23:39:23 -07:00
|
|
|
} else {
|
2018-06-21 17:23:34 -07:00
|
|
|
result = libab_run_function_scoped(ab, "print", scope, &call_into, 1, &eval_into);
|
2018-08-10 16:15:58 -07:00
|
|
|
if(result == LIBAB_BAD_CALL) {
|
|
|
|
printf("(?)\n");
|
|
|
|
result = LIBAB_SUCCESS;
|
|
|
|
}
|
2018-06-01 23:39:23 -07:00
|
|
|
libab_ref_free(&call_into);
|
2018-05-23 15:41:17 -07:00
|
|
|
}
|
|
|
|
libab_ref_free(&eval_into);
|
|
|
|
}
|
|
|
|
|
2018-06-21 17:23:34 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
libab_result result;
|
|
|
|
libab_ref scope;
|
|
|
|
libab ab;
|
|
|
|
|
|
|
|
if (libab_init(&ab, impl_parse, impl_free) != LIBAB_SUCCESS) {
|
|
|
|
fprintf(stderr, "Failed to initialize libab.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
result = register_functions(&ab);
|
|
|
|
if(result == LIBAB_SUCCESS) {
|
|
|
|
result = libab_create_table(&scope, &ab.table);
|
|
|
|
}
|
|
|
|
if(result == LIBAB_SUCCESS) {
|
|
|
|
loop(&ab, INTERACTIONS, &scope);
|
|
|
|
libab_ref_free(&scope);
|
|
|
|
}
|
|
|
|
|
2018-05-23 15:41:17 -07:00
|
|
|
libab_free(&ab);
|
|
|
|
}
|