From 872b39cc327db562857defdd4ed7b0db7502f18b Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sun, 21 Jul 2024 09:36:23 -0500 Subject: [PATCH] Add syntax literals for signed and unsigned 64 bit integers. Number literals can now take an optional "representation" suffix - Use `:n` for normal numbers (IEEE-754 doubles) - Use `:s` for signed 64 bit integers - Use `:u` for unsigned 64 bit integers - Other suffix will fallthrough the usual parseing logic. This means that they will only possibly resolve to symbols if they start with -, +, or . The syntax does not collide with any existing valid Janet and is only enabled with JANET_INTTYPES. This also leaves open a syntax for other number types such as bignums, ratios, decimals, etc. --- src/core/parse.c | 5 +++++ src/core/strtod.c | 34 ++++++++++++++++++++++++++++++++++ src/include/janet.h | 3 +++ test/suite-inttypes.janet | 8 ++++++++ 4 files changed, 50 insertions(+) diff --git a/src/core/parse.c b/src/core/parse.c index 40ccfbf2..0d667f2f 100644 --- a/src/core/parse.c +++ b/src/core/parse.c @@ -467,8 +467,13 @@ static int tokenchar(JanetParser *p, JanetParseState *state, uint8_t c) { return 0; } ret = janet_keywordv(p->buf + 1, blen - 1); +#ifdef JANET_INT_TYPES + } else if (start_num && !janet_scan_numeric(p->buf, blen, &ret)) { + (void) numval; +#else } else if (start_num && !janet_scan_number(p->buf, blen, &numval)) { ret = janet_wrap_number(numval); +#endif } else if (!check_str_const("nil", p->buf, blen)) { ret = janet_wrap_nil(); } else if (!check_str_const("false", p->buf, blen)) { diff --git a/src/core/strtod.c b/src/core/strtod.c index 8321fd52..8918d348 100644 --- a/src/core/strtod.c +++ b/src/core/strtod.c @@ -489,6 +489,40 @@ int janet_scan_uint64(const uint8_t *str, int32_t len, uint64_t *out) { return 0; } +/* Similar to janet_scan_number but allows for + * more numeric types with a given suffix. */ +int janet_scan_numeric( + const uint8_t *str, + int32_t len, + Janet *out) { + int result; + double num; + int64_t i64; + uint64_t u64; + if (len < 2 || str[len - 2] != ':') { + result = janet_scan_number_base(str, len, 0, &num); + *out = janet_wrap_number(num); + return result; + } + switch (str[len - 1]) { + default: + return 1; + case 'n': + result = janet_scan_number_base(str, len - 2, 0, &num); + *out = janet_wrap_number(num); + return result; + /* Condition is inverted janet_scan_int64 and janet_scan_uint64 */ + case 's': + result = !janet_scan_int64(str, len - 2, &i64); + *out = janet_wrap_s64(i64); + return result; + case 'u': + result = !janet_scan_uint64(str, len - 2, &u64); + *out = janet_wrap_u64(u64); + return result; + } +} + #endif void janet_buffer_dtostr(JanetBuffer *buffer, double x) { diff --git a/src/include/janet.h b/src/include/janet.h index 88e7f066..cc3fe1cf 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -1598,6 +1598,9 @@ JANET_API int janet_scan_number(const uint8_t *str, int32_t len, double *out); JANET_API int janet_scan_number_base(const uint8_t *str, int32_t len, int32_t base, double *out); JANET_API int janet_scan_int64(const uint8_t *str, int32_t len, int64_t *out); JANET_API int janet_scan_uint64(const uint8_t *str, int32_t len, uint64_t *out); +#ifdef JANET_INT_TYPES +JANET_API int janet_scan_numeric(const uint8_t *str, int32_t len, Janet *out); +#endif /* Debugging */ JANET_API void janet_debug_break(JanetFuncDef *def, int32_t pc); diff --git a/test/suite-inttypes.janet b/test/suite-inttypes.janet index 6f5c35eb..67272130 100644 --- a/test/suite-inttypes.janet +++ b/test/suite-inttypes.janet @@ -47,6 +47,14 @@ (assert (= (int/to-number (i64 9007199254740991)) 9007199254740991)) (assert (= (int/to-number (i64 -9007199254740991)) -9007199254740991)) +# New parser +(assert (= (u64 "123") 123:u) "u64 parsing") +(assert (= (u64 "0") 0:u) "u64 parsing") +(assert (= (u64 "0xFFFF_FFFF_FFFF_FFFF") 0xFFFF_FFFF_FFFF_FFFF:u) "u64 parsing") +(assert (= (i64 "123") 123:s) "s64 parsing") +(assert (= (i64 "-123") -123:s) "s64 parsing") +(assert (= (i64 "0") 0:s) "s64 parsing") + (assert-error "u64 out of bounds for safe integer" (int/to-number (u64 "9007199254740993"))