@scriptc/runtime 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/scr_runtime.h +10 -0
- package/src/scr_string.c +88 -0
package/package.json
CHANGED
package/src/scr_runtime.h
CHANGED
|
@@ -458,6 +458,16 @@ ScrStr *scr_regexp_escape(ScrStr *s);
|
|
|
458
458
|
double scr_parse_int(ScrStr *s, double radix);
|
|
459
459
|
double scr_parse_float(ScrStr *s);
|
|
460
460
|
|
|
461
|
+
/* ToNumber(string) — ECMA-262 7.1.4.1 StringToNumber exactly: trim
|
|
462
|
+
* StrWhiteSpace (the JS set, line terminators included) from both ends,
|
|
463
|
+
* empty/whitespace-only → +0, then the WHOLE remaining span must be one
|
|
464
|
+
* StrNumericLiteral — a signed decimal literal ("Infinity" exact-case
|
|
465
|
+
* included, correctly rounded via strtod over the validated span) or an
|
|
466
|
+
* UNSIGNED 0x/0o/0b integer literal (exact value rounded to nearest-even;
|
|
467
|
+
* a sign on those is NaN, per grammar). Any trailing garbage → NaN.
|
|
468
|
+
* Borrows s; never throws. */
|
|
469
|
+
double scr_string_to_number(ScrStr *s);
|
|
470
|
+
|
|
461
471
|
/* encodeURIComponent — ECMA-262 Encode with the component unreserved set
|
|
462
472
|
* (ALPHA/DIGIT/- _ . ! ~ * ' ( )): every other byte of the UTF-8 string
|
|
463
473
|
* percent-encodes as uppercase %XX (the spec's per-code-point UTF-8
|
package/src/scr_string.c
CHANGED
|
@@ -944,6 +944,94 @@ double scr_parse_float(ScrStr *s) {
|
|
|
944
944
|
return r;
|
|
945
945
|
}
|
|
946
946
|
|
|
947
|
+
/* ToNumber(string) — ECMA-262 7.1.4.1 StringToNumber, exactly. The
|
|
948
|
+
* grammar (StringNumericLiteral) differs from parseFloat's in all three
|
|
949
|
+
* directions: the WHOLE trimmed span must match (trailing garbage → NaN,
|
|
950
|
+
* where parseFloat keeps the longest prefix), the non-decimal 0x/0o/0b
|
|
951
|
+
* integer literals join (UNSIGNED only — a sign on them is NaN), and the
|
|
952
|
+
* empty/whitespace-only string is +0 (parseFloat: NaN). Decimal spans
|
|
953
|
+
* convert through strtod like parseFloat (copied first — strtod's own
|
|
954
|
+
* grammar is wider — inheriting correct rounding, the JSON precedent);
|
|
955
|
+
* 0x/0o/0b digits are the exact mathematical value rounded to nearest-
|
|
956
|
+
* even via scr_digits_to_double (u64 fast path, bignum beyond 2^64 —
|
|
957
|
+
* Node-exact for giant hex, Infinity overflow included: power-of-two
|
|
958
|
+
* radixes take the exact path, never V8's approximate chunk loop). */
|
|
959
|
+
double scr_string_to_number(ScrStr *s) {
|
|
960
|
+
const char *p = s->data;
|
|
961
|
+
size_t b = 0, e = s->len;
|
|
962
|
+
while (b < e) {
|
|
963
|
+
size_t adv;
|
|
964
|
+
uint32_t cp = scr_utf8_decode(p + b, &adv);
|
|
965
|
+
if (!scr_is_js_whitespace(cp)) break;
|
|
966
|
+
b += adv;
|
|
967
|
+
}
|
|
968
|
+
while (e > b) {
|
|
969
|
+
size_t cs = e - 1; /* back up to the lead byte of the last char */
|
|
970
|
+
while (cs > b && ((unsigned char)p[cs] & 0xC0) == 0x80) cs--;
|
|
971
|
+
size_t adv;
|
|
972
|
+
uint32_t cp = scr_utf8_decode(p + cs, &adv);
|
|
973
|
+
if (!scr_is_js_whitespace(cp)) break;
|
|
974
|
+
e = cs;
|
|
975
|
+
}
|
|
976
|
+
if (b == e) return 0.0; /* empty or all StrWhiteSpace */
|
|
977
|
+
p += b;
|
|
978
|
+
size_t n = e - b;
|
|
979
|
+
/* NonDecimalIntegerLiteral: 0x/0X, 0o/0O, 0b/0B — no sign admitted. */
|
|
980
|
+
if (n >= 2 && p[0] == '0' &&
|
|
981
|
+
(p[1] == 'x' || p[1] == 'X' || p[1] == 'o' || p[1] == 'O' ||
|
|
982
|
+
p[1] == 'b' || p[1] == 'B')) {
|
|
983
|
+
int radix = (p[1] == 'x' || p[1] == 'X') ? 16
|
|
984
|
+
: (p[1] == 'o' || p[1] == 'O') ? 8
|
|
985
|
+
: 2;
|
|
986
|
+
size_t i = 2, dig_start = 2;
|
|
987
|
+
while (i < n && scr_digit_value(p[i]) < radix) i++;
|
|
988
|
+
if (i == dig_start || i != n) return NAN; /* no digits, or garbage */
|
|
989
|
+
while (dig_start < i && p[dig_start] == '0') dig_start++;
|
|
990
|
+
if (dig_start == i) return 0.0;
|
|
991
|
+
return scr_digits_to_double(p + dig_start, i - dig_start, radix);
|
|
992
|
+
}
|
|
993
|
+
/* StrDecimalLiteral, whole-span: [+-]? (Infinity | digits [. digits*]
|
|
994
|
+
* | . digits) ([eE][+-]?digits)? — nothing before, nothing after. */
|
|
995
|
+
size_t i = 0;
|
|
996
|
+
double sign = 1.0;
|
|
997
|
+
if (p[0] == '+' || p[0] == '-') {
|
|
998
|
+
if (p[0] == '-') sign = -1.0;
|
|
999
|
+
i = 1;
|
|
1000
|
+
}
|
|
1001
|
+
if (n - i == 8 && memcmp(p + i, "Infinity", 8) == 0) {
|
|
1002
|
+
return sign * (double)INFINITY;
|
|
1003
|
+
}
|
|
1004
|
+
size_t int_digits = 0, frac_digits = 0;
|
|
1005
|
+
while (i < n && p[i] >= '0' && p[i] <= '9') {
|
|
1006
|
+
i++;
|
|
1007
|
+
int_digits++;
|
|
1008
|
+
}
|
|
1009
|
+
if (i < n && p[i] == '.') {
|
|
1010
|
+
i++;
|
|
1011
|
+
while (i < n && p[i] >= '0' && p[i] <= '9') {
|
|
1012
|
+
i++;
|
|
1013
|
+
frac_digits++;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
if (int_digits == 0 && frac_digits == 0) return NAN; /* ".", "+", "e5" */
|
|
1017
|
+
if (i < n && (p[i] == 'e' || p[i] == 'E')) {
|
|
1018
|
+
i++;
|
|
1019
|
+
if (i < n && (p[i] == '+' || p[i] == '-')) i++;
|
|
1020
|
+
size_t ed = i;
|
|
1021
|
+
while (i < n && p[i] >= '0' && p[i] <= '9') i++;
|
|
1022
|
+
if (i == ed) return NAN; /* "1e", "1e+" — exponent needs digits */
|
|
1023
|
+
}
|
|
1024
|
+
if (i != n) return NAN; /* trailing garbage ("1_000", "1.2.3", "12px") */
|
|
1025
|
+
char buf[64];
|
|
1026
|
+
char *tmp = n < sizeof(buf) ? buf : malloc(n + 1);
|
|
1027
|
+
if (!tmp) scr_oom();
|
|
1028
|
+
memcpy(tmp, p, n);
|
|
1029
|
+
tmp[n] = '\0';
|
|
1030
|
+
double r = strtod(tmp, NULL);
|
|
1031
|
+
if (tmp != buf) free(tmp);
|
|
1032
|
+
return r;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
947
1035
|
ScrStr *scr_f64_to_scrstr(double x) {
|
|
948
1036
|
char buf[32];
|
|
949
1037
|
size_t len = scr_f64_to_str(x, buf);
|