aboutsummaryrefslogtreecommitdiff
path: root/src/lj_strscan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_strscan.c')
-rw-r--r--src/lj_strscan.c80
1 files changed, 67 insertions, 13 deletions
diff --git a/src/lj_strscan.c b/src/lj_strscan.c
index 914cfb7a..1d1c1c74 100644
--- a/src/lj_strscan.c
+++ b/src/lj_strscan.c
@@ -80,7 +80,7 @@ static void strscan_double(uint64_t x, TValue *o, int32_t ex2, int32_t neg)
80 /* Avoid double rounding for denormals. */ 80 /* Avoid double rounding for denormals. */
81 if (LJ_UNLIKELY(ex2 <= -1075 && x != 0)) { 81 if (LJ_UNLIKELY(ex2 <= -1075 && x != 0)) {
82 /* NYI: all of this generates way too much code on 32 bit CPUs. */ 82 /* NYI: all of this generates way too much code on 32 bit CPUs. */
83#if defined(__GNUC__) && LJ_64 83#if (defined(__GNUC__) || defined(__clang__)) && LJ_64
84 int32_t b = (int32_t)(__builtin_clzll(x)^63); 84 int32_t b = (int32_t)(__builtin_clzll(x)^63);
85#else 85#else
86 int32_t b = (x>>32) ? 32+(int32_t)lj_fls((uint32_t)(x>>32)) : 86 int32_t b = (x>>32) ? 32+(int32_t)lj_fls((uint32_t)(x>>32)) :
@@ -94,7 +94,7 @@ static void strscan_double(uint64_t x, TValue *o, int32_t ex2, int32_t neg)
94 } 94 }
95 95
96 /* Convert to double using a signed int64_t conversion, then rescale. */ 96 /* Convert to double using a signed int64_t conversion, then rescale. */
97 lua_assert((int64_t)x >= 0); 97 lj_assertX((int64_t)x >= 0, "bad double conversion");
98 n = (double)(int64_t)x; 98 n = (double)(int64_t)x;
99 if (neg) n = -n; 99 if (neg) n = -n;
100 if (ex2) n = ldexp(n, ex2); 100 if (ex2) n = ldexp(n, ex2);
@@ -142,7 +142,7 @@ static StrScanFmt strscan_hex(const uint8_t *p, TValue *o,
142 break; 142 break;
143 } 143 }
144 144
145 /* Reduce range then convert to double. */ 145 /* Reduce range, then convert to double. */
146 if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } 146 if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; }
147 strscan_double(x, o, ex2, neg); 147 strscan_double(x, o, ex2, neg);
148 return fmt; 148 return fmt;
@@ -264,7 +264,7 @@ static StrScanFmt strscan_dec(const uint8_t *p, TValue *o,
264 uint32_t hi = 0, lo = (uint32_t)(xip-xi); 264 uint32_t hi = 0, lo = (uint32_t)(xip-xi);
265 int32_t ex2 = 0, idig = (int32_t)lo + (ex10 >> 1); 265 int32_t ex2 = 0, idig = (int32_t)lo + (ex10 >> 1);
266 266
267 lua_assert(lo > 0 && (ex10 & 1) == 0); 267 lj_assertX(lo > 0 && (ex10 & 1) == 0, "bad lo %d ex10 %d", lo, ex10);
268 268
269 /* Handle simple overflow/underflow. */ 269 /* Handle simple overflow/underflow. */
270 if (idig > 310/2) { if (neg) setminfV(o); else setpinfV(o); return fmt; } 270 if (idig > 310/2) { if (neg) setminfV(o); else setpinfV(o); return fmt; }
@@ -328,10 +328,55 @@ static StrScanFmt strscan_dec(const uint8_t *p, TValue *o,
328 return fmt; 328 return fmt;
329} 329}
330 330
331/* Parse binary number. */
332static StrScanFmt strscan_bin(const uint8_t *p, TValue *o,
333 StrScanFmt fmt, uint32_t opt,
334 int32_t ex2, int32_t neg, uint32_t dig)
335{
336 uint64_t x = 0;
337 uint32_t i;
338
339 if (ex2 || dig > 64) return STRSCAN_ERROR;
340
341 /* Scan binary digits. */
342 for (i = dig; i; i--, p++) {
343 if ((*p & ~1) != '0') return STRSCAN_ERROR;
344 x = (x << 1) | (*p & 1);
345 }
346
347 /* Format-specific handling. */
348 switch (fmt) {
349 case STRSCAN_INT:
350 if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) {
351 o->i = neg ? -(int32_t)x : (int32_t)x;
352 return STRSCAN_INT; /* Fast path for 32 bit integers. */
353 }
354 if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; break; }
355 /* fallthrough */
356 case STRSCAN_U32:
357 if (dig > 32) return STRSCAN_ERROR;
358 o->i = neg ? -(int32_t)x : (int32_t)x;
359 return STRSCAN_U32;
360 case STRSCAN_I64:
361 case STRSCAN_U64:
362 o->u64 = neg ? (uint64_t)-(int64_t)x : x;
363 return fmt;
364 default:
365 break;
366 }
367
368 /* Reduce range, then convert to double. */
369 if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; }
370 strscan_double(x, o, ex2, neg);
371 return fmt;
372}
373
331/* Scan string containing a number. Returns format. Returns value in o. */ 374/* Scan string containing a number. Returns format. Returns value in o. */
332StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) 375StrScanFmt lj_strscan_scan(const uint8_t *p, MSize len, TValue *o,
376 uint32_t opt)
333{ 377{
334 int32_t neg = 0; 378 int32_t neg = 0;
379 const uint8_t *pe = p + len;
335 380
336 /* Remove leading space, parse sign and non-numbers. */ 381 /* Remove leading space, parse sign and non-numbers. */
337 if (LJ_UNLIKELY(!lj_char_isdigit(*p))) { 382 if (LJ_UNLIKELY(!lj_char_isdigit(*p))) {
@@ -349,7 +394,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
349 p += 3; 394 p += 3;
350 } 395 }
351 while (lj_char_isspace(*p)) p++; 396 while (lj_char_isspace(*p)) p++;
352 if (*p) return STRSCAN_ERROR; 397 if (*p || p < pe) return STRSCAN_ERROR;
353 o->u64 = tmp.u64; 398 o->u64 = tmp.u64;
354 return STRSCAN_NUM; 399 return STRSCAN_NUM;
355 } 400 }
@@ -366,8 +411,12 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
366 411
367 /* Determine base and skip leading zeros. */ 412 /* Determine base and skip leading zeros. */
368 if (LJ_UNLIKELY(*p <= '0')) { 413 if (LJ_UNLIKELY(*p <= '0')) {
369 if (*p == '0' && casecmp(p[1], 'x')) 414 if (*p == '0') {
370 base = 16, cmask = LJ_CHAR_XDIGIT, p += 2; 415 if (casecmp(p[1], 'x'))
416 base = 16, cmask = LJ_CHAR_XDIGIT, p += 2;
417 else if (casecmp(p[1], 'b'))
418 base = 2, cmask = LJ_CHAR_DIGIT, p += 2;
419 }
371 for ( ; ; p++) { 420 for ( ; ; p++) {
372 if (*p == '0') { 421 if (*p == '0') {
373 hasdig = 1; 422 hasdig = 1;
@@ -396,6 +445,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
396 445
397 /* Handle decimal point. */ 446 /* Handle decimal point. */
398 if (dp) { 447 if (dp) {
448 if (base == 2) return STRSCAN_ERROR;
399 fmt = STRSCAN_NUM; 449 fmt = STRSCAN_NUM;
400 if (dig) { 450 if (dig) {
401 ex = (int32_t)(dp-(p-1)); dp = p-1; 451 ex = (int32_t)(dp-(p-1)); dp = p-1;
@@ -406,7 +456,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
406 } 456 }
407 457
408 /* Parse exponent. */ 458 /* Parse exponent. */
409 if (casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) { 459 if (base >= 10 && casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) {
410 uint32_t xx; 460 uint32_t xx;
411 int negx = 0; 461 int negx = 0;
412 fmt = STRSCAN_NUM; p++; 462 fmt = STRSCAN_NUM; p++;
@@ -445,6 +495,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
445 while (lj_char_isspace(*p)) p++; 495 while (lj_char_isspace(*p)) p++;
446 if (*p) return STRSCAN_ERROR; 496 if (*p) return STRSCAN_ERROR;
447 } 497 }
498 if (p < pe) return STRSCAN_ERROR;
448 499
449 /* Fast path for decimal 32 bit integers. */ 500 /* Fast path for decimal 32 bit integers. */
450 if (fmt == STRSCAN_INT && base == 10 && 501 if (fmt == STRSCAN_INT && base == 10 &&
@@ -466,6 +517,8 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
466 return strscan_oct(sp, o, fmt, neg, dig); 517 return strscan_oct(sp, o, fmt, neg, dig);
467 if (base == 16) 518 if (base == 16)
468 fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig); 519 fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig);
520 else if (base == 2)
521 fmt = strscan_bin(sp, o, fmt, opt, ex, neg, dig);
469 else 522 else
470 fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig); 523 fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig);
471 524
@@ -481,18 +534,19 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt)
481 534
482int LJ_FASTCALL lj_strscan_num(GCstr *str, TValue *o) 535int LJ_FASTCALL lj_strscan_num(GCstr *str, TValue *o)
483{ 536{
484 StrScanFmt fmt = lj_strscan_scan((const uint8_t *)strdata(str), o, 537 StrScanFmt fmt = lj_strscan_scan((const uint8_t *)strdata(str), str->len, o,
485 STRSCAN_OPT_TONUM); 538 STRSCAN_OPT_TONUM);
486 lua_assert(fmt == STRSCAN_ERROR || fmt == STRSCAN_NUM); 539 lj_assertX(fmt == STRSCAN_ERROR || fmt == STRSCAN_NUM, "bad scan format");
487 return (fmt != STRSCAN_ERROR); 540 return (fmt != STRSCAN_ERROR);
488} 541}
489 542
490#if LJ_DUALNUM 543#if LJ_DUALNUM
491int LJ_FASTCALL lj_strscan_number(GCstr *str, TValue *o) 544int LJ_FASTCALL lj_strscan_number(GCstr *str, TValue *o)
492{ 545{
493 StrScanFmt fmt = lj_strscan_scan((const uint8_t *)strdata(str), o, 546 StrScanFmt fmt = lj_strscan_scan((const uint8_t *)strdata(str), str->len, o,
494 STRSCAN_OPT_TOINT); 547 STRSCAN_OPT_TOINT);
495 lua_assert(fmt == STRSCAN_ERROR || fmt == STRSCAN_NUM || fmt == STRSCAN_INT); 548 lj_assertX(fmt == STRSCAN_ERROR || fmt == STRSCAN_NUM || fmt == STRSCAN_INT,
549 "bad scan format");
496 if (fmt == STRSCAN_INT) setitype(o, LJ_TISNUM); 550 if (fmt == STRSCAN_INT) setitype(o, LJ_TISNUM);
497 return (fmt != STRSCAN_ERROR); 551 return (fmt != STRSCAN_ERROR);
498} 552}