diff --git a/include/abacus.hpp b/include/abacus.hpp new file mode 100644 index 0000000..25eaa6d --- /dev/null +++ b/include/abacus.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include "ref.hpp" +extern "C" { +#include "libabacus.h" +#include "table.h" +#include "value.h" +#include "util.h" +} + +class abacus { + private: + libab ab; + abacus_ref scope; + std::map compiled_types; + libab_basetype basetype_string = { [](void* s) { delete ((string*) s); }, NULL, 0 }; + public: + abacus(); + void add_variable(const std::string& name, abacus_ref val); + void add_function(const std::string& name, libab_function_ptr ptr, const std::string& type); + void add_operator_infix(const std::string& op, const std::string& func, int assoc, int prec); + void add_operator_prefix(const std::string& op, const std::string& func); + void add_operator_postfix(const std::string& op, const std::string& func); + abacus_ref run(const std::string& code); + template + abacus_ref call(const std::string& bane, Ts...params); + std::string to_string(abacus_ref& value); + ~abacus(); +}; + +abacus::abacus() { + auto parse_function = [](const char* s) { + return (void*) new number(s); + }; + auto free_function = [](void* num) { + delete ((number*) num); + }; + libab_init(&ab, parse_function, free_function); + libab_register_basetype(&ab, "str", &basetype_string); + libab_create_table(&ab, scope, &ab.table); +} + +void abacus::add_variable(const std::string& name, abacus_ref val) { + libab_table_entry* entry = libab_table_search_entry_value(get(scope), name.c_str()); + if(entry) { + libab_ref_free(&entry->data_u.value); + libab_ref_copy(val, &entry->data_u.value); + } else { + libab_put_table_value(get(scope), name.c_str(), std::move(val)); + } +} + +void abacus::add_function(const std::string& name, libab_function_ptr ptr, const std::string& type) { + if(compiled_types.find(type) != compiled_types.end()) { + libab_register_function(&ab, name.c_str(), compiled_types[type], ptr); + } else { + abacus_ref& new_ref = compiled_types[type]; + libab_create_type(&ab, new_ref, type.c_str()); + libab_register_function(&ab, name.c_str(), new_ref, ptr); + } +} + +void abacus::add_operator_infix(const std::string& op, const std::string& func, int assoc, int prec) { + libab_register_operator_infix(&ab, op.c_str(), prec, assoc, func.c_str()); +} +void abacus::add_operator_prefix(const std::string& op, const std::string& func) { + libab_register_operator_prefix(&ab, op.c_str(), func.c_str()); +} +void abacus::add_operator_postfix(const std::string& op, const std::string& func) { + libab_register_operator_postfix(&ab, op.c_str(), func.c_str()); +} + +abacus_ref abacus::run(const std::string& code) { + abacus_ref value; + libab_run_scoped(&ab, code.c_str(), scope, value); + libab_gc_run(&ab.containers); + return value; +} + +template +abacus_ref abacus::call(const std::string& name, Ts...params) { + abacus_ref value; + libab_run_function_scoped(&ab, name.c_str(), scope, value, sizeof...(params), (libab_ref*) params...); + libab_gc_run(&ab.containers); + return value; +} + +std::string abacus::to_string(abacus_ref& val) { + abacus_ref string_value = call("to_string", val); + if(string_value == nullptr) return "Unable to convert to string."; + libab_basetype* base = get(&get(string_value)->type)->data_u.base; + if(base != &basetype_string) return "\"to_string\" did not return string."; + return get(&get(string_value)->data)->value; +} + +abacus::~abacus() { + scope = nullptr; + libab_free(&ab); +} diff --git a/include/config.hpp b/include/config.hpp new file mode 100644 index 0000000..3fc4e51 --- /dev/null +++ b/include/config.hpp @@ -0,0 +1,3 @@ +#pragma once + +#define PRECISION 200 diff --git a/include/functions.hpp b/include/functions.hpp new file mode 100644 index 0000000..9654802 --- /dev/null +++ b/include/functions.hpp @@ -0,0 +1,61 @@ +#pragma once + +extern "C" { +#include "libabacus.h" +} + +#define FUNCTION(name) libab_result function_##name( \ + libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) + +#define FUNCTION_MPFR(name, func) FUNCTION(name) { \ + number* value = (number*) libab_unwrap_param(params, 0); \ + mpfr_t output; \ + mpfr_init2(output, PRECISION); \ + mpfr_##func(output, value->value, MPFR_RNDN); \ + abacus_ref to_return = create_value(ab, new number(std::move(output))); \ + libab_ref_copy(to_return, into); \ + return LIBAB_SUCCESS; \ +} + +#define FUNCTION_MPFR2(name, func) FUNCTION(name) { \ + number* left = (number*) libab_unwrap_param(params, 0); \ + number* right = (number*) libab_unwrap_param(params, 1); \ + mpfr_t output; \ + mpfr_init2(output, PRECISION); \ + mpfr_##func(output, left->value, right->value, MPFR_RNDN); \ + abacus_ref to_return = create_value(ab, new number(std::move(output))); \ + libab_ref_copy(to_return, into); \ + return LIBAB_SUCCESS; \ +} + +#define FUNCTION_COMPARE(name, op) FUNCTION(name) { \ + number* left = (number*) libab_unwrap_param(params, 0); \ + number* right = (number*) libab_unwrap_param(params, 1); \ + libab_get_bool_value(ab, mpfr_cmp(left->value, right->value) op 0, into); \ + return LIBAB_SUCCESS; \ +} + +FUNCTION(print_string); +FUNCTION(to_string_num); +FUNCTION(to_string_bool); +FUNCTION(to_string_unit); +FUNCTION(plus); +FUNCTION(minus); +FUNCTION(times); +FUNCTION(divide); +FUNCTION(lt); +FUNCTION(lte); +FUNCTION(equals); +FUNCTION(gt); +FUNCTION(gte); +FUNCTION(negate); +FUNCTION(ln); +FUNCTION(exp); +FUNCTION(sin); +FUNCTION(cos); +FUNCTION(tan); +FUNCTION(arcsin); +FUNCTION(arccos); +FUNCTION(arctan); +FUNCTION(quit); +FUNCTION(request_precision); diff --git a/include/ref.hpp b/include/ref.hpp new file mode 100644 index 0000000..2ef97c3 --- /dev/null +++ b/include/ref.hpp @@ -0,0 +1,65 @@ +#pragma once + +extern "C" { +#include "libabacus.h" +#include "util.h" +} + +class abacus_ref { + private: + libab_ref ref; + public: + abacus_ref(); + abacus_ref(void* data, void (*free_func)(void*)); + abacus_ref(const abacus_ref& other); + abacus_ref& operator=(const abacus_ref& other); + abacus_ref& operator=(std::nullptr_t); + template + bool operator==(T data); + operator libab_ref*() { + return &ref; + } + ~abacus_ref(); +}; + +template +T* get(libab_ref* ref) { + return (T*) libab_ref_get(ref); +} + +abacus_ref::abacus_ref() { + libab_ref_null(&ref); +} + +abacus_ref::abacus_ref(void* data, void (*free_func)(void*)) { + libab_ref_new(&ref, data, free_func); +} + +abacus_ref::abacus_ref(const abacus_ref& other) { + libab_ref_copy(&other.ref, &ref); +} + +abacus_ref& abacus_ref::operator=(const abacus_ref& other) { + libab_ref_copy(&other.ref, &ref); + return *this; +} + +abacus_ref& abacus_ref::operator=(std::nullptr_t t) { + libab_ref_free(&ref); + libab_ref_null(&ref); + return *this; +} + +template +bool abacus_ref::operator==(T data) { + return libab_ref_get(&ref) == (void*) data; +} + +template <> +bool abacus_ref::operator==(std::nullptr_t t) { + return libab_ref_get(&ref) == t; +} + +abacus_ref::~abacus_ref() { + libab_ref_free(&ref); +} diff --git a/include/types.hpp b/include/types.hpp new file mode 100644 index 0000000..ea7392c --- /dev/null +++ b/include/types.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include "config.hpp" + +struct string { + std::string value; + string(std::string&& new_value) : value(std::move(new_value)) {} + string(const std::string& new_value) : value(new_value) {} +}; + +struct number { + mpfr_t value; + number(const char* new_value) { + mpfr_init2(value, PRECISION); + mpfr_set_str(value, new_value, 10, MPFR_RNDN); + } + number(mpfr_t&& new_value) { + std::swap(value, new_value); + } + int to_int() { + return mpfr_get_si(value, MPFR_RNDN); + } + ~number() { + mpfr_clear(value); + } +}; + diff --git a/src/main.cpp b/src/main.cpp index 56d73e8..dc8feec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,10 @@ #include #include #include +#include "types.hpp" +#include "ref.hpp" +#include "functions.hpp" +#include "abacus.hpp" extern "C" { #include "libabacus.h" #include "table.h" @@ -10,99 +14,13 @@ extern "C" { #include "util.h" } -#define PRECISION 200 // == Global State (uh-oh) bool close_requested = false; long requested_precision = 3; -// == STRING Type -struct string { - std::string value; - string(std::string&& new_value) : value(std::move(new_value)) {} - string(const std::string& new_value) : value(new_value) {} -}; - -// MPFR Type -struct number { - mpfr_t value; - number(const char* new_value) { - mpfr_init2(value, PRECISION); - mpfr_set_str(value, new_value, 10, MPFR_RNDN); - } - number(mpfr_t&& new_value) { - std::swap(value, new_value); - } - int to_int() { - return mpfr_get_si(value, MPFR_RNDN); - } - ~number() { - mpfr_clear(value); - } -}; - -// == Reference Wrapper -class abacus_ref { - private: - libab_ref ref; - public: - abacus_ref(); - abacus_ref(void* data, void (*free_func)(void*)); - abacus_ref(const abacus_ref& other); - abacus_ref& operator=(const abacus_ref& other); - abacus_ref& operator=(std::nullptr_t); - template - bool operator==(T data); - operator libab_ref*() { - return &ref; - } - ~abacus_ref(); -}; - -template -T* get(libab_ref* ref) { - return (T*) libab_ref_get(ref); -} - -abacus_ref::abacus_ref() { - libab_ref_null(&ref); -} - -abacus_ref::abacus_ref(void* data, void (*free_func)(void*)) { - libab_ref_new(&ref, data, free_func); -} - -abacus_ref::abacus_ref(const abacus_ref& other) { - libab_ref_copy(&other.ref, &ref); -} - -abacus_ref& abacus_ref::operator=(const abacus_ref& other) { - libab_ref_copy(&other.ref, &ref); - return *this; -} - -abacus_ref& abacus_ref::operator=(std::nullptr_t t) { - libab_ref_free(&ref); - libab_ref_null(&ref); - return *this; -} - -template -bool abacus_ref::operator==(T data) { - return libab_ref_get(&ref) == (void*) data; -} - -template <> -bool abacus_ref::operator==(std::nullptr_t t) { - return libab_ref_get(&ref) == t; -} - -abacus_ref::~abacus_ref() { - libab_ref_free(&ref); -} // // == BASIC FUNCTIONS -#define FUNCTION(name) libab_result function_##name(libab* ab, libab_ref* scope, libab_ref_vec* params, libab_ref* into) template abacus_ref create_value(libab* ab, T* val); @@ -160,42 +78,6 @@ FUNCTION(to_string_unit) { return LIBAB_SUCCESS; } -#define OPERATOR_FUNCTION(name, op) FUNCTION(name) { \ - number* left = (number*) libab_unwrap_param(params, 0); \ - number* right = (number*) libab_unwrap_param(params, 1); \ - abacus_ref value = create_value(ab, *left op *right); \ - libab_ref_copy(value, into); \ - return LIBAB_SUCCESS; \ -} - -#define FUNCTION_MPFR(name, func) FUNCTION(name) { \ - number* value = (number*) libab_unwrap_param(params, 0); \ - mpfr_t output; \ - mpfr_init2(output, PRECISION); \ - mpfr_##func(output, value->value, MPFR_RNDN); \ - abacus_ref to_return = create_value(ab, new number(std::move(output))); \ - libab_ref_copy(to_return, into); \ - return LIBAB_SUCCESS; \ -} - -#define FUNCTION_MPFR2(name, func) FUNCTION(name) { \ - number* left = (number*) libab_unwrap_param(params, 0); \ - number* right = (number*) libab_unwrap_param(params, 1); \ - mpfr_t output; \ - mpfr_init2(output, PRECISION); \ - mpfr_##func(output, left->value, right->value, MPFR_RNDN); \ - abacus_ref to_return = create_value(ab, new number(std::move(output))); \ - libab_ref_copy(to_return, into); \ - return LIBAB_SUCCESS; \ -} - -#define FUNCTION_COMPARE(name, op) FUNCTION(name) { \ - number* left = (number*) libab_unwrap_param(params, 0); \ - number* right = (number*) libab_unwrap_param(params, 1); \ - libab_get_bool_value(ab, mpfr_cmp(left->value, right->value) op 0, into); \ - return LIBAB_SUCCESS; \ -} - FUNCTION_MPFR2(plus, add) FUNCTION_MPFR2(minus, sub) FUNCTION_MPFR2(times, mul) @@ -221,8 +103,6 @@ FUNCTION_MPFR(arcsin, asin); FUNCTION_MPFR(arccos, acos); FUNCTION_MPFR(arctan, atan); -FUNCTION(sqrt); - FUNCTION(quit) { close_requested = true; libab_get_unit_value(ab, into); @@ -236,96 +116,6 @@ FUNCTION(request_precision) { return LIBAB_SUCCESS; } -// == Main class -class abacus { - private: - libab ab; - abacus_ref scope; - std::map compiled_types; - libab_basetype basetype_string = { [](void* s) { delete ((string*) s); }, NULL, 0 }; - public: - abacus(); - void add_variable(const std::string& name, abacus_ref val); - void add_function(const std::string& name, libab_function_ptr ptr, const std::string& type); - void add_operator_infix(const std::string& op, const std::string& func, int assoc, int prec); - void add_operator_prefix(const std::string& op, const std::string& func); - void add_operator_postfix(const std::string& op, const std::string& func); - abacus_ref run(const std::string& code); - template - abacus_ref call(const std::string& bane, Ts...params); - std::string to_string(abacus_ref& value); - ~abacus(); -}; - -abacus::abacus() { - auto parse_function = [](const char* s) { - return (void*) new number(s); - }; - auto free_function = [](void* num) { - delete ((number*) num); - }; - libab_init(&ab, parse_function, free_function); - libab_register_basetype(&ab, "str", &basetype_string); - libab_create_table(&ab, scope, &ab.table); -} - -void abacus::add_variable(const std::string& name, abacus_ref val) { - libab_table_entry* entry = libab_table_search_entry_value(get(scope), name.c_str()); - if(entry) { - libab_ref_free(&entry->data_u.value); - libab_ref_copy(val, &entry->data_u.value); - } else { - libab_put_table_value(get(scope), name.c_str(), std::move(val)); - } -} - -void abacus::add_function(const std::string& name, libab_function_ptr ptr, const std::string& type) { - if(compiled_types.find(type) != compiled_types.end()) { - libab_register_function(&ab, name.c_str(), compiled_types[type], ptr); - } else { - abacus_ref& new_ref = compiled_types[type]; - libab_create_type(&ab, new_ref, type.c_str()); - libab_register_function(&ab, name.c_str(), new_ref, ptr); - } -} - -void abacus::add_operator_infix(const std::string& op, const std::string& func, int assoc, int prec) { - libab_register_operator_infix(&ab, op.c_str(), prec, assoc, func.c_str()); -} -void abacus::add_operator_prefix(const std::string& op, const std::string& func) { - libab_register_operator_prefix(&ab, op.c_str(), func.c_str()); -} -void abacus::add_operator_postfix(const std::string& op, const std::string& func) { - libab_register_operator_postfix(&ab, op.c_str(), func.c_str()); -} - -abacus_ref abacus::run(const std::string& code) { - abacus_ref value; - libab_run_scoped(&ab, code.c_str(), scope, value); - libab_gc_run(&ab.containers); - return value; -} - -template -abacus_ref abacus::call(const std::string& name, Ts...params) { - abacus_ref value; - libab_run_function_scoped(&ab, name.c_str(), scope, value, sizeof...(params), (libab_ref*) params...); - libab_gc_run(&ab.containers); - return value; -} - -std::string abacus::to_string(abacus_ref& val) { - abacus_ref string_value = call("to_string", val); - if(string_value == nullptr) return "Unable to convert to string."; - libab_basetype* base = get(&get(string_value)->type)->data_u.base; - if(base != &basetype_string) return "\"to_string\" did not return string."; - return get(&get(string_value)->data)->value; -} - -abacus::~abacus() { - scope = nullptr; - libab_free(&ab); -} int main() { abacus ab; rl_bind_key('\t', rl_insert);