aboutsummaryrefslogtreecommitdiff
path: root/builtin.cpp
diff options
context:
space:
mode:
authorTeddy <ted.sybil@gmail.com>2013-08-05 21:11:53 +0800
committerTeddy <ted.sybil@gmail.com>2013-08-05 21:11:53 +0800
commit45dec735ec131c18d70ad202ed1446982b99ed9f (patch)
tree6326d2889045ec2b4d13ae0a612e24c771205029 /builtin.cpp
parenta6574b0025b68eb28a8c7d679ca6783132ad013d (diff)
added more built-in procedures
Diffstat (limited to 'builtin.cpp')
-rw-r--r--builtin.cpp260
1 files changed, 213 insertions, 47 deletions
diff --git a/builtin.cpp b/builtin.cpp
index 6c58d96..26bbc9d 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -46,7 +46,7 @@ double str_to_double(string repr, bool &flag) {
int gcd(int a, int b) {
int t;
while (b) t = b, b = a % b, a = t;
- return a;
+ return abs(a);
}
@@ -115,33 +115,42 @@ CompNumObj *CompNumObj::convert(NumObj *obj) {
#define D (r->imag)
NumObj *CompNumObj::plus(NumObj *_r) {
- CompNumObj *r = CompNumObj::convert(_r);
+ CompNumObj *r = static_cast<CompNumObj*>(_r);
return new CompNumObj(A + C, B + D);
}
NumObj *CompNumObj::minus(NumObj *_r) {
- CompNumObj *r = CompNumObj::convert(_r);
+ CompNumObj *r = static_cast<CompNumObj*>(_r);
return new CompNumObj(A - C, B - D);
}
NumObj *CompNumObj::multi(NumObj *_r) {
- CompNumObj *r = CompNumObj::convert(_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 = CompNumObj::convert(_r);
+ CompNumObj *r = static_cast<CompNumObj*>(_r);
double f = 1.0 / (C * C + D * D);
return new CompNumObj((A * C + B * D) * f,
(B * C - A * D) * f);
}
-BoolObj *CompNumObj::eq(NumObj *_r) {
- CompNumObj *r = CompNumObj::convert(_r);
- return new BoolObj(A == C && B == D); // TODO: more proper judgement
+bool CompNumObj::lt(NumObj *_r) {
+ throw TokenError("a comparable number", RUN_ERR_WRONG_TYPE);
}
+bool CompNumObj::gt(NumObj *_r) {
+ throw TokenError("a comparable 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
+}
+
+
string CompNumObj::ext_repr() {
return double_to_str(real) + double_to_str(imag, true) + "i";
}
@@ -178,38 +187,38 @@ RealNumObj *RealNumObj::convert(NumObj *obj) {
}
NumObj *RealNumObj::plus(NumObj *_r) {
- return new RealNumObj(real + RealNumObj::convert(_r)->real);
+ return new RealNumObj(real + static_cast<RealNumObj*>(_r)->real);
}
NumObj *RealNumObj::minus(NumObj *_r) {
- return new RealNumObj(real - RealNumObj::convert(_r)->real);
+ return new RealNumObj(real - static_cast<RealNumObj*>(_r)->real);
}
NumObj *RealNumObj::multi(NumObj *_r) {
- return new RealNumObj(real * RealNumObj::convert(_r)->real);
+ return new RealNumObj(real * static_cast<RealNumObj*>(_r)->real);
}
NumObj *RealNumObj::div(NumObj *_r) {
- return new RealNumObj(real / RealNumObj::convert(_r)->real);
+ return new RealNumObj(real / static_cast<RealNumObj*>(_r)->real);
}
-BoolObj *RealNumObj::eq(NumObj *_r) {
- return new BoolObj(real == RealNumObj::convert(_r)->real);
+bool RealNumObj::eq(NumObj *_r) {
+ return real == static_cast<RealNumObj*>(_r)->real;
}
-BoolObj *RealNumObj::lt(NumObj *_r) {
- return new BoolObj(real < RealNumObj::convert(_r)->real);
+bool RealNumObj::lt(NumObj *_r) {
+ return real < static_cast<RealNumObj*>(_r)->real;
}
-BoolObj *RealNumObj::gt(NumObj *_r) {
- return new BoolObj(real > RealNumObj::convert(_r)->real);
+bool RealNumObj::gt(NumObj *_r) {
+ return real > static_cast<RealNumObj*>(_r)->real;
}
string RealNumObj::ext_repr() {
return double_to_str(real);
}
-ExactNumObj::ExactNumObj(NumLvl level) : NumObj(level, false) {}
+ExactNumObj::ExactNumObj(NumLvl level) : NumObj(level, true) {}
RatNumObj::RatNumObj(int _a, int _b) :
ExactNumObj(NUM_LVL_RAT), a(_a), b(_b) {
@@ -242,7 +251,7 @@ RatNumObj *RatNumObj::convert(NumObj *obj) {
#define D (r->b)
NumObj *RatNumObj::plus(NumObj *_r) {
- RatNumObj *r = RatNumObj::convert(_r);
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
int na = A * D + B * C, nb = B * D;
int g = gcd(na, nb);
na /= g;
@@ -251,7 +260,7 @@ NumObj *RatNumObj::plus(NumObj *_r) {
}
NumObj *RatNumObj::minus(NumObj *_r) {
- RatNumObj *r = RatNumObj::convert(_r);
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
int na = A * D - B * C, nb = B * D;
int g = gcd(na, nb);
na /= g;
@@ -260,7 +269,7 @@ NumObj *RatNumObj::minus(NumObj *_r) {
}
NumObj *RatNumObj::multi(NumObj *_r) {
- RatNumObj *r = RatNumObj::convert(_r);
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
int na = A * C, nb = B * D;
int g = gcd(na, nb);
na /= g;
@@ -269,7 +278,7 @@ NumObj *RatNumObj::multi(NumObj *_r) {
}
NumObj *RatNumObj::div(NumObj *_r) {
- RatNumObj *r = RatNumObj::convert(_r);
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
int na = A * D, nb = B * C;
int g = gcd(na, nb);
na /= g;
@@ -277,19 +286,19 @@ NumObj *RatNumObj::div(NumObj *_r) {
return new RatNumObj(na, nb);
}
-BoolObj *RatNumObj::lt(NumObj *_r) {
- RatNumObj *r = RatNumObj::convert(_r);
- return new BoolObj(A * D < C * B);
+bool RatNumObj::lt(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+ return A * D < C * B;
}
-BoolObj *RatNumObj::gt(NumObj *_r) {
- RatNumObj *r = RatNumObj::convert(_r);
- return new BoolObj(A * D > C * B);
+bool RatNumObj::gt(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+ return A * D > C * B;
}
-BoolObj *RatNumObj::eq(NumObj *_r) {
- RatNumObj *r = RatNumObj::convert(_r);
- return new BoolObj(A * D == C * B);
+bool RatNumObj::eq(NumObj *_r) {
+ RatNumObj *r = static_cast<RatNumObj*>(_r);
+ return A * D == C * B;
}
string RatNumObj::ext_repr() {
@@ -321,31 +330,31 @@ IntNumObj *IntNumObj::convert(NumObj *obj) {
NumObj *IntNumObj::plus(NumObj *_r) {
- return new IntNumObj(val + IntNumObj::convert(_r)->val);
+ return new IntNumObj(val + static_cast<IntNumObj*>(_r)->val);
}
NumObj *IntNumObj::minus(NumObj *_r) {
- return new IntNumObj(val - IntNumObj::convert(_r)->val);
+ return new IntNumObj(val - static_cast<IntNumObj*>(_r)->val);
}
NumObj *IntNumObj::multi(NumObj *_r) {
- return new IntNumObj(val * IntNumObj::convert(_r)->val);
+ return new IntNumObj(val * static_cast<IntNumObj*>(_r)->val);
}
NumObj *IntNumObj::div(NumObj *_r) {
- return new IntNumObj(val / IntNumObj::convert(_r)->val);
+ return new IntNumObj(val / static_cast<IntNumObj*>(_r)->val);
}
-BoolObj *IntNumObj::lt(NumObj *_r) {
- return new BoolObj(val < IntNumObj::convert(_r)->val);
+bool IntNumObj::lt(NumObj *_r) {
+ return val < static_cast<IntNumObj*>(_r)->val;
}
-BoolObj *IntNumObj::gt(NumObj *_r) {
- return new BoolObj(val > IntNumObj::convert(_r)->val);
+bool IntNumObj::gt(NumObj *_r) {
+ return val > static_cast<IntNumObj*>(_r)->val;
}
-BoolObj *IntNumObj::eq(NumObj *_r) {
- return new BoolObj(val == IntNumObj::convert(_r)->val);
+bool IntNumObj::eq(NumObj *_r) {
+ return val == static_cast<IntNumObj*>(_r)->val;
}
string IntNumObj::ext_repr() {
@@ -599,17 +608,174 @@ EvalObj *builtin_plus(ArgList *args) {
for (Cons *ptr = args; ptr != empty_list; ptr = TO_CONS(ptr->cdr))
{
if (!ptr->car->is_num_obj()) // not a number
- throw TokenError(ptr->car->ext_repr(), RUN_ERR_WRONG_TYPE);
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+ opr = static_cast<NumObj*>(ptr->car);
+ NumObj *_res = res;
+ if (_res->level < opr->level)
+ opr = _res->convert(opr);
+ else
+ _res = opr->convert(_res);
+ res = _res->plus(opr);
+ }
+ return res;
+}
+
+EvalObj *builtin_minus(ArgList *args) {
+ if (args == empty_list)
+ throw TokenError("-", RUN_ERR_WRONG_NUM_OF_ARGS);
+ if (!args->car->is_num_obj())
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+
+ NumObj *res = static_cast<NumObj*>(args->car), *opr;
+ for (Cons *ptr = TO_CONS(args->cdr);
+ ptr != empty_list; ptr = TO_CONS(ptr->cdr))
+ {
+ if (!ptr->car->is_num_obj()) // not a number
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+ opr = static_cast<NumObj*>(ptr->car);
+ // upper type conversion
+ NumObj *_res = res;
+ if (_res->level < opr->level)
+ opr = _res->convert(opr);
+ else
+ _res = opr->convert(_res);
+ res = _res->minus(opr);
+ }
+ return res;
+}
+
+EvalObj *builtin_multi(ArgList *args) {
+ NumObj *res = new IntNumObj(1), *opr; // the most accurate type
+ for (Cons *ptr = args; ptr != empty_list; ptr = TO_CONS(ptr->cdr))
+ {
+ if (!ptr->car->is_num_obj()) // not a number
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+ opr = static_cast<NumObj*>(ptr->car);
+ NumObj *_res = res;
+ if (_res->level < opr->level)
+ opr = _res->convert(opr);
+ else
+ _res = opr->convert(_res);
+ res = _res->multi(opr);
+ }
+ return res;
+}
+
+EvalObj *builtin_div(ArgList *args) {
+ if (args == empty_list)
+ throw TokenError("/", RUN_ERR_WRONG_NUM_OF_ARGS);
+ if (!args->car->is_num_obj())
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+
+ NumObj *res = static_cast<NumObj*>(args->car), *opr;
+ for (Cons *ptr = TO_CONS(args->cdr);
+ ptr != empty_list; ptr = TO_CONS(ptr->cdr))
+ {
+ if (!ptr->car->is_num_obj()) // not a number
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
opr = static_cast<NumObj*>(ptr->car);
- if (res->level < opr->level)
- // upper type conversion
- res = res->plus(opr);
+ // upper type conversion
+ NumObj *_res = res;
+ if (_res->level < opr->level)
+ opr = _res->convert(opr);
else
- res = opr->plus(res);
+ _res = opr->convert(_res);
+ res = _res->div(opr);
}
return res;
}
+EvalObj *builtin_lt(ArgList *args) {
+ if (args == empty_list)
+ throw TokenError("<", RUN_ERR_WRONG_NUM_OF_ARGS);
+ if (!args->car->is_num_obj())
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+
+ NumObj *last = static_cast<NumObj*>(args->car), *opr;
+
+ for (Cons *ptr = TO_CONS(args->cdr);
+ ptr != empty_list; ptr = TO_CONS(ptr->cdr), last = opr)
+ {
+ if (!ptr->car->is_num_obj()) // not a number
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+ opr = static_cast<NumObj*>(ptr->car);
+ // upper type conversion
+ if (last->level < opr->level)
+ opr = last->convert(opr);
+ else
+ last = opr->convert(last);
+ if (!last->lt(opr))
+ return new BoolObj(false);
+ }
+ return new BoolObj(true);
+}
+
+EvalObj *builtin_gt(ArgList *args) {
+ if (args == empty_list)
+ throw TokenError(">", RUN_ERR_WRONG_NUM_OF_ARGS);
+ if (!args->car->is_num_obj())
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+
+ NumObj *last = static_cast<NumObj*>(args->car), *opr;
+
+ for (Cons *ptr = TO_CONS(args->cdr);
+ ptr != empty_list; ptr = TO_CONS(ptr->cdr), last = opr)
+ {
+ if (!ptr->car->is_num_obj()) // not a number
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+ opr = static_cast<NumObj*>(ptr->car);
+ // upper type conversion
+ if (last->level < opr->level)
+ opr = last->convert(opr);
+ else
+ last = opr->convert(last);
+ if (!last->gt(opr))
+ return new BoolObj(false);
+ }
+ return new BoolObj(true);
+}
+
+EvalObj *builtin_arithmetic_eq(ArgList *args) {
+ if (args == empty_list)
+ throw TokenError("=", RUN_ERR_WRONG_NUM_OF_ARGS);
+ if (!args->car->is_num_obj())
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+
+ NumObj *last = static_cast<NumObj*>(args->car), *opr;
+
+ for (Cons *ptr = TO_CONS(args->cdr);
+ ptr != empty_list; ptr = TO_CONS(ptr->cdr), last = opr)
+ {
+ if (!ptr->car->is_num_obj()) // not a number
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+ opr = static_cast<NumObj*>(ptr->car);
+ // upper type conversion
+ if (last->level < opr->level)
+ opr = last->convert(opr);
+ else
+ last = opr->convert(last);
+ if (!last->eq(opr))
+ return new BoolObj(false);
+ }
+ return new BoolObj(true);
+}
+
+
+EvalObj *builtin_exact(ArgList *args) {
+ if (args == empty_list ||
+ args->cdr != empty_list)
+ throw TokenError("(in)exact?", RUN_ERR_WRONG_NUM_OF_ARGS);
+ if (!args->car->is_num_obj())
+ throw TokenError("a number", RUN_ERR_WRONG_TYPE);
+ return new BoolObj(static_cast<NumObj*>(args->car)->is_exact());
+}
+
+EvalObj *builtin_inexact(ArgList *args) {
+ BoolObj *ret = static_cast<BoolObj*>(builtin_exact(args));
+ ret->val = !ret->val;
+ return ret;
+}
+
EvalObj *builtin_display(ArgList *args) {
printf("%s\n", args->car->ext_repr().c_str());