diff --git a/src/kuroko/value.h b/src/kuroko/value.h index e0c2deb..60093c6 100644 --- a/src/kuroko/value.h +++ b/src/kuroko/value.h @@ -151,6 +151,7 @@ static inline int krk_valuesSame(KrkValue a, KrkValue b) { return _krk_valuesSam extern int krk_valuesSameOrEqual(KrkValue a, KrkValue b); extern KrkValue krk_parse_int(const char * start, size_t width, unsigned int base); +extern KrkValue krk_parse_float(const char* start, size_t width); #ifndef KRK_NO_NAN_BOXING diff --git a/src/obj_long.c b/src/obj_long.c index 4225763..3fed013 100644 --- a/src/obj_long.c +++ b/src/obj_long.c @@ -2741,6 +2741,117 @@ KrkValue krk_double_to_string(double a, unsigned int digits, char formatter, int free(str); return krk_finishStringBuilder(&sb); } + +KrkValue krk_parse_float(const char * s, size_t l) { + size_t c = 0; + int sign = 1; + size_t ps = 0, pe = 0, ss = 0, se = 0, es = 0, ee = 0; + + union Float { double d; uint64_t i; }; + + if (s[c] == '-') { + sign = -1; + c++; + ps = 1; + } + + if (c + 3 == l) { + if (((s[c+0] | 0x20) == 'n') && ((s[c+1] | 0x20) == 'a') && ((s[c+2] | 0x20) == 'n')) { + return FLOATING_VAL(((union Float){.i=0x7ff0000000000001ULL}).d); + } + if (((s[c+0] | 0x20) == 'i') && ((s[c+1] | 0x20) == 'n') && ((s[c+2] | 0x20) == 'f')) { + return FLOATING_VAL(((union Float){.i=0x7ff0000000000000ULL}).d * sign); + } + } + + while (c < l && ((s[c] >= '0' && s[c] <= '9') || s[c] == '_')) c++; + pe = c; + + if (c < l && s[c] == '.') { + c++; + ss = c; + while (c < l && s[c] >= '0' && s[c] <= '9') c++; + se = c; + } + + if (c < l && (s[c] == 'e' || s[c] == 'E')) { + c++; + es = c; + if (c < l && s[c] == '-') c++; + else if (c < l && s[c] == '+') { c++; es++; } + while (c < l && s[c] >= '0' && s[c] <= '9') c++; + ee = c; + } + + if (c != l) return krk_runtimeError(vm.exceptions->valueError, "invalid literal for float"); + + struct StringBuilder sb = {0}; + for (size_t i = ps; i < pe; ++i) { + if (!sb.length && s[i] == '0') continue; + if (s[i] == '_') continue; + krk_pushStringBuilder(&sb,s[i]); + } + for (size_t i = ss; i < se; ++i) { + if (!sb.length && s[i] == '0') continue; + krk_pushStringBuilder(&sb,s[i]); + } + + const char * m = sb.bytes; + size_t m_len = sb.length; + if (!sb.length) { + m = "0"; + m_len = 1; + } + + KrkLong m_l; + krk_long_parse_string(m,&m_l,10,m_len); + krk_discardStringBuilder(&sb); + krk_long_set_sign(&m_l,sign); + + const char * e = (es != ee) ? &s[es] : "0"; + size_t e_len = (es != ee) ? (ee-es) : 1; + + KrkLong e_l; + krk_long_parse_string(e,&e_l,10,e_len); + + if (e_l.width > 1) { + krk_long_clear_many(&m_l,&e_l,NULL); + return FLOATING_VAL(((union Float){.i=0x7ff0000000000000ULL}).d * sign); + } else if (e_l.width < -1) { + krk_long_clear_many(&m_l,&e_l,NULL); + return FLOATING_VAL(0.0); + } + + int64_t exp = krk_long_medium(&e_l); + ssize_t digits = (se - ss) - exp; + + if (digits > 0) { + KrkLong ten_digits, digits_el; + krk_long_init_si(&ten_digits, 10); + krk_long_init_si(&digits_el, digits); + _krk_long_pow(&ten_digits,&ten_digits,&digits_el); + KrkValue v = _krk_long_truediv(&m_l, &ten_digits); + krk_long_clear_many(&digits_el,&m_l,&e_l,&ten_digits, NULL); + return v; + } else if (digits < 0) { + KrkLong ten_digits, digits_el, one; + krk_long_init_si(&ten_digits, 10); + krk_long_init_si(&digits_el, -digits); + krk_long_init_si(&one, 1); + _krk_long_pow(&ten_digits,&ten_digits,&digits_el); + krk_long_mul(&m_l,&m_l,&ten_digits); + KrkValue v = _krk_long_truediv(&m_l, &one); + krk_long_clear_many(&digits_el,&m_l,&e_l,&ten_digits,&one,NULL); + return v; + } else { + KrkLong one; + krk_long_init_si(&one, 1); + KrkValue v = _krk_long_truediv(&m_l, &one); + krk_long_clear_many(&m_l,&e_l,&one,NULL); + return v; + } +} + #endif /**