Skip to content
11 changes: 11 additions & 0 deletions compiler+runtime/include/cpp/jank/runtime/core/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ namespace jank::runtime
object_ref add(obj::ratio_ref l, obj::integer_ref r);
obj::ratio_ref add(obj::integer_ref l, obj::ratio_ref r);

object_ref promoting_add(object_ref const l, object_ref const r);

object_ref sub(object_ref l, object_ref r);
object_ref sub(obj::integer_ref l, object_ref r);
object_ref sub(object_ref l, obj::integer_ref r);
Expand All @@ -64,6 +66,8 @@ namespace jank::runtime
object_ref sub(i64 l, object_ref r);
i64 sub(i64 l, i64 r);

object_ref promoting_sub(object_ref const l, object_ref const r);

object_ref div(object_ref l, object_ref r);
object_ref div(obj::integer_ref l, object_ref r);
object_ref div(object_ref l, obj::integer_ref r);
Expand Down Expand Up @@ -110,6 +114,8 @@ namespace jank::runtime
object_ref mul(i64 l, object_ref r);
i64 mul(i64 l, i64 r);

object_ref promoting_mul(object_ref const l, object_ref const r);

bool lt(object_ref l, object_ref r);
bool lt(obj::integer_ref l, object_ref r);
bool lt(object_ref l, obj::integer_ref r);
Expand Down Expand Up @@ -232,7 +238,9 @@ namespace jank::runtime
object_ref rem(object_ref l, object_ref r);
object_ref quot(object_ref l, object_ref r);
object_ref inc(object_ref l);
object_ref promoting_inc(object_ref const l);
object_ref dec(object_ref l);
object_ref promoting_dec(object_ref const l);

bool is_zero(object_ref l);
bool is_pos(object_ref l);
Expand Down Expand Up @@ -269,6 +277,8 @@ namespace jank::runtime
f64 to_real(object_ref o);

bool is_number(object_ref o);
object_ref number(object_ref const o);

bool is_integer(object_ref o);
bool is_real(object_ref o);
bool is_ratio(object_ref o);
Expand All @@ -279,6 +289,7 @@ namespace jank::runtime
i64 parse_long(object_ref o);
f64 parse_double(object_ref o);

bool is_big_integer(object_ref const o);
obj::big_integer_ref to_big_integer(object_ref const o);

bool is_big_decimal(object_ref const o);
Expand Down
164 changes: 164 additions & 0 deletions compiler+runtime/src/cpp/jank/runtime/core/math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,40 @@ namespace jank::runtime
return l + r;
}

object_ref promoting_add(object_ref const l, object_ref const r)
{
return visit_number_like(
[](auto const typed_l, auto const r) -> object_ref {
using LT = typename decltype(typed_l)::value_type;

return visit_number_like(
[](auto const typed_r, auto const &l_val) -> object_ref {
using RT = typename decltype(typed_r)::value_type;

if constexpr(std::same_as<LT, obj::integer> && std::same_as<RT, obj::integer>)
{
i64 res{};

if(static_cast<bool>(__builtin_add_overflow(l_val, typed_r->data, &res)))
{
native_big_integer const l{ l_val };
return make_box<obj::big_integer>(l + typed_r->data);
}

return make_box<obj::integer>(res);
}
else
{
return make_box(l_val + typed_r->data);
}
},
r,
typed_l->data);
},
l,
r);
}

