diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6ff9b9e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.1) +project(cmdAbacus) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(MPFR REQUIRED mpfr) +set(CMAKE_CXX_STANDARD 11) + +add_subdirectory(external/libabacus) +add_executable(cmdAbacus src/main.cpp) +target_link_libraries(cmdAbacus abacus ${MPFR_LIBRARIES}) +target_include_directories(cmdAbacus PUBLIC include ${MPFR_INCLUDE_DIRS}) +target_compile_options(cmdAbacus PUBLIC ${MPFR_CFLAGS_OTHER}) diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..befe8e1 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,199 @@ +#include +#include +#include +extern "C" { +#include "libabacus.h" +#include "util.h" +} + +// == 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_init_set_str(value, new_value, 10, MPFR_RNDN); + } + number(mpfr_t&& new_value) { + std::swap(value, new_value); + } + number* operator+(const number& right) { + mpfr_t new_value; + mpfr_init(new_value); + mpfr_add(new_value, value, right.value, MPFR_RNDN); + return new number(std::move(new_value)); + } + number* operator-(const number& right) { + mpfr_t new_value; + mpfr_init(new_value); + mpfr_sub(new_value, value, right.value, MPFR_RNDN); + return new number(std::move(new_value)); + } + number* operator*(const number& right) { + mpfr_t new_value; + mpfr_init(new_value); + mpfr_mul(new_value, value, right.value, MPFR_RNDN); + return new number(std::move(new_value)); + } + number* operator/(const number& right) { + mpfr_t new_value; + mpfr_init(new_value); + mpfr_div(new_value, value, right.value, MPFR_RNDN); + return new number(std::move(new_value)); + } + ~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); + operator libab_ref*() { + return &ref; + } + ~abacus_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() { + 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); + +template <> +abacus_ref create_value(libab* ab, string* param) { + abacus_ref type; + abacus_ref value; + libab_create_type(ab, type, "str"); + libab_create_value_raw(ab, value, (void*) param, type); + return value; +} + +template <> +abacus_ref create_value(libab* ab, number* param) { + abacus_ref type; + abacus_ref value; + libab_get_type_num(ab, type); + libab_create_value_raw(ab, value, (void*) param, type); + return value; +} + +FUNCTION(print_string) { + string* param = (string*) libab_unwrap_param(params, 0); + std::cout << param->value << std::endl; + libab_get_unit_value(ab, into); + return LIBAB_SUCCESS; +} + +FUNCTION(to_string_num) { + number* num = (number*) libab_unwrap_param(params, 0); + mpfr_exp_t exp; + char* str = mpfr_get_str(NULL, &exp, 10, 0, num->value, MPFR_RNDN); + abacus_ref value = create_value(ab, new string(std::string(str).insert(exp, 1, '.'))); + libab_ref_copy(value, into); + mpfr_free_str(str); + 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; \ +} + +OPERATOR_FUNCTION(plus, +) +OPERATOR_FUNCTION(minus, -) +OPERATOR_FUNCTION(times, *) +OPERATOR_FUNCTION(divide, /) + +// == 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_function(const std::string& name, libab_function_ptr ptr, const std::string& type); + abacus_ref run(const std::string& code); + ~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_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); + } +} + +abacus_ref abacus::run(const std::string& code) { + abacus_ref value; + libab_run_scoped(&ab, code.c_str(), scope, value); + return value; +} + +abacus::~abacus() { + libab_free(&ab); +} + +int main() { + abacus ab; + ab.add_function("print", function_print_string, "(str)->unit"); + ab.add_function("to_string", function_to_string_num, "(num)->str"); + ab.add_function("plus", function_plus, "(num, num)->num"); + ab.add_function("minus", function_minus, "(num, num)->num"); + ab.add_function("times", function_times, "(num, num)->num"); + ab.add_function("divide", function_divide, "(num, num)->num"); + ab.run("print(to_string(plus(1, times(3, 3))))"); +}