diff --git a/compiler+runtime/include/cpp/jank/runtime/core/math.hpp b/compiler+runtime/include/cpp/jank/runtime/core/math.hpp index aac16a5e3..a88c1a127 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/math.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/math.hpp @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); diff --git a/compiler+runtime/src/cpp/jank/runtime/core/math.cpp b/compiler+runtime/src/cpp/jank/runtime/core/math.cpp index 01382dab5..e6766720f 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/math.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/math.cpp @@ -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 && std::same_as) + { + i64 res{}; + + if(static_cast(__builtin_add_overflow(l_val, typed_r->data, &res))) + { + native_big_integer const l{ l_val }; + return make_box(l + typed_r->data); + } + + return make_box(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( @@ -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 && std::same_as) + { + i64 res{}; + + if(__builtin_sub_overflow(l_val, typed_r->data, &res)) + { + native_big_integer const l{ l_val }; + return make_box(l_val - typed_r->data); + } + + return make_box(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( @@ -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 && std::same_as) + { + i64 res{}; + + if(__builtin_mul_overflow(l_val, typed_r->data, &res)) + { + native_big_integer const l{ l_val }; + return make_box(l * typed_r->data); + } + + return make_box(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( @@ -659,6 +761,32 @@ 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) + { + i64 res{}; + + if(__builtin_add_overflow(typed_l->data, 1ll, &res)) + { + native_big_integer const v{ typed_l->data }; + return make_box(v + 1ll); + } + + return make_box(res); + } + else + { + return make_box(typed_l->data + 1ll); + } + }, + l); + } + object_ref dec(object_ref const l) { return visit_number_like( @@ -666,6 +794,32 @@ namespace jank::runtime 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) + { + i64 res{}; + + if(__builtin_sub_overflow(typed_l->data, 1ll, &res)) + { + native_big_integer const v{ typed_l->data }; + return make_box(v - 1ll); + } + + return make_box(res); + } + else + { + return make_box(typed_l->data - 1ll); + } + }, + l); + } + bool is_zero(object_ref const l) { return visit_number_like( @@ -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; @@ -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( diff --git a/compiler+runtime/src/jank/clojure/core.jank b/compiler+runtime/src/jank/clojure/core.jank index 9c2cd137a..fdc4c6d3d 100644 --- a/compiler+runtime/src/jank/clojure/core.jank +++ b/compiler+runtime/src/jank/clojure/core.jank @@ -1126,7 +1126,7 @@ ([] 0) ([x] - x) + (cpp/jank.runtime.number x)) ([l r] (cpp/jank.runtime.add l r)) ([l r & args] @@ -1156,7 +1156,7 @@ ([] 1) ([x] - x) + (cpp/jank.runtime.number x)) ([l r] (cpp/jank.runtime.mul l r)) ([l r & args] @@ -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 @@ -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))) @@ -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))) @@ -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))) @@ -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. @@ -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" diff --git a/compiler+runtime/test/bash/clojure-test-suite/src/jank_test/run_clojure_test_suite.cljc b/compiler+runtime/test/bash/clojure-test-suite/src/jank_test/run_clojure_test_suite.cljc index e5826c90f..a88e33bba 100644 --- a/compiler+runtime/test/bash/clojure-test-suite/src/jank_test/run_clojure_test_suite.cljc +++ b/compiler+runtime/test/bash/clojure-test-suite/src/jank_test/run_clojure_test_suite.cljc @@ -75,7 +75,7 @@ ;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. @@ -83,7 +83,7 @@ ;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 @@ -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. @@ -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