aboutsummaryrefslogtreecommitdiff
path: root/types.cpp
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2013-08-11 14:42:49 +0800
committerTeddy <ted.sybil@gmail.com>2013-08-11 14:42:49 +0800
commit04f0c9294a8da8c37ef3466fbcddf2a23b649608 (patch)
treeaf9fa5951b720e3c8734043df2d23e67df6eadfe /types.cpp
parent6ee68e0b6ac242c242e2c057ba583974ce47bed9 (diff)
...
Diffstat (limited to 'types.cpp')
-rw-r--r--types.cpp906
1 files changed, 906 insertions, 0 deletions
diff --git a/types.cpp b/types.cpp
new file mode 100644
index 0000000..c2e3bea
--- /dev/null
+++ b/types.cpp
@@ -0,0 +1,906 @@
+#include "types.h"
+#include "model.h"
+#include "exc.h"
+#include "consts.h"
+
+#include <cmath>
+#include <cstdlib>
+#include <sstream>
+#include <iomanip>
+
+const double EPS = 1e-16;
+const int PREC = 16;
+
+EmptyList *empty_list = new EmptyList();
+
+Pair::Pair(EvalObj *_car, EvalObj *_cdr) :
+ EvalObj(CLS_PAIR_OBJ), car(_car), cdr(_cdr),
+ next(NULL) {}
+
+ ReprCons *Pair::get_repr_cons() {
+ return new PairReprCons(this, this);
+ }
+
+RetAddr::RetAddr(Pair *_addr) : FrameObj(CLS_RET_ADDR), addr(_addr) {}
+
+ParseBracket::ParseBracket(unsigned char _btype) :
+ FrameObj(CLS_SIM_OBJ | CLS_PAR_BRA), btype(_btype) {}
+
+ UnspecObj::UnspecObj() : EvalObj(CLS_SIM_OBJ) {}
+
+ ReprCons *UnspecObj::get_repr_cons() {
+ return new ReprStr("#<Unspecified>");
+ }
+
+SymObj::SymObj(const string &str) :
+ EvalObj(CLS_SIM_OBJ | CLS_SYM_OBJ), val(str) {}
+
+ ReprCons *SymObj::get_repr_cons() {
+ return new ReprStr(val);
+ }
+
+OptObj::OptObj() : EvalObj(CLS_SIM_OBJ | CLS_OPT_OBJ) {}
+
+ProcObj::ProcObj(Pair *_body,
+ Environment *_envt,
+ EvalObj *_params) :
+ OptObj(), body(_body), params(_params), envt(_envt) {}
+
+ Pair *ProcObj::call(Pair *args, Environment * &genvt,
+ Continuation * &cont, FrameObj ** &top_ptr) {
+ // Create a new continuation
+ // static_cast see `call` invocation in eval.cpp
+ Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr;
+ Continuation *_cont = new Continuation(genvt, ret_addr, cont, body);
+ // Create local env and recall the closure
+ Environment *_envt = new Environment(envt);
+ // static_cast<SymObj*> because the params is already checked
+ EvalObj *ppar, *nptr;
+ for (ppar = params;
+ ppar->is_pair_obj();
+ ppar = TO_PAIR(ppar)->cdr)
+ {
+ if ((nptr = args->cdr) != empty_list)
+ args = TO_PAIR(nptr);
+ else break;
+ _envt->add_binding(static_cast<SymObj*>(TO_PAIR(ppar)->car), args->car);
+ }
+
+ if (ppar->is_sym_obj())
+ _envt->add_binding(static_cast<SymObj*>(ppar), args->cdr); // (... . var_n)
+ else if (args->cdr != empty_list || ppar != empty_list)
+ throw TokenError("", RUN_ERR_WRONG_NUM_OF_ARGS);
+
+ genvt = _envt;
+ cont = _cont;
+ *top_ptr++ = new RetAddr(NULL); // Mark the entrance of a cont
+ return body; // Move pc to the proc entry point
+ }
+
+ReprCons *ProcObj::get_repr_cons() {
+ return new ReprStr("#<Procedure>");
+}
+
+SpecialOptObj::SpecialOptObj(string _name) : OptObj(), name(_name) {}
+
+BoolObj::BoolObj(bool _val) : EvalObj(CLS_SIM_OBJ | CLS_BOOL_OBJ), val(_val) {}
+
+bool BoolObj::is_true() { return val; }
+
+ReprCons *BoolObj::get_repr_cons() {
+ return new ReprStr(val ? "#t" : "#f");
+}
+
+BoolObj *BoolObj::from_string(string repr) {
+ if (repr.length() != 2 || repr[0] != '#')
+ return NULL;
+ if (repr[1] == 't')
+ return new BoolObj(true);
+ else if (repr[1] == 'f')
+ return new BoolObj(false);
+ return NULL;
+}
+
+NumObj::NumObj(NumLvl _level, bool _exactness) :
+ EvalObj(CLS_SIM_OBJ | CLS_NUM_OBJ), exactness(_exactness), level(_level) {}
+
+ bool NumObj::is_exact() { return exactness; }
+
+ StrObj::StrObj(string _str) : EvalObj(CLS_SIM_OBJ | CLS_STR_OBJ), str(_str) {}
+
+ ReprCons *StrObj::get_repr_cons() {
+ return new ReprStr(str);
+ }
+
+CharObj::CharObj(char _ch) : EvalObj(CLS_SIM_OBJ | CLS_CHAR_OBJ), ch(_ch) {}
+
+CharObj *CharObj::from_string(string repr) {
+ size_t len = repr.length();
+ if (len < 2) return NULL;
+ if (repr[0] != '#' || repr[1] != '\\') return NULL;
+ if (len == 3) return new CharObj(repr[2]);
+ string char_name = repr.substr(2, len - 2);
+ if (char_name == "newline") return new CharObj('\n');
+ if (char_name == "space") return new CharObj(' ');
+ throw TokenError(char_name, RUN_ERR_UNKNOWN_CHAR_NAME);
+}
+
+ReprCons *CharObj::get_repr_cons() {
+ string val = "";
+ if (ch == ' ') val = "space";
+ else if (ch == '\n') val = "newline";
+ else val += ch;
+ return new ReprStr("#\\" + val);
+}
+
+VecObj::VecObj() : EvalObj(CLS_SIM_OBJ | CLS_VECT_OBJ) {}
+
+EvalObj *VecObj::get_obj(int idx) {
+ return vec[idx];
+}
+
+size_t VecObj::get_size() {
+ return vec.end() - vec.begin();
+}
+
+void VecObj::resize(int new_size) {
+ vec.resize(new_size);
+}
+
+void VecObj::push_back(EvalObj *new_elem) {
+ vec.push_back(new_elem);
+}
+
+ReprCons *VecObj::get_repr_cons() {
+ return new VectReprCons(this, this);
+}
+
+StrObj *StrObj::from_string(string repr) {
+ size_t len = repr.length();
+ if (repr[0] == '\"' && repr[len - 1] == '\"')
+ return new StrObj(repr.substr(1, len - 2));
+ return NULL;
+}
+
+bool StrObj::lt(StrObj *r) {
+ return str < r->str;
+}
+
+bool StrObj::gt(StrObj *r) {
+ return str > r->str;
+}
+
+bool StrObj::le(StrObj *r) {
+ return str <= r->str;
+}
+
+bool StrObj::ge(StrObj *r) {
+ return str >= r->str;
+}
+
+bool StrObj::eq(StrObj *r) {
+ return str == r->str;
+}
+
+BuiltinProcObj::BuiltinProcObj(BuiltinProc f, string _name) :
+ OptObj(), handler(f), name(_name) {}
+
+ Pair *BuiltinProcObj::call(Pair *args, Environment * &envt,
+ Continuation * &cont, FrameObj ** &top_ptr) {
+
+ Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr;
+ *top_ptr++ = handler(TO_PAIR(args->cdr), name);
+ return ret_addr->next; // Move to the next instruction
+ }
+
+ReprCons *BuiltinProcObj::get_repr_cons() {
+ return new ReprStr("#<Builtin Procedure: " + name + ">");
+}
+
+Environment::Environment(Environment *_prev_envt) : prev_envt(_prev_envt) {}
+
+bool Environment::add_binding(SymObj *sym_obj, EvalObj *eval_obj, bool def) {
+ bool has_key = binding.count(sym_obj->val);
+ if (!def && !has_key) return false;
+ binding[sym_obj->val] = eval_obj;
+ return true;
+}
+
+EvalObj *Environment::get_obj(EvalObj *obj) {
+ if (!obj->is_sym_obj()) return obj;
+ SymObj *sym_obj = static_cast<SymObj*>(obj);
+
+ string name(sym_obj->val);
+ for (Environment *ptr = this; ptr; ptr = ptr->prev_envt)
+ {
+ bool has_key = ptr->binding.count(name);
+ if (has_key) return ptr->binding[name];
+ }
+ // Object not found
+ throw TokenError(name, RUN_ERR_UNBOUND_VAR);
+}
+
+Continuation::Continuation(Environment *_envt, Pair *_pc,
+ Continuation *_prev_cont,
+ Pair *_proc_body) :
+ prev_cont(_prev_cont), envt(_envt), pc(_pc),
+ proc_body(_proc_body) {}
+
+ ReprCons::ReprCons(bool _done, EvalObj *_ori) : ori(_ori), done(_done) {}
+ ReprStr::ReprStr(string _repr) : ReprCons(true) { repr = _repr; }
+ EvalObj *ReprStr::next(const string &prev) {
+ throw NormalError(INT_ERR);
+ }
+
+PairReprCons::PairReprCons(Pair *_ptr, EvalObj *_ori) :
+ ReprCons(false, _ori), state(0), ptr(_ptr) {}
+
+ EvalObj *PairReprCons::next(const string &prev) {
+ repr += prev;
+ EvalObj *res;
+ if (state == 0)
+ {
+ state = 1;
+ res = TO_PAIR(ptr)->car;
+ if (res->is_pair_obj())
+ repr += "(";
+ return res;
+ }
+ else if (state == 1)
+ {
+ state = 2;
+ if (TO_PAIR(ptr)->car->is_pair_obj())
+ repr += ")";
+ ptr = TO_PAIR(ptr)->cdr;
+ if (ptr == empty_list)
+ return NULL;
+ repr += " ";
+ if (ptr->is_simple_obj())
+ repr += ". ";
+ return ptr;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+VectReprCons::VectReprCons(VecObj *_ptr, EvalObj *_ori) :
+ ReprCons(false, _ori), ptr(_ptr), idx(0) { repr = "#("; }
+
+ EvalObj *VectReprCons::next(const string &prev) {
+ repr += prev;
+
+ if (idx && ptr->get_obj(idx - 1)->is_pair_obj())
+ repr += ")";
+
+ if (idx == ptr->get_size())
+ {
+ repr += ")";
+ return NULL;
+ }
+ else
+ {
+ if (idx) repr += " ";
+ EvalObj *res = ptr->get_obj(idx++);
+ if (res->is_pair_obj())
+ repr += "(";
+ return res;
+ }
+ }
+
+PromObj::PromObj(EvalObj *exp) :
+ EvalObj(CLS_SIM_OBJ | CLS_PROM_OBJ), entry(new Pair(exp, empty_list)), mem(NULL) {}
+
+Pair *PromObj::get_entry() { return entry; }
+
+ReprCons *PromObj::get_repr_cons() { return new ReprStr("#<Promise>"); }
+
+EvalObj *PromObj::get_mem() { return mem; }
+
+void PromObj::feed_mem(EvalObj *res) { mem = res; }
+
+
+string double_to_str(double val, bool force_sign = false) {
+ std::stringstream ss;
+ if (force_sign) ss << std::showpos;
+ ss << std::setprecision(PREC);
+ ss << val;
+ return ss.str();
+}
+
+string int_to_str(int val) {
+ std::stringstream ss;
+ ss << val;
+ return ss.str();
+}
+
+double str_to_double(string repr, bool &flag) {
+ const char *nptr = repr.c_str();
+ char *endptr;
+ double val = strtod(nptr, &endptr);
+ if (endptr == nptr || endptr != nptr + repr.length())
+ {
+ flag = false;
+ return 0;
+ }
+ flag = true;
+ return val;
+}
+
+int str_to_int(string repr, bool &flag) {
+ const char *nptr = repr.c_str();
+ char *endptr;
+ int val = strtol(nptr, &endptr, 10);
+ if (endptr == nptr || endptr != nptr + repr.length())
+ {
+ flag = false;
+ return 0;
+ }
+ flag = true;
+ return val;
+}
+
+
+int gcd(int a, int b) {
+ int t;
+ while (b) t = b, b = a % b, a = t;
+ return abs(a);
+}
+
+bool is_zero(double x) {
+ return -EPS < x && x < EPS;
+}
+
+InexactNumObj::InexactNumObj(NumLvl level) : NumObj(level, false) {}
+
+CompNumObj::CompNumObj(double _real, double _imag) :
+ InexactNumObj(NUM_LVL_COMP), real(_real), imag(_imag) {}
+
+ CompNumObj *CompNumObj::from_string(string repr) {
+ // spos: the position of the last sign
+ // ipos: the position of i
+ long long spos = -1, ipos = -1;
+ size_t len = repr.length();
+ bool sign;
+ for (size_t i = 0; i < len; i++)
+ if (repr[i] == '+' || repr[i] == '-')
+ {
+ spos = i;
+ sign = repr[i] == '-';
+ }
+ else if (repr[i] == 'i' || repr[i] == 'I')
+ ipos = i;
+
+ if (spos == -1 || ipos == -1 || !(spos < ipos))
+ return NULL;
+
+ double real = 0, imag = 1;
+ IntNumObj *int_ptr;
+ RatNumObj *rat_ptr;
+ RealNumObj *real_ptr;
+ if (spos > 0)
+ {
+ string real_str = repr.substr(0, spos);
+ if ((int_ptr = IntNumObj::from_string(real_str)))
+#ifndef GMP_SUPPORT
+ real = int_ptr->val;
+#else
+ real = int_ptr->val.get_d();
+#endif
+ else if ((rat_ptr = RatNumObj::from_string(real_str)))
+#ifndef GMP_SUPPORT
+ real = rat_ptr->a / double(rat_ptr->b);
+#else
+ real = rat_ptr->val.get_d();
+#endif
+ else if ((real_ptr = RealNumObj::from_string(real_str)))
+ real = real_ptr->real;
+ else return NULL;
+ }
+ if (ipos > spos + 1)
+ {
+ string imag_str = repr.substr(spos + 1, ipos - spos - 1);
+ if ((int_ptr = IntNumObj::from_string(imag_str)))
+#ifndef GMP_SUPPORT
+ imag = int_ptr->val;
+#else
+ imag = int_ptr->val.get_d();
+#endif
+ else if ((rat_ptr = RatNumObj::from_string(imag_str)))
+#ifndef GMP_SUPPORT
+ imag = rat_ptr->a / double(rat_ptr->b);
+#else
+ imag = rat_ptr->val.get_d();
+#endif
+ else if ((real_ptr = RealNumObj::from_string(imag_str)))
+ imag = real_ptr->real;
+ else return NULL;
+ }
+ if (sign) imag = -imag;
+ return new CompNumObj(real, imag);
+ }
+
+CompNumObj *CompNumObj::convert(NumObj *obj) {
+ switch (obj->level)
+ {
+ case NUM_LVL_COMP :
+ return static_cast<CompNumObj*>(obj); break;
+ case NUM_LVL_REAL :
+ return new CompNumObj(static_cast<RealNumObj*>(obj)->real, 0);
+ break;
+ case NUM_LVL_RAT :
+ {
+ RatNumObj *rat = static_cast<RatNumObj*>(obj);
+#ifndef GMP_SUPPORT
+ return new CompNumObj(rat->a / double(rat->b), 0);
+#else
+ return new CompNumObj(rat->val.get_d(), 0);
+#endif
+ break;
+ }
+ case NUM_LVL_INT :
+#ifndef GMP_SUPPORT
+ return new CompNumObj(static_cast<IntNumObj*>(obj)->val, 0);
+#else
+ return new CompNumObj(static_cast<IntNumObj*>(obj)->val.get_d(), 0);
+#endif
+ }
+ throw NormalError(INT_ERR);
+}
+
+#define A (real)
+#define B (imag)
+#define C (r->real)
+#define D (r->imag)
+
+NumObj *CompNumObj::add(NumObj *_r) {
+ CompNumObj *r = static_cast<CompNumObj*>(_r);
+ return new CompNumObj(A + C, B + D);
+}
+
+NumObj *CompNumObj::sub(NumObj *_r) {
+ CompNumObj *r = static_cast<CompNumObj*>(_r);
+ return new CompNumObj(A - C, B - D);
+}
+
+NumObj *CompNumObj::mul(NumObj *_r) {
+ CompNumObj *r = static_cast<CompNumObj*>(_r);
+ return new CompNumObj(A * C - B * D,
+ B * C + A * D);
+}
+
+NumObj *CompNumObj::div(NumObj *_r) {
+ CompNumObj *r = static_cast<CompNumObj*>(_r);
+ double f = C * C + D * D;
+ if (f == 0)
+ throw NormalError(RUN_ERR_NUMERIC_OVERFLOW);
+ f = 1 / f;
+ return new CompNumObj((A * C + B * D) * f,
+ (B * C - A * D) * f);
+}
+
+bool NumObj::lt(NumObj *_r) {
+ throw TokenError("a comparable number", RUN_ERR_WRONG_TYPE);
+}
+
+bool NumObj::gt(NumObj *_r) {
+ throw TokenError("a comparable number", RUN_ERR_WRONG_TYPE);
+}
+
+bool NumObj::le(NumObj *_r) {
+ throw TokenError("a comparable number", RUN_ERR_WRONG_TYPE);
+}
+
+bool NumObj::ge(NumObj *_r) {
+ throw TokenError("a comparable number", RUN_ERR_WRONG_TYPE);
+}
+
+NumObj *NumObj::abs() {
+ throw TokenError("a real number", RUN_ERR_WRONG_TYPE);
+}
+
+
+bool CompNumObj::eq(NumObj *_r) {
+ CompNumObj *r = static_cast<CompNumObj*>(_r);
+ return A == C && B == D; // TODO: more proper judgement
+}
+
+
+ReprCons *CompNumObj::get_repr_cons() {
+ return new ReprStr(double_to_str(real) + double_to_str(imag, true) + "i");
+}
+
+#undef A
+#undef B
+#undef C
+#undef D
+
+RealNumObj::RealNumObj(double _real) : InexactNumObj(NUM_LVL_REAL), real(_real) {}
+
+RealNumObj *RealNumObj::from_string(string repr) {
+ bool flag;
+ double real = str_to_double(repr, flag);
+ if (!flag) return NULL;
+ return new RealNumObj(real);
+}
+
+RealNumObj *RealNumObj::convert(NumObj *obj) {
+ switch (obj->level)
+ {
+ case NUM_LVL_REAL:
+ return static_cast<RealNumObj*>(obj); break;
+ case NUM_LVL_RAT:
+ {
+ RatNumObj *rat = static_cast<RatNumObj*>(obj);
+#ifndef GMP_SUPPORT
+ return new RealNumObj(rat->a / double(rat->b));
+#else
+ return new RealNumObj(rat->val.get_d());
+#endif
+ break;
+ }
+ case NUM_LVL_INT:
+#ifndef GMP_SUPPORT
+ return new RealNumObj(static_cast<IntNumObj*>(obj)->val);
+#else
+ return new RealNumObj(static_cast<IntNumObj*>(obj)->val.get_d());
+#endif
+
+ }
+ throw NormalError(INT_ERR);
+}
+
+NumObj *RealNumObj::add(NumObj *_r) {
+ return new RealNumObj(real + static_cast<RealNumObj*>(_r)->real);
+}
+
+NumObj *RealNumObj::sub(NumObj *_r) {
+ return new RealNumObj(real - static_cast<RealNumObj*>(_r)->real);
+}
+
+NumObj *RealNumObj::mul(NumObj *_r) {
+ return new RealNumObj(real * static_cast<RealNumObj*>(_r)->real);
+}
+
+NumObj *RealNumObj::div(NumObj *_r) {
+ return new RealNumObj(real / static_cast<RealNumObj*>(_r)->real);
+}
+
+NumObj *RealNumObj::abs() {
+ return new RealNumObj(fabs(real));
+}
+
+bool RealNumObj::eq(NumObj *_r) {
+ return real == static_cast<RealNumObj*>(_r)->real;
+}
+
+bool RealNumObj::lt(NumObj *_r) {
+ return real < static_cast<RealNumObj*>(_r)->real;
+}
+
+bool RealNumObj::gt(NumObj *_r) {
+ return real > static_cast<RealNumObj*>(_r)->real;
+}
+
+bool RealNumObj::le(NumObj *_r) {
+ return real <= static_cast<RealNumObj*>(_r)->real;
+}
+
+bool RealNumObj::ge(NumObj *_r) {
+ return real >= static_cast<RealNumObj*>(_r)->real;
+}
+
+
+ReprCons *RealNumObj::get_repr_cons() {
+ return new ReprStr(double_to_str(real));
+}
+
+ExactNumObj::ExactNumObj(NumLvl level) : NumObj(level, true) {}
+
+#ifndef GMP_SUPPORT
+RatNumObj::RatNumObj(int _a, int _b) :
+ ExactNumObj(NUM_LVL_RAT), a(_a), b(_b) {
+ if (b == 0)
+ throw NormalError(RUN_ERR_NUMERIC_OVERFLOW);
+ if (b < 0) a = -a, b = -b;
+ int g = gcd(a, b);
+ a /= g;
+ b /= g;
+ }
+
+RatNumObj *RatNumObj::from_string(string repr) {
+ int a, b;
+ size_t len = repr.length();
+ int pos = -1;
+ for (size_t i = 0; i < len; i++)
+ if (repr[i] == '/') { pos = i; break; }
+ bool flag;
+ a = str_to_int(repr.substr(0, pos), flag);
+ if (!flag) return NULL;
+ b = str_to_int(repr.substr(pos + 1, len - pos - 1), flag);
+ if (!flag) return NULL;
+
+ return new RatNumObj(a, b);
+}
+#else
+RatNumObj::RatNumObj(mpq_class _val) :
+ ExactNumObj(NUM_LVL_RAT), val(_val) {
+ val.canonicalize();
+}
+
+RatNumObj *RatNumObj::from_string(string repr) {
+ try
+ {
+ mpq_class ret(repr, 10);
+ if (ret.get_den() == 0)
+ throw NormalError(RUN_ERR_NUMERIC_OVERFLOW);
+ ret.canonicalize();
+ return new RatNumObj(ret);
+ }
+ catch (std::invalid_argument &e)
+ {
+ return NULL;
+ }
+}
+#endif
+
+
+RatNumObj *RatNumObj::convert(NumObj *obj) {
+ switch (obj->level)
+ {
+ case NUM_LVL_RAT:
+ return static_cast<RatNumObj*>(obj); break;
+ case NUM_LVL_INT:
+#ifndef GMP_SUPPORT
+ return new RatNumObj(static_cast<IntNumObj*>(obj)->val, 1);
+#else
+ return new RatNumObj(mpq_class(
+ static_cast<IntNumObj*>(obj)->val,
+ mpz_class(1)));
+#endif
+ }
+ throw NormalError(INT_ERR);
+}
+
+#define A (a)
+#define B (b)
+#define C (r->a)
+#define D (r->b)
+
+NumObj *RatNumObj::add(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ int na = A * D + B * C, nb = B * D;
+ int g = gcd(na, nb);
+ na /= g;
+ nb /= g;
+ return new RatNumObj(na, nb);
+#else
+ return new RatNumObj(val + r->val);
+#endif
+}
+
+NumObj *RatNumObj::sub(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ int na = A * D - B * C, nb = B * D;
+ int g = gcd(na, nb);
+ na /= g;
+ nb /= g;
+ return new RatNumObj(na, nb);
+#else
+ return new RatNumObj(val - r->val);
+#endif
+}
+
+NumObj *RatNumObj::mul(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ int na = A * C, nb = B * D;
+ int g = gcd(na, nb);
+ na /= g;
+ nb /= g;
+ return new RatNumObj(na, nb);
+#else
+ return new RatNumObj(val * r->val);
+#endif
+}
+
+NumObj *RatNumObj::div(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ int na = A * D, nb = B * C;
+ int g = gcd(na, nb);
+ na /= g;
+ nb /= g;
+ return new RatNumObj(na, nb);
+#else
+ return new RatNumObj(val / r->val);
+#endif
+}
+
+bool RatNumObj::lt(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ return A * D < C * B;
+#else
+ return val < r->val;
+#endif
+}
+
+bool RatNumObj::gt(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ return A * D > C * B;
+#else
+ return val > r->val;
+#endif
+}
+
+bool RatNumObj::le(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ return A * D <= C * B;
+#else
+ return val <= r->val;
+#endif
+}
+
+bool RatNumObj::ge(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ return A * D >= C * B;
+#else
+ return val >= r->val;
+#endif
+}
+
+
+bool RatNumObj::eq(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+#ifndef GMP_SUPPORT
+ return A * D == C * B;
+#else
+ return val == r->val;
+#endif
+}
+
+NumObj *RatNumObj::abs() {
+#ifndef GMP_SUPPORT
+ return new RatNumObj((a > 0 ? a : -a), b);
+#else
+ return new RatNumObj(std::abs(val));
+#endif
+}
+
+ReprCons *RatNumObj::get_repr_cons() {
+#ifndef GMP_SUPPORT
+ return new ReprStr(int_to_str(A) + "/" + int_to_str(B));
+#else
+ return new ReprStr(val.get_str());
+#endif
+}
+
+
+#ifndef GMP_SUPPORT
+IntNumObj::IntNumObj(int _val) : ExactNumObj(NUM_LVL_INT), val(_val) {}
+IntNumObj *IntNumObj::from_string(string repr) {
+ int val = 0;
+ for (size_t i = 0; i < repr.length(); i++)
+ {
+ if (!('0' <= repr[i] && repr[i] <= '9'))
+ return NULL;
+ val = val * 10 + repr[i] - '0';
+ }
+ return new IntNumObj(val);
+}
+int IntNumObj::get_i() { return val; }
+#else
+IntNumObj::IntNumObj(mpz_class _val) : ExactNumObj(NUM_LVL_INT), val(_val) {}
+IntNumObj *IntNumObj::from_string(string repr) {
+ try
+ {
+ mpz_class ret(repr, 10);
+ return new IntNumObj(ret);
+ }
+ catch (std::invalid_argument &e)
+ {
+ return NULL;
+ }
+}
+int IntNumObj::get_i() { return val.get_si(); }
+#endif
+
+IntNumObj *IntNumObj::convert(NumObj *obj) {
+ switch (obj->level)
+ {
+ case NUM_LVL_INT :
+ return static_cast<IntNumObj*>(obj);
+ default:
+ throw NormalError(INT_ERR);
+ }
+}
+
+NumObj *IntNumObj::add(NumObj *_r) {
+ return new IntNumObj(val + static_cast<IntNumObj*>(_r)->val);
+}
+
+NumObj *IntNumObj::sub(NumObj *_r) {
+ return new IntNumObj(val - static_cast<IntNumObj*>(_r)->val);
+}
+
+NumObj *IntNumObj::mul(NumObj *_r) {
+ return new IntNumObj(val * static_cast<IntNumObj*>(_r)->val);
+}
+
+NumObj *IntNumObj::div(NumObj *_r) {
+#ifndef GMP_SUPPORT
+ return new RatNumObj(val, static_cast<IntNumObj*>(_r)->val);
+#else
+ mpz_class d(static_cast<IntNumObj*>(_r)->val);
+ if (d == 0) throw NormalError(RUN_ERR_NUMERIC_OVERFLOW);
+ return new RatNumObj(mpq_class(val, d));
+#endif
+}
+
+NumObj *IntNumObj::abs() {
+ return new IntNumObj(std::abs(val));
+}
+
+NumObj *IntNumObj::rem(NumObj *_r) {
+ return new IntNumObj(val % static_cast<IntNumObj*>(_r)->val);
+}
+
+NumObj *IntNumObj::mod(NumObj *_r) {
+ const mpz_class &rval = static_cast<IntNumObj*>(_r)->val;
+ mpz_class ret = val % rval;
+ if (sgn(ret) != sgn(rval))
+ ret = ret + rval;
+ return new IntNumObj(ret);
+}
+
+NumObj *IntNumObj::quo(NumObj *_r) {
+ return new IntNumObj(val / static_cast<IntNumObj*>(_r)->val);
+}
+
+NumObj *IntNumObj::gcd(NumObj *_r) {
+ mpz_t g;
+ mpz_gcd(g, val.get_mpz_t(), static_cast<IntNumObj*>(_r)->val.get_mpz_t());
+ return new IntNumObj(mpz_class(g));
+}
+
+NumObj *IntNumObj::lcm(NumObj *_r) {
+ mpz_t l;
+ mpz_lcm(l, val.get_mpz_t(), static_cast<IntNumObj*>(_r)->val.get_mpz_t());
+ return new IntNumObj(mpz_class(l));
+}
+
+bool IntNumObj::lt(NumObj *_r) {
+ return val < static_cast<IntNumObj*>(_r)->val;
+}
+
+bool IntNumObj::gt(NumObj *_r) {
+ return val > static_cast<IntNumObj*>(_r)->val;
+}
+
+bool IntNumObj::le(NumObj *_r) {
+ return val <= static_cast<IntNumObj*>(_r)->val;
+}
+
+bool IntNumObj::ge(NumObj *_r) {
+ return val >= static_cast<IntNumObj*>(_r)->val;
+}
+
+
+bool IntNumObj::eq(NumObj *_r) {
+ return val == static_cast<IntNumObj*>(_r)->val;
+}
+
+ReprCons *IntNumObj::get_repr_cons() {
+#ifndef GMP_SUPPORT
+ return new ReprStr(int_to_str(val));
+#else
+ return new ReprStr(val.get_str());
+#endif
+}