From 88db9751d78cb788ae286aefd7f596c94148dd45 Mon Sep 17 00:00:00 2001 From: Ian Shehadeh Date: Sun, 20 Feb 2022 16:16:52 -0500 Subject: [PATCH] add int/to-number: converts s64 and u64 to numbers (int/to-number value) converts an s64 or u64 to a number. It restricts the value to the int32 range, so that `int32?` will always suceeded when called on the result. --- src/core/inttypes.c | 33 +++++++++++++++++++++++++++++++++ test/suite0006.janet | 14 ++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/core/inttypes.c b/src/core/inttypes.c index 8cee9e67..3a220688 100644 --- a/src/core/inttypes.c +++ b/src/core/inttypes.c @@ -207,6 +207,38 @@ JANET_CORE_FN(cfun_it_u64_new, return janet_wrap_u64(janet_unwrap_u64(argv[0])); } +JANET_CORE_FN(cfun_to_number, + "(int/to-number value)", + "Convert an int/u64 or int/s64 to a number. Fails if the number is out of range for an int32.") { + janet_fixarity(argc, 1); + if (janet_type(argv[0]) == JANET_ABSTRACT) { + void* abst = janet_unwrap_abstract(argv[0]); + + if (janet_abstract_type(abst) == &janet_s64_type) { + int64_t value = *((int64_t*)abst); + if (value > INT32_MAX) { + janet_panicf("cannot convert %q to a number, exceededs int32 max", argv[0]); + } + if (value < INT32_MIN) { + janet_panicf("cannot convert %q to a number, exceededs int32 min", argv[0]); + } + + return janet_wrap_integer(value); + } + + if (janet_abstract_type(abst) == &janet_u64_type) { + uint64_t value = *((uint64_t*)abst); + if (value > INT32_MAX) { + janet_panicf("cannot convert %q to a number, exceededs int32 max", argv[0]); + } + + return janet_wrap_integer(value); + } + } + + janet_panicf("expected int/u64 or int/s64, got %q", argv[0]); +} + /* * Code to support polymorphic comparison. * int/u64 and int/s64 support a "compare" method that allows @@ -514,6 +546,7 @@ void janet_lib_inttypes(JanetTable *env) { JanetRegExt it_cfuns[] = { JANET_CORE_REG("int/s64", cfun_it_s64_new), JANET_CORE_REG("int/u64", cfun_it_u64_new), + JANET_CORE_REG("int/to-number", cfun_to_number), JANET_REG_END }; janet_core_cfuns_ext(env, NULL, it_cfuns); diff --git a/test/suite0006.janet b/test/suite0006.janet index e0fa6774..2f86584f 100644 --- a/test/suite0006.janet +++ b/test/suite0006.janet @@ -39,6 +39,20 @@ (def c (u64 "32rvv_vv_vv_vv")) (def d (u64 "123456789")))) +# Conversion back to an int32 +(assert (= (int/to-number (u64 0xFaFa)) 0xFaFa)) +(assert (= (int/to-number (i64 0xFaFa)) 0xFaFa)) + +(assert-error + "int64 out of bounds for int32" + (do + (int/to-number (u64 "0x7fff_ffff_ffff_ffff")) + (int/to-number (i64 "-0x7fff_ffff_ffff_ffff")))) + +(assert-error + "int/to-number fails on non-abstract types" + (int/to-number 1)) + (assert-no-error "create some int64 bigints" (do