|
|
|
@ -3,6 +3,10 @@ |
|
|
|
|
#include <mpfr.h> |
|
|
|
|
#include <readline/readline.h> |
|
|
|
|
#include <readline/history.h> |
|
|
|
|
#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 <typename T> |
|
|
|
|
bool operator==(T data); |
|
|
|
|
operator libab_ref*() { |
|
|
|
|
return &ref; |
|
|
|
|
} |
|
|
|
|
~abacus_ref(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
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 <typename T> |
|
|
|
|
bool abacus_ref::operator==(T data) { |
|
|
|
|
return libab_ref_get(&ref) == (void*) data; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <> |
|
|
|
|
bool abacus_ref::operator==<std::nullptr_t>(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 <typename T> |
|
|
|
|
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<number>(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<number>(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<std::string, abacus_ref> 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 <typename ... Ts> |
|
|
|
|
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<libab_table>(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<libab_table>(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 <typename ... Ts> |
|
|
|
|
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<libab_parsetype>(&get<libab_value>(string_value)->type)->data_u.base; |
|
|
|
|
if(base != &basetype_string) return "\"to_string\" did not return string."; |
|
|
|
|
return get<string>(&get<libab_value>(string_value)->data)->value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
abacus::~abacus() { |
|
|
|
|
scope = nullptr; |
|
|
|
|
libab_free(&ab); |
|
|
|
|
} |
|
|
|
|
int main() { |
|
|
|
|
abacus ab; |
|
|
|
|
rl_bind_key('\t', rl_insert); |
|
|
|
|