object_ref sub(object_ref const l, object_ref const r)
{
return visit_number_like(
Expand Down Expand Up @@ -306,6 +340,40 @@ namespace jank::runtime
return l - r;
}

object_ref promoting_sub(object_ref const l, object_ref const r)
{
return visit_number_like(
[](auto const typed_l, auto const r) -> object_ref {
using LT = typename decltype(typed_l)::value_type;

return visit_number_like(
[](auto const typed_r, auto const &l_val) -> object_ref {
using RT = typename decltype(typed_r)::value_type;

if constexpr(std::same_as<LT, obj::integer> && std::same_as<RT, obj::integer>)
{
i64 res{};

if(__builtin_sub_overflow(l_val, typed_r->data, &res))
{
native_big_integer const l{ l_val };
return make_box<obj::big_integer>(l_val - typed_r->data);
}

return make_box<obj::integer>(res);
}
else
{
return make_box(l_val - typed_r->data);
}
},
r,
typed_l->data);
},
l,
r);
}

object_ref div(object_ref const l, object_ref const r)
{
return visit_number_like(
Expand Down Expand Up @@ -576,6 +644,40 @@ namespace jank::runtime
return l * r;
}

object_ref promoting_mul(object_ref const l, object_ref const r)
{
return visit_number_like(
[](auto const typed_l, auto const r) -> object_ref {
using LT = typename decltype(typed_l)::value_type;

return visit_number_like(
[](auto const typed_r, auto const &l_val) -> object_ref {
using RT = typename decltype(typed_r)::value_type;

if constexpr(std::same_as<LT, obj::integer> && std::same_as<RT, obj::integer>)
{
i64 res{};

if(__builtin_mul_overflow(l_val, typed_r->data, &res))
{
native_big_integer const l{ l_val };
return make_box<obj::big_integer>(l * typed_r->data);
}

return make_box<obj::integer>(res);
}
else
{
return make_box(l_val * typed_r->data);
}
},
r,
typed_l->data);
},
l,
r);
}

object_ref rem(object_ref const l, object_ref const r)
{
return visit_number_like(
Expand Down Expand Up @@ -659,13 +761,65 @@ namespace jank::runtime
l);
}

object_ref promoting_inc(object_ref const l)
{
return visit_number_like(
[](auto const typed_l) -> object_ref {
using T = typename decltype(typed_l)::value_type;

if constexpr(std::same_as<T, obj::integer>)
{
i64 res{};

if(__builtin_add_overflow(typed_l->data, 1ll, &res))
{
native_big_integer const v{ typed_l->data };
return make_box<obj::big_integer>(v + 1ll);
}

return make_box<obj::integer>(res);
}
else
{
return make_box(typed_l->data + 1ll);
}
},
l);
}

object_ref dec(object_ref const l)
{
return visit_number_like(
[](auto const typed_l) -> object_ref { return make_box(typed_l->data - 1ll).erase(); },
l);
}

object_ref promoting_dec(object_ref const l)
{
return visit_number_like(
[](auto const typed_l) -> object_ref {
using T = typename decltype(typed_l)::value_type;

if constexpr(std::same_as<T, obj::integer>)
{
i64 res{};

if(__builtin_sub_overflow(typed_l->data, 1ll, &res))
{
native_big_integer const v{ typed_l->data };
return make_box<obj::big_integer>(v - 1ll);
}

return make_box<obj::integer>(res);
}
else
{
return make_box(typed_l->data - 1ll);
}
},
l);
}

bool is_zero(object_ref const l)
{
return visit_number_like(
Expand Down Expand Up @@ -1710,6 +1864,11 @@ namespace jank::runtime
o);
}

object_ref number(object_ref const o)
{
return visit_number_like([](auto const typed_l) -> object_ref { return typed_l; }, o);
}

bool is_integer(object_ref const o)
{
return o->type == object_type::integer;
Expand Down Expand Up @@ -1793,6 +1952,11 @@ namespace jank::runtime
}
}

bool is_big_integer(object_ref const o)
{
return o->type == object_type::big_integer;
}

obj::big_integer_ref to_big_integer(object_ref const o)
{
return visit_number_like(
Expand Down
31 changes: 11 additions & 20 deletions compiler+runtime/src/jank/clojure/core.jank
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@
([]
0)
([x]
x)
(cpp/jank.runtime.number x))
([l r]
(cpp/jank.runtime.add l r))
([l r & args]
Expand Down Expand Up @@ -1156,7 +1156,7 @@
([]
1)
([x]
x)
(cpp/jank.runtime.number x))
([l r]
(cpp/jank.runtime.mul l r))
([l r & args]
Expand Down Expand Up @@ -4482,8 +4482,7 @@
"Returns a number one greater than num. Supports arbitrary precision.
See also: inc"
[x]
;; (. clojure.lang.Numbers (incP x))
(throw "TODO: port inc'"))
(cpp/jank.runtime.promoting_inc x))

;; ;;math stuff
;; (defn ^:private nary-inline
Expand All @@ -4509,11 +4508,9 @@
See also: +"
([] 0)
([x]
;; (cast Number x)
(throw "TODO: port +'"))
(cpp/jank.runtime.number x))
([x y]
;; (. clojure.lang.Numbers (addP x y))
(throw "TODO: port +'"))
(cpp/jank.runtime.promoting_add x y))
([x y & more]
(reduce +' (+' x y) more)))

Expand All @@ -4522,11 +4519,9 @@
See also: *"
([] 1)
([x]
;; (cast Number x)
(throw "TODO: port *'"))
(cpp/jank.runtime.number x))
([x y]
;; (. clojure.lang.Numbers (multiplyP x y))
(throw "TODO: port *'"))
(cpp/jank.runtime.promoting_mul x y))
([x y & more]
(reduce *' (*' x y) more)))

Expand All @@ -4535,11 +4530,9 @@
the ys from x and returns the result. Supports arbitrary precision.
See also: -"
([x]
;; (. clojure.lang.Numbers (minusP x))
(throw "TODO: port -'"))
(-' 0 x))
([x y]
;; (. clojure.lang.Numbers (minusP x y))
(throw "TODO: port -'"))
(cpp/jank.runtime.promoting_sub x y))
([x y & more]
(reduce -' (-' x y) more)))

