Add string output and precision setting.

This commit is contained in:
Danila Fedorin 2018-08-14 17:41:51 -07:00
parent d140ea6113
commit 9e75176612

View File

@ -3,11 +3,15 @@
#include <mpfr.h>
extern "C" {
#include "libabacus.h"
#include "value.h"
#include "util.h"
}
#define PRECISION 200
// == Global State (uh-oh)
bool close_requested = false;
long requested_precision = 3;
// == STRING Type
struct string {
@ -20,35 +24,39 @@ struct string {
struct number {
mpfr_t value;
number(const char* new_value) {
mpfr_init_set_str(value, new_value, 10, MPFR_RNDN);
mpfr_init2(value, PRECISION);
mpfr_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_init2(new_value, 200);
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_init2(new_value, 200);
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_init2(new_value, 200);
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_init2(new_value, 200);
mpfr_div(new_value, value, right.value, MPFR_RNDN);
return new number(std::move(new_value));
}
int to_int() {
return mpfr_get_si(value, MPFR_RNDN);
}
~number() {
mpfr_clear(value);
}
@ -143,8 +151,13 @@ FUNCTION(print_string) {
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, '.')));
char* str = mpfr_get_str(NULL, &exp, 10, requested_precision, num->value, MPFR_RNDN);
std::string output_string = std::string(str).insert(1, 1, '.');
if(exp != 1) {
output_string += "e";
output_string += std::to_string(exp - 1);
}
abacus_ref value = create_value(ab, new string(std::move(output_string)));
libab_ref_copy(value, into);
mpfr_free_str(str);
return LIBAB_SUCCESS;
@ -169,6 +182,13 @@ FUNCTION(quit) {
return LIBAB_SUCCESS;
}
FUNCTION(request_precision) {
number* value = (number*) libab_unwrap_param(params, 0);
requested_precision = std::min(PRECISION / 4, std::max(2, value->to_int()));
libab_get_unit_value(ab, into);
return LIBAB_SUCCESS;
}
// == Main class
class abacus {
private:
@ -180,6 +200,9 @@ class abacus {
abacus();
void add_function(const std::string& name, libab_function_ptr ptr, const std::string& type);
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();
};
@ -212,16 +235,38 @@ abacus_ref abacus::run(const std::string& code) {
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;
}
template <typename T>
T* get(libab_ref* ref) {
return (T*) libab_ref_get(ref);
}
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;
std::string buffer;
ab.add_function("quit", function_quit, "()->unit");
ab.add_function("request_precision", function_request_precision, "(num)->unit");
ab.add_function("print", function_print_string, "(str)->unit");
ab.add_function("to_string", function_to_string_num, "(num)->str");
@ -237,6 +282,8 @@ int main() {
abacus_ref value = ab.run(buffer);
if(value == nullptr) {
std::cout << "Invalid expression." << std::endl;
} else {
std::cout << ab.to_string(value) << std::endl;
}
}
}