Expand All @@ -4556,8 +4549,7 @@
"Returns a number one less than num. Supports arbitrary precision.
See also: dec"
[x]
;; (. clojure.lang.Numbers (decP x))
(throw "TODO: port dec'"))
(cpp/jank.runtime.promoting_dec x))

(defn unchecked-inc-int
"Returns a number one greater than x, an int.
Expand Down Expand Up @@ -5340,8 +5332,7 @@
(defn num
"Coerce to Number"
[x]
;; (. clojure.lang.Numbers (num x))
(throw "TODO: port num"))
(cpp/jank.runtime.number x))

(defn long
"Coerce to long"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@
;clojure.core-test.nth ; Uncaught exception: index out of bounds: -1, In clojure.core-test.nth$fn_2-64, duplicate definition of symbol '_fn_2_0', https://github.com/jank-lang/jank/issues/244, Exception: index out of bounds: -1
;clojure.core-test.nthnext ; Uncaught exception: not a number: nil, In clojure.core-test.nthnext$fn_2-83, duplicate definition of symbol '_fn_2_0', https://github.com/jank-lang/jank/issues/243 , https://github.com/jank-lang/jank/issues/244
;clojure.core-test.nthrest ; Uncaught exception: not a number: nil, In clojure.core-test.nthrest$fn_2-85, duplicate definition of symbol '_fn_2_0', https://github.com/jank-lang/jank/issues/243 , https://github.com/jank-lang/jank/issues/244 , https://github.com/jank-lang/jank/issues/247
clojure.core-test.num ; Expecting whitespace after the last token. due to M.
clojure.core-test.num
clojure.core-test.number-qmark ; Expecting whitespace after the last token. due to M.
clojure.core-test.number-range
;clojure.core-test.numerator ; Failed a test. Expecting whitespace after the last token. due to M.
;clojure.core-test.odd-qmark ; Uncaught exception: invalid object type: 3. Expecting whitespace after the last token. due to M.
;clojure.core-test.or ; unloadable, In clojure.core-test.or$fn_2-159, duplicate definition of symbol '_fn_2_0', unloadable
;clojure.core-test.partial ;unloadable
;clojure.core-test.plus ; error: Unable to resolve symbol 'Exception'
;clojure.core-test.plus-squote ; error: Unable to resolve symbol 'clojure.lang.BigInt'.
; clojure.core-test.plus-squote
clojure.core-test.pos-int-qmark ; Expecting whitespace after the last token. due to M.
;clojure.core-test.pos-qmark ; Uncaught exception: not a number: nil. Expecting whitespace after the last token. due to M.
;clojure.core-test.pr-str ; Uncaught exception: invalid call to clojure.core/pr-str with 2 args provided, In clojure.core-test.pr-str$fn_2-49, duplicate definition of symbol '_fn_2_0', unloadable
Expand All @@ -96,7 +96,7 @@
;clojure.core-test.quot ; Failed tests. Expecting whitespace after the last token. due to M.
;clojure.core-test.rand ; unloadable, In clojure.core-test.rand$fn_2-71, duplicate definition of symbol '_jank_global_init_70', unloadable
;clojure.core-test.rand-int ; unloadable, In clojure.core-test.rand-int$fn_2-56, duplicate definition of symbol '_fn_2_0', unloadable
clojure.core-test.ratio-qmark ; Expecting whitespace after the last token. due to M.
clojure.core-test.ratio-qmark
;clojure.core-test.rational-qmark ; (= true (rational? 0N))
;clojure.core-test.rationalize ; TODO: port rationalize, Expecting whitespace after the last token. due to M.
;clojure.core-test.rem ; Fails the test cases.
Expand All @@ -112,7 +112,7 @@
;clojure.core-test.slash ; Unable to resolve symbol 'Exception'., Expecting whitespace after the last token. due to M.
;clojure.core-test.some-qmark ;Read error (437 - 437): unsupported reader macro
;clojure.core-test.star ; error: Unable to resolve symbol 'Exception'.
;clojure.core-test.star-squote ; error: Unable to resolve symbol 'clojure.lang.BigInt'.
; clojure.core-test.star-squote
;clojure.core-test.str ; TODO: port double, Expecting whitespace after the last token. due to M.
clojure.core-test.string-qmark
;clojure.core-test.subs ; Uncaught exception: end index 1 is less than start 2, In clojure.core-test.subs$fn_2-70, duplicate definition of symbol '_fn_2_0', https://github.com/jank-lang/jank/issues/244
Expand Down
Loading