Merge branch 'quickjs-ng:master' into gc-callbacks
This commit is contained in:
commit
f722d5c440
22 changed files with 4822 additions and 3711 deletions
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
|
@ -71,6 +71,26 @@ jobs:
|
|||
- name: test
|
||||
run: |
|
||||
make test
|
||||
linux-riscv64:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: alpine.sh {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: riscv64
|
||||
packages: "build-base make cmake"
|
||||
- name: build
|
||||
run: |
|
||||
make
|
||||
- name: stats
|
||||
run: |
|
||||
make stats
|
||||
- name: test
|
||||
run: |
|
||||
make test
|
||||
linux-s390x:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
|
|
62
.github/workflows/release.yml
vendored
62
.github/workflows/release.yml
vendored
|
@ -6,6 +6,62 @@ on:
|
|||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
linux-aarch64:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: aarch64
|
||||
packages: "build-base make cmake"
|
||||
- name: build
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_STATIC_QJS_EXE=ON ..
|
||||
cd ..
|
||||
cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN)
|
||||
cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN)
|
||||
mv build/qjs build/qjs-linux-aarch64
|
||||
mv build/qjsc build/qjsc-linux-aarch64
|
||||
- name: check
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
file build/*-linux-aarch64
|
||||
- name: upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qjs
|
||||
path: build/*-linux-aarch64
|
||||
linux-riscv64:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: riscv64
|
||||
packages: "build-base make cmake"
|
||||
- name: build
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_STATIC_QJS_EXE=ON ..
|
||||
cd ..
|
||||
cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN)
|
||||
cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN)
|
||||
mv build/qjs build/qjs-linux-riscv64
|
||||
mv build/qjsc build/qjsc-linux-riscv64
|
||||
- name: check
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
file build/*-linux-riscv64
|
||||
- name: upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qjs
|
||||
path: build/*-linux-riscv64
|
||||
linux-x86:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
|
@ -28,7 +84,7 @@ jobs:
|
|||
- name: check
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
file build/qjs-linux-x86 build/qjsc-linux-x86
|
||||
file build/*-linux-x86
|
||||
- name: upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
@ -57,7 +113,7 @@ jobs:
|
|||
- name: check
|
||||
shell: alpine.sh {0}
|
||||
run: |
|
||||
file build/qjs-linux-x86_64 build/qjsc-linux-x86_64
|
||||
file build/*-linux-x86_64
|
||||
- name: upload
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
@ -169,7 +225,7 @@ jobs:
|
|||
path: build/qjs-wasi.wasm
|
||||
|
||||
upload-to-release:
|
||||
needs: [linux-x86, linux-x86_64, macos, windows-x86, windows-x86_64, wasi]
|
||||
needs: [linux-aarch64, linux-riscv64, linux-x86, linux-x86_64, macos, windows-x86, windows-x86_64, wasi]
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: get assets
|
||||
|
|
460
cutils.c
460
cutils.c
|
@ -213,58 +213,85 @@ void dbuf_free(DynBuf *s)
|
|||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
/*--- Unicode / UTF-8 utility functions --*/
|
||||
/*--- UTF-8 utility functions --*/
|
||||
|
||||
/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes
|
||||
are output. */
|
||||
int unicode_to_utf8(uint8_t *buf, unsigned int c)
|
||||
/* Note: only encode valid codepoints (0x0000..0x10FFFF).
|
||||
At most UTF8_CHAR_LEN_MAX bytes are output. */
|
||||
|
||||
/* Compute the number of bytes of the UTF-8 encoding for a codepoint
|
||||
`c` is a code-point.
|
||||
Returns the number of bytes. If a codepoint is beyond 0x10FFFF the
|
||||
return value is 3 as the codepoint would be encoded as 0xFFFD.
|
||||
*/
|
||||
size_t utf8_encode_len(uint32_t c)
|
||||
{
|
||||
uint8_t *q = buf;
|
||||
|
||||
if (c < 0x80) {
|
||||
*q++ = c;
|
||||
} else {
|
||||
if (c < 0x800) {
|
||||
*q++ = (c >> 6) | 0xc0;
|
||||
} else {
|
||||
if (c < 0x10000) {
|
||||
*q++ = (c >> 12) | 0xe0;
|
||||
} else {
|
||||
if (c < 0x00200000) {
|
||||
*q++ = (c >> 18) | 0xf0;
|
||||
} else {
|
||||
if (c < 0x04000000) {
|
||||
*q++ = (c >> 24) | 0xf8;
|
||||
} else if (c < 0x80000000) {
|
||||
*q++ = (c >> 30) | 0xfc;
|
||||
*q++ = ((c >> 24) & 0x3f) | 0x80;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
*q++ = ((c >> 18) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = ((c >> 12) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = ((c >> 6) & 0x3f) | 0x80;
|
||||
}
|
||||
*q++ = (c & 0x3f) | 0x80;
|
||||
}
|
||||
return q - buf;
|
||||
if (c < 0x80)
|
||||
return 1;
|
||||
if (c < 0x800)
|
||||
return 2;
|
||||
if (c < 0x10000)
|
||||
return 3;
|
||||
if (c < 0x110000)
|
||||
return 4;
|
||||
return 3;
|
||||
}
|
||||
|
||||
static const unsigned int utf8_min_code[5] = {
|
||||
0x80, 0x800, 0x10000, 0x00200000, 0x04000000,
|
||||
};
|
||||
|
||||
static const unsigned char utf8_first_code_mask[5] = {
|
||||
0x1f, 0xf, 0x7, 0x3, 0x1,
|
||||
};
|
||||
|
||||
/* return -1 if error. *pp is not updated in this case. max_len must
|
||||
be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */
|
||||
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
|
||||
/* Encode a codepoint in UTF-8
|
||||
`buf` points to an array of at least `UTF8_CHAR_LEN_MAX` bytes
|
||||
`c` is a code-point.
|
||||
Returns the number of bytes. If a codepoint is beyond 0x10FFFF the
|
||||
return value is 3 and the codepoint is encoded as 0xFFFD.
|
||||
No null byte is stored after the encoded bytes.
|
||||
Return value is in range 1..4
|
||||
*/
|
||||
size_t utf8_encode(uint8_t *buf, uint32_t c)
|
||||
{
|
||||
int l, c, b, i;
|
||||
if (c < 0x80) {
|
||||
buf[0] = c;
|
||||
return 1;
|
||||
}
|
||||
if (c < 0x800) {
|
||||
buf[0] = (c >> 6) | 0xC0;
|
||||
buf[1] = (c & 0x3F) | 0x80;
|
||||
return 2;
|
||||
}
|
||||
if (c < 0x10000) {
|
||||
buf[0] = (c >> 12) | 0xE0;
|
||||
buf[1] = ((c >> 6) & 0x3F) | 0x80;
|
||||
buf[2] = (c & 0x3F) | 0x80;
|
||||
return 3;
|
||||
}
|
||||
if (c < 0x110000) {
|
||||
buf[0] = (c >> 18) | 0xF0;
|
||||
buf[1] = ((c >> 12) & 0x3F) | 0x80;
|
||||
buf[2] = ((c >> 6) & 0x3F) | 0x80;
|
||||
buf[3] = (c & 0x3F) | 0x80;
|
||||
return 4;
|
||||
}
|
||||
buf[0] = (0xFFFD >> 12) | 0xE0;
|
||||
buf[1] = ((0xFFFD >> 6) & 0x3F) | 0x80;
|
||||
buf[2] = (0xFFFD & 0x3F) | 0x80;
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* Decode a single code point from a UTF-8 encoded array of bytes
|
||||
`p` is a valid pointer to an array of bytes
|
||||
`pp` is a valid pointer to a `const uint8_t *` to store a pointer
|
||||
to the byte following the current sequence.
|
||||
Return the code point at `p`, in the range `0..0x10FFFF`
|
||||
Return 0xFFFD on error. Only a single byte is consumed in this case
|
||||
The maximum length for a UTF-8 byte sequence is 4 bytes.
|
||||
This implements the algorithm specified in whatwg.org, except it accepts
|
||||
UTF-8 encoded surrogates as JavaScript allows them in strings.
|
||||
The source string is assumed to have at least UTF8_CHAR_LEN_MAX bytes
|
||||
or be null terminated.
|
||||
If `p[0]` is '\0', the return value is `0` and the byte is consumed.
|
||||
cf: https://encoding.spec.whatwg.org/#utf-8-encoder
|
||||
*/
|
||||
uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp)
|
||||
{
|
||||
uint32_t c;
|
||||
uint8_t lower, upper;
|
||||
|
||||
c = *p++;
|
||||
if (c < 0x80) {
|
||||
|
@ -272,49 +299,283 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
|
|||
return c;
|
||||
}
|
||||
switch(c) {
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
||||
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
||||
case 0xc8: case 0xc9: case 0xca: case 0xcb:
|
||||
case 0xcc: case 0xcd: case 0xce: case 0xcf:
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
|
||||
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb:
|
||||
case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
l = 1;
|
||||
case 0xC2: case 0xC3:
|
||||
case 0xC4: case 0xC5: case 0xC6: case 0xC7:
|
||||
case 0xC8: case 0xC9: case 0xCA: case 0xCB:
|
||||
case 0xCC: case 0xCD: case 0xCE: case 0xCF:
|
||||
case 0xD0: case 0xD1: case 0xD2: case 0xD3:
|
||||
case 0xD4: case 0xD5: case 0xD6: case 0xD7:
|
||||
case 0xD8: case 0xD9: case 0xDA: case 0xDB:
|
||||
case 0xDC: case 0xDD: case 0xDE: case 0xDF:
|
||||
if (*p >= 0x80 && *p <= 0xBF) {
|
||||
*pp = p + 1;
|
||||
return ((c - 0xC0) << 6) + (*p - 0x80);
|
||||
}
|
||||
// otherwise encoding error
|
||||
break;
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
||||
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
l = 2;
|
||||
case 0xE0:
|
||||
lower = 0xA0; /* reject invalid encoding */
|
||||
goto need2;
|
||||
case 0xE1: case 0xE2: case 0xE3:
|
||||
case 0xE4: case 0xE5: case 0xE6: case 0xE7:
|
||||
case 0xE8: case 0xE9: case 0xEA: case 0xEB:
|
||||
case 0xEC: case 0xED: case 0xEE: case 0xEF:
|
||||
lower = 0x80;
|
||||
need2:
|
||||
if (*p >= lower && *p <= 0xBF && p[1] >= 0x80 && p[1] <= 0xBF) {
|
||||
*pp = p + 2;
|
||||
return ((c - 0xE0) << 12) + ((*p - 0x80) << 6) + (p[1] - 0x80);
|
||||
}
|
||||
// otherwise encoding error
|
||||
break;
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
|
||||
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
l = 3;
|
||||
break;
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb:
|
||||
l = 4;
|
||||
break;
|
||||
case 0xfc: case 0xfd:
|
||||
l = 5;
|
||||
case 0xF0:
|
||||
lower = 0x90; /* reject invalid encoding */
|
||||
upper = 0xBF;
|
||||
goto need3;
|
||||
case 0xF4:
|
||||
lower = 0x80;
|
||||
upper = 0x8F; /* reject values above 0x10FFFF */
|
||||
goto need3;
|
||||
case 0xF1: case 0xF2: case 0xF3:
|
||||
lower = 0x80;
|
||||
upper = 0xBF;
|
||||
need3:
|
||||
if (*p >= lower && *p <= upper && p[1] >= 0x80 && p[1] <= 0xBF
|
||||
&& p[2] >= 0x80 && p[2] <= 0xBF) {
|
||||
*pp = p + 3;
|
||||
return ((c - 0xF0) << 18) + ((*p - 0x80) << 12) +
|
||||
((p[1] - 0x80) << 6) + (p[2] - 0x80);
|
||||
}
|
||||
// otherwise encoding error
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
// invalid lead byte
|
||||
break;
|
||||
}
|
||||
/* check that we have enough characters */
|
||||
if (l > (max_len - 1))
|
||||
return -1;
|
||||
c &= utf8_first_code_mask[l - 1];
|
||||
for(i = 0; i < l; i++) {
|
||||
b = *p++;
|
||||
if (b < 0x80 || b >= 0xc0)
|
||||
return -1;
|
||||
c = (c << 6) | (b & 0x3f);
|
||||
}
|
||||
if (c < utf8_min_code[l - 1])
|
||||
return -1;
|
||||
*pp = p;
|
||||
return c;
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp) {
|
||||
switch (max_len) {
|
||||
case 0:
|
||||
*pp = p;
|
||||
return 0xFFFD;
|
||||
case 1:
|
||||
if (*p < 0x80)
|
||||
goto good;
|
||||
break;
|
||||
case 2:
|
||||
if (*p < 0xE0)
|
||||
goto good;
|
||||
break;
|
||||
case 3:
|
||||
if (*p < 0xF0)
|
||||
goto good;
|
||||
break;
|
||||
default:
|
||||
good:
|
||||
return utf8_decode(p, pp);
|
||||
}
|
||||
*pp = p + 1;
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
/* Scan a UTF-8 encoded buffer for content type
|
||||
`buf` is a valid pointer to a UTF-8 encoded string
|
||||
`len` is the number of bytes to scan
|
||||
`plen` points to a `size_t` variable to receive the number of units
|
||||
Return value is a mask of bits.
|
||||
- `UTF8_PLAIN_ASCII`: return value for 7-bit ASCII plain text
|
||||
- `UTF8_NON_ASCII`: bit for non ASCII code points (8-bit or more)
|
||||
- `UTF8_HAS_16BIT`: bit for 16-bit code points
|
||||
- `UTF8_HAS_NON_BMP1`: bit for non-BMP1 code points, needs UTF-16 surrogate pairs
|
||||
- `UTF8_HAS_ERRORS`: bit for encoding errors
|
||||
*/
|
||||
int utf8_scan(const char *buf, size_t buf_len, size_t *plen)
|
||||
{
|
||||
const uint8_t *p, *p_end, *p_next;
|
||||
size_t i, len;
|
||||
int kind;
|
||||
uint8_t cbits;
|
||||
|
||||
kind = UTF8_PLAIN_ASCII;
|
||||
cbits = 0;
|
||||
len = buf_len;
|
||||
// TODO: handle more than 1 byte at a time
|
||||
for (i = 0; i < buf_len; i++)
|
||||
cbits |= buf[i];
|
||||
if (cbits >= 0x80) {
|
||||
p = (const uint8_t *)buf;
|
||||
p_end = p + buf_len;
|
||||
kind = UTF8_NON_ASCII;
|
||||
len = 0;
|
||||
while (p < p_end) {
|
||||
len++;
|
||||
if (*p++ >= 0x80) {
|
||||
/* parse UTF-8 sequence, check for encoding error */
|
||||
uint32_t c = utf8_decode_len(p - 1, p_end - (p - 1), &p_next);
|
||||
if (p_next == p)
|
||||
kind |= UTF8_HAS_ERRORS;
|
||||
p = p_next;
|
||||
if (c > 0xFF) {
|
||||
kind |= UTF8_HAS_16BIT;
|
||||
if (c > 0xFFFF) {
|
||||
len++;
|
||||
kind |= UTF8_HAS_NON_BMP1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*plen = len;
|
||||
return kind;
|
||||
}
|
||||
|
||||
/* Decode a string encoded in UTF-8 into an array of bytes
|
||||
`src` points to the source string. It is assumed to be correctly encoded
|
||||
and only contains code points below 0x800
|
||||
`src_len` is the length of the source string
|
||||
`dest` points to the destination array, it can be null if `dest_len` is `0`
|
||||
`dest_len` is the length of the destination array. A null
|
||||
terminator is stored at the end of the array unless `dest_len` is `0`.
|
||||
*/
|
||||
size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len)
|
||||
{
|
||||
const uint8_t *p, *p_end;
|
||||
size_t i;
|
||||
|
||||
p = (const uint8_t *)src;
|
||||
p_end = p + src_len;
|
||||
for (i = 0; p < p_end; i++) {
|
||||
uint32_t c = *p++;
|
||||
if (c >= 0xC0)
|
||||
c = (c << 6) + *p++ - ((0xC0 << 6) + 0x80);
|
||||
if (i < dest_len)
|
||||
dest[i] = c;
|
||||
}
|
||||
if (i < dest_len)
|
||||
dest[i] = '\0';
|
||||
else if (dest_len > 0)
|
||||
dest[dest_len - 1] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Decode a string encoded in UTF-8 into an array of 16-bit words
|
||||
`src` points to the source string. It is assumed to be correctly encoded.
|
||||
`src_len` is the length of the source string
|
||||
`dest` points to the destination array, it can be null if `dest_len` is `0`
|
||||
`dest_len` is the length of the destination array. No null terminator is
|
||||
stored at the end of the array.
|
||||
*/
|
||||
size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len)
|
||||
{
|
||||
const uint8_t *p, *p_end;
|
||||
size_t i;
|
||||
|
||||
p = (const uint8_t *)src;
|
||||
p_end = p + src_len;
|
||||
for (i = 0; p < p_end; i++) {
|
||||
uint32_t c = *p++;
|
||||
if (c >= 0x80) {
|
||||
/* parse utf-8 sequence */
|
||||
c = utf8_decode_len(p - 1, p_end - (p - 1), &p);
|
||||
/* encoding errors are converted as 0xFFFD and use a single byte */
|
||||
if (c > 0xFFFF) {
|
||||
if (i < dest_len)
|
||||
dest[i] = get_hi_surrogate(c);
|
||||
i++;
|
||||
c = get_lo_surrogate(c);
|
||||
}
|
||||
}
|
||||
if (i < dest_len)
|
||||
dest[i] = c;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Encode a buffer of 8-bit bytes as a UTF-8 encoded string
|
||||
`src` points to the source buffer.
|
||||
`src_len` is the length of the source buffer
|
||||
`dest` points to the destination array, it can be null if `dest_len` is `0`
|
||||
`dest_len` is the length in bytes of the destination array. A null
|
||||
terminator is stored at the end of the array unless `dest_len` is `0`.
|
||||
*/
|
||||
size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len)
|
||||
{
|
||||
size_t i, j;
|
||||
uint32_t c;
|
||||
|
||||
for (i = j = 0; i < src_len; i++) {
|
||||
c = src[i];
|
||||
if (c < 0x80) {
|
||||
if (j + 1 >= dest_len)
|
||||
goto overflow;
|
||||
dest[j++] = c;
|
||||
} else {
|
||||
if (j + 2 >= dest_len)
|
||||
goto overflow;
|
||||
dest[j++] = (c >> 6) | 0xC0;
|
||||
dest[j++] = (c & 0x3F) | 0x80;
|
||||
}
|
||||
}
|
||||
if (j < dest_len)
|
||||
dest[j] = '\0';
|
||||
return j;
|
||||
|
||||
overflow:
|
||||
if (j < dest_len)
|
||||
dest[j] = '\0';
|
||||
while (i < src_len)
|
||||
j += 1 + (src[i++] >= 0x80);
|
||||
return j;
|
||||
}
|
||||
|
||||
/* Encode a buffer of 16-bit code points as a UTF-8 encoded string
|
||||
`src` points to the source buffer.
|
||||
`src_len` is the length of the source buffer
|
||||
`dest` points to the destination array, it can be null if `dest_len` is `0`
|
||||
`dest_len` is the length in bytes of the destination array. A null
|
||||
terminator is stored at the end of the array unless `dest_len` is `0`.
|
||||
*/
|
||||
size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len)
|
||||
{
|
||||
size_t i, j;
|
||||
uint32_t c;
|
||||
|
||||
for (i = j = 0; i < src_len;) {
|
||||
c = src[i++];
|
||||
if (c < 0x80) {
|
||||
if (j + 1 >= dest_len)
|
||||
goto overflow;
|
||||
dest[j++] = c;
|
||||
} else {
|
||||
if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i]))
|
||||
c = from_surrogate(c, src[i++]);
|
||||
if (j + utf8_encode_len(c) >= dest_len)
|
||||
goto overflow;
|
||||
j += utf8_encode((uint8_t *)dest + j, c);
|
||||
}
|
||||
}
|
||||
if (j < dest_len)
|
||||
dest[j] = '\0';
|
||||
return j;
|
||||
|
||||
overflow:
|
||||
i -= 1 + (c > 0xFFFF);
|
||||
if (j < dest_len)
|
||||
dest[j] = '\0';
|
||||
while (i < src_len) {
|
||||
c = src[i++];
|
||||
if (c < 0x80) {
|
||||
j++;
|
||||
} else {
|
||||
if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i]))
|
||||
c = from_surrogate(c, src[i++]);
|
||||
j += utf8_encode_len(c);
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/*--- integer to string conversions --*/
|
||||
|
@ -329,6 +590,9 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
|
|||
/* 2 <= base <= 36 */
|
||||
char const digits36[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
#define USE_SPECIAL_RADIX_10 1 // special case base 10 radix conversions
|
||||
#define USE_SINGLE_CASE_FAST 1 // special case single digit numbers
|
||||
|
||||
/* using u32toa_shift variant */
|
||||
|
||||
#define gen_digit(buf, c) if (is_be()) \
|
||||
|
@ -367,11 +631,13 @@ size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len)
|
|||
|
||||
size_t u32toa(char buf[minimum_length(11)], uint32_t n)
|
||||
{
|
||||
#ifdef USE_SINGLE_CASE_FAST /* 10% */
|
||||
if (n < 10) {
|
||||
buf[0] = (char)('0' + n);
|
||||
buf[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#define TEN_POW_7 10000000
|
||||
if (n >= TEN_POW_7) {
|
||||
uint32_t quo = n / TEN_POW_7;
|
||||
|
@ -433,6 +699,8 @@ static uint8_t const radix_shift[64] = {
|
|||
|
||||
size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
|
||||
{
|
||||
int shift;
|
||||
|
||||
#ifdef USE_SPECIAL_RADIX_10
|
||||
if (likely(base == 10))
|
||||
return u32toa(buf, n);
|
||||
|
@ -442,13 +710,13 @@ size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
|
|||
buf[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
int shift = radix_shift[base & 63];
|
||||
shift = radix_shift[base & 63];
|
||||
if (shift) {
|
||||
uint32_t mask = (1 << shift) - 1;
|
||||
size_t len = (32 - clz32(n) + shift - 1) / shift;
|
||||
size_t last = n & mask;
|
||||
n /= base;
|
||||
char *end = buf + len;
|
||||
n >>= shift;
|
||||
*end-- = '\0';
|
||||
*end-- = digits36[last];
|
||||
while (n >= base) {
|
||||
|
@ -482,11 +750,13 @@ size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
|
|||
|
||||
size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
|
||||
{
|
||||
int shift;
|
||||
|
||||
#ifdef USE_SPECIAL_RADIX_10
|
||||
if (likely(base == 10))
|
||||
return u64toa(buf, n);
|
||||
#endif
|
||||
int shift = radix_shift[base & 63];
|
||||
shift = radix_shift[base & 63];
|
||||
if (shift) {
|
||||
if (n < base) {
|
||||
buf[0] = digits36[n];
|
||||
|
@ -496,8 +766,8 @@ size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
|
|||
uint64_t mask = (1 << shift) - 1;
|
||||
size_t len = (64 - clz64(n) + shift - 1) / shift;
|
||||
size_t last = n & mask;
|
||||
n /= base;
|
||||
char *end = buf + len;
|
||||
n >>= shift;
|
||||
*end-- = '\0';
|
||||
*end-- = digits36[last];
|
||||
while (n >= base) {
|
||||
|
@ -531,6 +801,15 @@ size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
|
|||
}
|
||||
}
|
||||
|
||||
size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned int base)
|
||||
{
|
||||
if (likely(n >= 0))
|
||||
return u32toa_radix(buf, n, base);
|
||||
|
||||
buf[0] = '-';
|
||||
return 1 + u32toa_radix(buf + 1, -(uint32_t)n, base);
|
||||
}
|
||||
|
||||
size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base)
|
||||
{
|
||||
if (likely(n >= 0))
|
||||
|
@ -540,6 +819,11 @@ size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base)
|
|||
return 1 + u64toa_radix(buf + 1, -(uint64_t)n, base);
|
||||
}
|
||||
|
||||
#undef gen_digit
|
||||
#undef TEN_POW_7
|
||||
#undef USE_SPECIAL_RADIX_10
|
||||
#undef USE_SINGLE_CASE_FAST
|
||||
|
||||
/*---- sorting with opaque argument ----*/
|
||||
|
||||
typedef void (*exchange_f)(void *a, void *b, size_t size);
|
||||
|
|
23
cutils.h
23
cutils.h
|
@ -387,10 +387,26 @@ static inline void dbuf_set_error(DynBuf *s)
|
|||
s->error = TRUE;
|
||||
}
|
||||
|
||||
#define UTF8_CHAR_LEN_MAX 6
|
||||
/*---- UTF-8 and UTF-16 handling ----*/
|
||||
|
||||
int unicode_to_utf8(uint8_t *buf, unsigned int c);
|
||||
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
|
||||
#define UTF8_CHAR_LEN_MAX 4
|
||||
|
||||
enum {
|
||||
UTF8_PLAIN_ASCII = 0, // 7-bit ASCII plain text
|
||||
UTF8_NON_ASCII = 1, // has non ASCII code points (8-bit or more)
|
||||
UTF8_HAS_16BIT = 2, // has 16-bit code points
|
||||
UTF8_HAS_NON_BMP1 = 4, // has non-BMP1 code points, needs UTF-16 surrogate pairs
|
||||
UTF8_HAS_ERRORS = 8, // has encoding errors
|
||||
};
|
||||
int utf8_scan(const char *buf, size_t len, size_t *plen);
|
||||
size_t utf8_encode_len(uint32_t c);
|
||||
size_t utf8_encode(uint8_t *buf, uint32_t c);
|
||||
uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp);
|
||||
uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp);
|
||||
size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len);
|
||||
size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len);
|
||||
size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len);
|
||||
size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len);
|
||||
|
||||
static inline BOOL is_surrogate(uint32_t c)
|
||||
{
|
||||
|
@ -448,6 +464,7 @@ size_t i32toa(char buf[minimum_length(12)], int32_t n);
|
|||
size_t u64toa(char buf[minimum_length(21)], uint64_t n);
|
||||
size_t i64toa(char buf[minimum_length(22)], int64_t n);
|
||||
size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned int base);
|
||||
size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned base);
|
||||
size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned int base);
|
||||
size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base);
|
||||
|
||||
|
|
|
@ -330,6 +330,11 @@ optional properties:
|
|||
@item backtrace_barrier
|
||||
Boolean (default = false). If true, error backtraces do not list the
|
||||
stack frames below the evalScript.
|
||||
@item async
|
||||
Boolean (default = false). If true, @code{await} is accepted in the
|
||||
script and a promise is returned. The promise is resolved with an
|
||||
object whose @code{value} property holds the value returned by the
|
||||
script.
|
||||
@end table
|
||||
|
||||
@item loadScript(filename)
|
||||
|
@ -717,6 +722,12 @@ write_fd]} or null in case of error.
|
|||
@item sleep(delay_ms)
|
||||
Sleep during @code{delay_ms} milliseconds.
|
||||
|
||||
@item sleepAsync(delay_ms)
|
||||
Asynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example:
|
||||
@example
|
||||
await os.sleepAsync(500);
|
||||
@end example
|
||||
|
||||
@item setTimeout(func, delay)
|
||||
Call the function @code{func} after @code{delay} ms. Return a handle
|
||||
to the timer.
|
||||
|
|
|
@ -2,53 +2,53 @@
|
|||
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
const uint32_t qjsc_fib_module_size = 310;
|
||||
const uint32_t qjsc_fib_module_size = 311;
|
||||
|
||||
const uint8_t qjsc_fib_module[310] = {
|
||||
const uint8_t qjsc_fib_module[311] = {
|
||||
0x0c, 0x03, 0x2c, 0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x62, 0x5f,
|
||||
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x6a,
|
||||
0x73, 0x06, 0x66, 0x69, 0x62, 0x02, 0x6e, 0x0d,
|
||||
0xb2, 0x03, 0x00, 0x01, 0x00, 0x00, 0xb4, 0x03,
|
||||
0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e, 0x01,
|
||||
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x00,
|
||||
0xb4, 0x03, 0x00, 0x01, 0x0c, 0x43, 0xfa, 0x01,
|
||||
0xb4, 0x03, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00,
|
||||
0x1a, 0x01, 0xb6, 0x03, 0x00, 0x01, 0x00, 0xb4,
|
||||
0x03, 0x00, 0x00, 0xd0, 0xb3, 0xa7, 0xe9, 0x03,
|
||||
0xb3, 0x28, 0xd0, 0xb4, 0xac, 0xe9, 0x03, 0xb4,
|
||||
0x28, 0xdc, 0xd0, 0xb4, 0x9e, 0xee, 0xdc, 0xd0,
|
||||
0xb5, 0x9e, 0xee, 0x9d, 0x28, 0xb2, 0x03, 0x02,
|
||||
0x08, 0x20, 0x04, 0x00, 0x07, 0x06, 0x07, 0x06,
|
||||
0x12, 0x09, 0x08, 0x07, 0x07, 0x10, 0x07, 0x06,
|
||||
0x07, 0x06, 0x12, 0x13, 0x08, 0x07, 0x08, 0x16,
|
||||
0x0c, 0x0c, 0x07, 0x04, 0x0c, 0x0a, 0x0c, 0x0c,
|
||||
0x07, 0x04, 0x8d, 0x01, 0x66, 0x75, 0x6e, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x69, 0x62,
|
||||
0x28, 0x6e, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20,
|
||||
0x3c, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20,
|
||||
0x00, 0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09,
|
||||
0x00, 0xb4, 0x03, 0x00, 0x01, 0x0c, 0x43, 0xfa,
|
||||
0x01, 0xb4, 0x03, 0x01, 0x00, 0x01, 0x04, 0x01,
|
||||
0x00, 0x1a, 0x01, 0xb6, 0x03, 0x00, 0x01, 0x00,
|
||||
0xb4, 0x03, 0x00, 0x00, 0xd0, 0xb3, 0xa7, 0xe9,
|
||||
0x03, 0xb3, 0x28, 0xd0, 0xb4, 0xac, 0xe9, 0x03,
|
||||
0xb4, 0x28, 0xdc, 0xd0, 0xb4, 0x9e, 0xee, 0xdc,
|
||||
0xd0, 0xb5, 0x9e, 0xee, 0x9d, 0x28, 0xb2, 0x03,
|
||||
0x02, 0x08, 0x20, 0x04, 0x00, 0x07, 0x06, 0x07,
|
||||
0x06, 0x12, 0x09, 0x08, 0x07, 0x07, 0x10, 0x07,
|
||||
0x06, 0x07, 0x06, 0x12, 0x13, 0x08, 0x07, 0x08,
|
||||
0x16, 0x0c, 0x0c, 0x07, 0x04, 0x0c, 0x0a, 0x0c,
|
||||
0x0c, 0x07, 0x04, 0x8d, 0x01, 0x66, 0x75, 0x6e,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x69,
|
||||
0x62, 0x28, 0x6e, 0x29, 0x0a, 0x7b, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e,
|
||||
0x20, 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
|
||||
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73,
|
||||
0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20,
|
||||
0x3d, 0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
|
||||
0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b, 0x0a,
|
||||
0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65,
|
||||
0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20, 0x3d,
|
||||
0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
|
||||
0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66,
|
||||
0x69, 0x62, 0x28, 0x6e, 0x20, 0x2d, 0x20, 0x31,
|
||||
0x29, 0x20, 0x2b, 0x20, 0x66, 0x69, 0x62, 0x28,
|
||||
0x6e, 0x20, 0x2d, 0x20, 0x32, 0x29, 0x3b, 0x0a,
|
||||
0x7d, 0x08, 0xe9, 0x05, 0xbe, 0x00, 0xe0, 0x29,
|
||||
0x06, 0x2e, 0xb2, 0x03, 0x01, 0x01, 0x06, 0x01,
|
||||
0x01, 0x00, 0x07, 0x14, 0x02, 0x00,
|
||||
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
|
||||
0x66, 0x69, 0x62, 0x28, 0x6e, 0x20, 0x2d, 0x20,
|
||||
0x31, 0x29, 0x20, 0x2b, 0x20, 0x66, 0x69, 0x62,
|
||||
0x28, 0x6e, 0x20, 0x2d, 0x20, 0x32, 0x29, 0x3b,
|
||||
0x0a, 0x7d, 0x08, 0xe9, 0x05, 0xbe, 0x00, 0xe0,
|
||||
0x29, 0x06, 0x2e, 0xb2, 0x03, 0x01, 0x01, 0x06,
|
||||
0x01, 0x01, 0x00, 0x07, 0x14, 0x02, 0x00,
|
||||
};
|
||||
|
||||
const uint32_t qjsc_hello_module_size = 177;
|
||||
const uint32_t qjsc_hello_module_size = 178;
|
||||
|
||||
const uint8_t qjsc_hello_module[177] = {
|
||||
const uint8_t qjsc_hello_module[178] = {
|
||||
0x0c, 0x07, 0x30, 0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
|
||||
0x6f, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
|
||||
|
@ -60,18 +60,18 @@ const uint8_t qjsc_hello_module[177] = {
|
|||
0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x10,
|
||||
0x66, 0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d,
|
||||
0x0d, 0xb2, 0x03, 0x01, 0xb4, 0x03, 0x00, 0x00,
|
||||
0x01, 0x00, 0xb6, 0x03, 0x00, 0x0c, 0x20, 0xfa,
|
||||
0x01, 0x9e, 0x01, 0x00, 0x00, 0x00, 0x05, 0x01,
|
||||
0x00, 0x32, 0x00, 0xb6, 0x03, 0x00, 0x0c, 0x08,
|
||||
0xe9, 0x02, 0x29, 0x38, 0xdc, 0x00, 0x00, 0x00,
|
||||
0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xde, 0x00,
|
||||
0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x38, 0xdc,
|
||||
0x00, 0x00, 0x00, 0x42, 0xdd, 0x00, 0x00, 0x00,
|
||||
0x04, 0xdf, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00,
|
||||
0xbb, 0x0a, 0xee, 0x24, 0x02, 0x00, 0x0e, 0x06,
|
||||
0x2e, 0xb2, 0x03, 0x01, 0x01, 0x0a, 0x01, 0x01,
|
||||
0x00, 0x04, 0x0a, 0x02, 0x62, 0x00, 0x4d, 0x30,
|
||||
0x00,
|
||||
0x01, 0x00, 0xb6, 0x03, 0x00, 0x00, 0x0c, 0x20,
|
||||
0xfa, 0x01, 0x9e, 0x01, 0x00, 0x00, 0x00, 0x05,
|
||||
0x01, 0x00, 0x32, 0x00, 0xb6, 0x03, 0x00, 0x0c,
|
||||
0x08, 0xe9, 0x02, 0x29, 0x38, 0xdc, 0x00, 0x00,
|
||||
0x00, 0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xde,
|
||||
0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x38,
|
||||
0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd, 0x00, 0x00,
|
||||
0x00, 0x04, 0xdf, 0x00, 0x00, 0x00, 0x65, 0x00,
|
||||
0x00, 0xbb, 0x0a, 0xee, 0x24, 0x02, 0x00, 0x0e,
|
||||
0x06, 0x2e, 0xb2, 0x03, 0x01, 0x01, 0x0a, 0x01,
|
||||
0x01, 0x00, 0x04, 0x0a, 0x02, 0x62, 0x00, 0x4d,
|
||||
0x30, 0x00,
|
||||
};
|
||||
|
||||
static JSContext *JS_NewCustomContext(JSRuntime *rt)
|
||||
|
|
5132
gen/repl.c
5132
gen/repl.c
File diff suppressed because it is too large
Load diff
|
@ -2,9 +2,9 @@
|
|||
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
const uint32_t qjsc_test_fib_size = 166;
|
||||
const uint32_t qjsc_test_fib_size = 167;
|
||||
|
||||
const uint8_t qjsc_test_fib[166] = {
|
||||
const uint8_t qjsc_test_fib[167] = {
|
||||
0x0c, 0x07, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74,
|
||||
0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 0x10,
|
||||
|
@ -15,17 +15,17 @@ const uint8_t qjsc_test_fib[166] = {
|
|||
0x6f, 0x72, 0x6c, 0x64, 0x10, 0x66, 0x69, 0x62,
|
||||
0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, 0xb2, 0x03,
|
||||
0x01, 0xb4, 0x03, 0x00, 0x00, 0x01, 0x00, 0xb6,
|
||||
0x03, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e, 0x01,
|
||||
0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x32, 0x00,
|
||||
0xb6, 0x03, 0x00, 0x0c, 0x08, 0xe9, 0x02, 0x29,
|
||||
0x38, 0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd, 0x00,
|
||||
0x00, 0x00, 0x04, 0xde, 0x00, 0x00, 0x00, 0x24,
|
||||
0x01, 0x00, 0x0e, 0x38, 0xdc, 0x00, 0x00, 0x00,
|
||||
0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x00,
|
||||
0x00, 0x00, 0x65, 0x00, 0x00, 0xbb, 0x0a, 0xee,
|
||||
0x24, 0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb2, 0x03,
|
||||
0x01, 0x01, 0x0a, 0x01, 0x01, 0x00, 0x04, 0x0a,
|
||||
0x02, 0x62, 0x00, 0x4d, 0x30, 0x00,
|
||||
0x03, 0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e,
|
||||
0x01, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x32,
|
||||
0x00, 0xb6, 0x03, 0x00, 0x0c, 0x08, 0xe9, 0x02,
|
||||
0x29, 0x38, 0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd,
|
||||
0x00, 0x00, 0x00, 0x04, 0xde, 0x00, 0x00, 0x00,
|
||||
0x24, 0x01, 0x00, 0x0e, 0x38, 0xdc, 0x00, 0x00,
|
||||
0x00, 0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xdf,
|
||||
0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0xbb, 0x0a,
|
||||
0xee, 0x24, 0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb2,
|
||||
0x03, 0x01, 0x01, 0x0a, 0x01, 0x01, 0x00, 0x04,
|
||||
0x0a, 0x02, 0x62, 0x00, 0x4d, 0x30, 0x00,
|
||||
};
|
||||
|
||||
static JSContext *JS_NewCustomContext(JSRuntime *rt)
|
||||
|
|
46
libregexp.c
46
libregexp.c
|
@ -712,7 +712,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
|||
static int get_class_atom(REParseState *s, CharRange *cr,
|
||||
const uint8_t **pp, BOOL inclass)
|
||||
{
|
||||
const uint8_t *p;
|
||||
const uint8_t *p, *p_next;
|
||||
uint32_t c;
|
||||
int ret;
|
||||
|
||||
|
@ -804,15 +804,18 @@ static int get_class_atom(REParseState *s, CharRange *cr,
|
|||
/* fall thru */
|
||||
default:
|
||||
normal_char:
|
||||
/* normal char */
|
||||
if (c >= 128) {
|
||||
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
|
||||
if ((unsigned)c > 0xffff && !s->is_unicode) {
|
||||
/* XXX: should handle non BMP-1 code points */
|
||||
p++;
|
||||
if (c >= 0x80) {
|
||||
c = utf8_decode(p - 1, &p_next);
|
||||
if (p_next == p)
|
||||
return re_parse_error(s, "invalid UTF-8 sequence");
|
||||
p = p_next;
|
||||
if (c > 0xFFFF && !s->is_unicode) {
|
||||
// TODO(chqrlie): should handle non BMP-1 code points in
|
||||
// the calling function and no require the source string
|
||||
// to be CESU-8 encoded if not s->is_unicode
|
||||
return re_parse_error(s, "malformed unicode char");
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1105,35 +1108,35 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len)
|
|||
/* '*pp' is the first char after '<' */
|
||||
static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)
|
||||
{
|
||||
const uint8_t *p, *p1;
|
||||
const uint8_t *p, *p_next;
|
||||
uint32_t c, d;
|
||||
char *q;
|
||||
|
||||
p = *pp;
|
||||
q = buf;
|
||||
for(;;) {
|
||||
c = *p;
|
||||
c = *p++;
|
||||
if (c == '\\') {
|
||||
p++;
|
||||
if (*p != 'u')
|
||||
return -1;
|
||||
c = lre_parse_escape(&p, 2); // accept surrogate pairs
|
||||
if ((int)c < 0)
|
||||
return -1;
|
||||
} else if (c == '>') {
|
||||
break;
|
||||
} else if (c >= 128) {
|
||||
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
|
||||
} else if (c >= 0x80) {
|
||||
c = utf8_decode(p - 1, &p_next);
|
||||
if (p_next == p)
|
||||
return -1;
|
||||
p = p_next;
|
||||
if (is_hi_surrogate(c)) {
|
||||
d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
|
||||
d = utf8_decode(p, &p_next);
|
||||
if (is_lo_surrogate(d)) {
|
||||
c = from_surrogate(c, d);
|
||||
p = p1;
|
||||
p = p_next;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
if (c > 0x10FFFF)
|
||||
return -1;
|
||||
if (q == buf) {
|
||||
if (!lre_js_is_ident_first(c))
|
||||
return -1;
|
||||
|
@ -1143,16 +1146,15 @@ static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)
|
|||
}
|
||||
if ((q - buf + UTF8_CHAR_LEN_MAX + 1) > buf_size)
|
||||
return -1;
|
||||
if (c < 128) {
|
||||
if (c < 0x80) {
|
||||
*q++ = c;
|
||||
} else {
|
||||
q += unicode_to_utf8((uint8_t*)q, c);
|
||||
q += utf8_encode((uint8_t*)q, c);
|
||||
}
|
||||
}
|
||||
if (q == buf)
|
||||
return -1;
|
||||
*q = '\0';
|
||||
p++;
|
||||
*pp = p;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ int lre_exec(uint8_t **capture,
|
|||
int lre_parse_escape(const uint8_t **pp, int allow_utf16);
|
||||
LRE_BOOL lre_is_space(int c);
|
||||
|
||||
void lre_byte_swap(uint8_t *buf, size_t len, BOOL is_byte_swapped);
|
||||
void lre_byte_swap(uint8_t *buf, size_t len, LRE_BOOL is_byte_swapped);
|
||||
|
||||
/* must be provided by the user */
|
||||
LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#ifndef LIBUNICODE_H
|
||||
#define LIBUNICODE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LRE_BOOL int /* for documentation purposes */
|
||||
|
|
1
qjs.c
1
qjs.c
|
@ -58,6 +58,7 @@ static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
|
|||
js_module_set_import_meta(ctx, val, TRUE, TRUE);
|
||||
val = JS_EvalFunction(ctx, val);
|
||||
}
|
||||
val = js_std_await(ctx, val);
|
||||
} else {
|
||||
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
||||
}
|
||||
|
|
|
@ -272,20 +272,21 @@ static JSValue js_printf_internal(JSContext *ctx,
|
|||
if (i >= argc)
|
||||
goto missing;
|
||||
if (JS_IsString(argv[i])) {
|
||||
// TODO(chqrlie) need an API to wrap charCodeAt and codePointAt */
|
||||
string_arg = JS_ToCString(ctx, argv[i++]);
|
||||
if (!string_arg)
|
||||
goto fail;
|
||||
int32_arg = unicode_from_utf8((const uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);
|
||||
int32_arg = utf8_decode((const uint8_t *)string_arg, &p);
|
||||
JS_FreeCString(ctx, string_arg);
|
||||
} else {
|
||||
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
||||
goto fail;
|
||||
}
|
||||
/* handle utf-8 encoding explicitly */
|
||||
// XXX: throw an exception?
|
||||
if ((unsigned)int32_arg > 0x10FFFF)
|
||||
int32_arg = 0xFFFD;
|
||||
/* ignore conversion flags, width and precision */
|
||||
len = unicode_to_utf8(cbuf, int32_arg);
|
||||
len = utf8_encode(cbuf, int32_arg);
|
||||
dbuf_put(&dbuf, cbuf, len);
|
||||
break;
|
||||
|
||||
|
@ -777,6 +778,7 @@ static JSValue js_evalScript(JSContext *ctx, JSValue this_val,
|
|||
JSValue ret;
|
||||
JSValue options_obj;
|
||||
BOOL backtrace_barrier = FALSE;
|
||||
BOOL is_async = FALSE;
|
||||
int flags;
|
||||
|
||||
if (argc >= 2) {
|
||||
|
@ -784,6 +786,9 @@ static JSValue js_evalScript(JSContext *ctx, JSValue this_val,
|
|||
if (get_bool_option(ctx, &backtrace_barrier, options_obj,
|
||||
"backtrace_barrier"))
|
||||
return JS_EXCEPTION;
|
||||
if (get_bool_option(ctx, &is_async, options_obj,
|
||||
"async"))
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
str = JS_ToCStringLen(ctx, &len, argv[0]);
|
||||
|
@ -796,6 +801,8 @@ static JSValue js_evalScript(JSContext *ctx, JSValue this_val,
|
|||
flags = JS_EVAL_TYPE_GLOBAL;
|
||||
if (backtrace_barrier)
|
||||
flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
|
||||
if (is_async)
|
||||
flags |= JS_EVAL_FLAG_ASYNC;
|
||||
ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
|
||||
JS_FreeCString(ctx, str);
|
||||
if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
|
||||
|
@ -2113,6 +2120,38 @@ static JSClassDef js_os_timer_class = {
|
|||
.gc_mark = js_os_timer_mark,
|
||||
};
|
||||
|
||||
/* return a promise */
|
||||
static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSRuntime *rt = JS_GetRuntime(ctx);
|
||||
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
|
||||
int64_t delay;
|
||||
JSOSTimer *th;
|
||||
JSValue promise, resolving_funcs[2];
|
||||
|
||||
if (JS_ToInt64(ctx, &delay, argv[0]))
|
||||
return JS_EXCEPTION;
|
||||
promise = JS_NewPromiseCapability(ctx, resolving_funcs);
|
||||
if (JS_IsException(promise))
|
||||
return JS_EXCEPTION;
|
||||
|
||||
th = js_mallocz(ctx, sizeof(*th));
|
||||
if (!th) {
|
||||
JS_FreeValue(ctx, promise);
|
||||
JS_FreeValue(ctx, resolving_funcs[0]);
|
||||
JS_FreeValue(ctx, resolving_funcs[1]);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
th->has_object = FALSE;
|
||||
th->timeout = js__hrtime_ms() + delay;
|
||||
th->func = JS_DupValue(ctx, resolving_funcs[0]);
|
||||
list_add_tail(&th->link, &ts->os_timers);
|
||||
JS_FreeValue(ctx, resolving_funcs[0]);
|
||||
JS_FreeValue(ctx, resolving_funcs[1]);
|
||||
return promise;
|
||||
}
|
||||
|
||||
static void call_handler(JSContext *ctx, JSValue func)
|
||||
{
|
||||
JSValue ret, func1;
|
||||
|
@ -3328,6 +3367,7 @@ static void *worker_func(void *opaque)
|
|||
JSRuntime *rt;
|
||||
JSThreadState *ts;
|
||||
JSContext *ctx;
|
||||
JSValue val;
|
||||
|
||||
rt = JS_NewRuntime();
|
||||
if (rt == NULL) {
|
||||
|
@ -3354,11 +3394,14 @@ static void *worker_func(void *opaque)
|
|||
|
||||
js_std_add_helpers(ctx, -1, NULL);
|
||||
|
||||
if (!JS_RunModule(ctx, args->basename, args->filename))
|
||||
js_std_dump_error(ctx);
|
||||
val = JS_LoadModule(ctx, args->basename, args->filename);
|
||||
free(args->filename);
|
||||
free(args->basename);
|
||||
free(args);
|
||||
val = js_std_await(ctx, val);
|
||||
if (JS_IsException(val))
|
||||
js_std_dump_error(ctx);
|
||||
JS_FreeValue(ctx, val);
|
||||
|
||||
js_std_loop(ctx);
|
||||
|
||||
|
@ -3701,6 +3744,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||
// per spec: both functions can cancel timeouts and intervals
|
||||
JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
|
||||
JS_CFUNC_DEF("clearInterval", 1, js_os_clearTimeout ),
|
||||
JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ),
|
||||
JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
|
||||
JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
|
||||
JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
|
||||
|
@ -3979,6 +4023,42 @@ void js_std_loop(JSContext *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
/* Wait for a promise and execute pending jobs while waiting for
|
||||
it. Return the promise result or JS_EXCEPTION in case of promise
|
||||
rejection. */
|
||||
JSValue js_std_await(JSContext *ctx, JSValue obj)
|
||||
{
|
||||
JSValue ret;
|
||||
int state;
|
||||
|
||||
for(;;) {
|
||||
state = JS_PromiseState(ctx, obj);
|
||||
if (state == JS_PROMISE_FULFILLED) {
|
||||
ret = JS_PromiseResult(ctx, obj);
|
||||
JS_FreeValue(ctx, obj);
|
||||
break;
|
||||
} else if (state == JS_PROMISE_REJECTED) {
|
||||
ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));
|
||||
JS_FreeValue(ctx, obj);
|
||||
break;
|
||||
} else if (state == JS_PROMISE_PENDING) {
|
||||
JSContext *ctx1;
|
||||
int err;
|
||||
err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
||||
if (err < 0) {
|
||||
js_std_dump_error(ctx1);
|
||||
}
|
||||
if (os_poll_func)
|
||||
os_poll_func(ctx);
|
||||
} else {
|
||||
/* not a promise */
|
||||
ret = obj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
||||
int load_only)
|
||||
{
|
||||
|
@ -3997,8 +4077,11 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
|||
goto exception;
|
||||
}
|
||||
js_module_set_import_meta(ctx, obj, FALSE, TRUE);
|
||||
val = JS_EvalFunction(ctx, obj);
|
||||
val = js_std_await(ctx, val);
|
||||
} else {
|
||||
val = JS_EvalFunction(ctx, obj);
|
||||
}
|
||||
val = JS_EvalFunction(ctx, obj);
|
||||
if (JS_IsException(val)) {
|
||||
exception:
|
||||
js_std_dump_error(ctx);
|
||||
|
|
|
@ -37,6 +37,7 @@ JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
|
|||
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
|
||||
void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
|
||||
void js_std_loop(JSContext *ctx);
|
||||
JSValue js_std_await(JSContext *ctx, JSValue obj);
|
||||
void js_std_init_handlers(JSRuntime *rt);
|
||||
void js_std_free_handlers(JSRuntime *rt);
|
||||
void js_std_dump_error(JSContext *ctx);
|
||||
|
|
79
quickjs.h
79
quickjs.h
|
@ -30,6 +30,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -182,7 +183,7 @@ typedef struct JSValue {
|
|||
|
||||
#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
|
||||
|
||||
#define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 }
|
||||
#define JS_NAN (JSValue){ (JSValueUnion){ .float64 = JS_FLOAT64_NAN }, JS_TAG_FLOAT64 }
|
||||
|
||||
static inline JSValue __JS_NewFloat64(double d)
|
||||
{
|
||||
|
@ -274,6 +275,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
|||
#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
|
||||
/* don't include the stack frames before this eval in the Error() backtraces */
|
||||
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
|
||||
/* allow top-level await in normal script. JS_Eval() returns a
|
||||
promise. Only allowed with JS_EVAL_TYPE_GLOBAL */
|
||||
#define JS_EVAL_FLAG_ASYNC (1 << 7)
|
||||
|
||||
typedef JSValue JSCFunction(JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic);
|
||||
|
@ -301,6 +305,7 @@ JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
|
|||
/* use 0 to disable memory limit */
|
||||
JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
|
||||
JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags);
|
||||
JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt);
|
||||
JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
|
||||
JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt);
|
||||
JS_EXTERN void JS_SetGCThresholdFixed(JSRuntime *rt, JS_BOOL fixed);
|
||||
|
@ -505,9 +510,9 @@ static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val)
|
|||
{
|
||||
JSValue v;
|
||||
if (val >= INT32_MIN && val <= INT32_MAX) {
|
||||
v = JS_NewInt32(ctx, val);
|
||||
v = JS_NewInt32(ctx, (int32_t)val);
|
||||
} else {
|
||||
v = JS_NewFloat64(ctx, val);
|
||||
v = JS_NewFloat64(ctx, (double)val);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
@ -516,9 +521,9 @@ static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
|
|||
{
|
||||
JSValue v;
|
||||
if (val <= 0x7fffffff) {
|
||||
v = JS_NewInt32(ctx, val);
|
||||
v = JS_NewInt32(ctx, (int32_t)val);
|
||||
} else {
|
||||
v = JS_NewFloat64(ctx, val);
|
||||
v = JS_NewFloat64(ctx, (double)val);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
@ -584,6 +589,7 @@ JS_EXTERN JSValue JS_GetException(JSContext *ctx);
|
|||
JS_EXTERN JS_BOOL JS_IsError(JSContext *ctx, JSValue val);
|
||||
JS_EXTERN void JS_ResetUncatchableError(JSContext *ctx);
|
||||
JS_EXTERN JSValue JS_NewError(JSContext *ctx);
|
||||
JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowPlainError(JSContext *ctx, const char *fmt, ...);
|
||||
JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);
|
||||
JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...);
|
||||
JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...);
|
||||
|
@ -641,6 +647,7 @@ JS_EXTERN int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValue val);
|
|||
JS_EXTERN int JS_ToFloat64(JSContext *ctx, double *pres, JSValue val);
|
||||
/* return an exception if 'val' is a Number */
|
||||
JS_EXTERN int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValue val);
|
||||
JS_EXTERN int JS_ToBigUint64(JSContext *ctx, uint64_t *pres, JSValue val);
|
||||
/* same as JS_ToInt64() but allow BigInt */
|
||||
JS_EXTERN int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValue val);
|
||||
|
||||
|
@ -698,6 +705,7 @@ JS_EXTERN int JS_PreventExtensions(JSContext *ctx, JSValue obj);
|
|||
JS_EXTERN int JS_DeleteProperty(JSContext *ctx, JSValue obj, JSAtom prop, int flags);
|
||||
JS_EXTERN int JS_SetPrototype(JSContext *ctx, JSValue obj, JSValue proto_val);
|
||||
JS_EXTERN JSValue JS_GetPrototype(JSContext *ctx, JSValue val);
|
||||
JS_EXTERN int JS_GetLength(JSContext *ctx, JSValue obj, int64_t *pres);
|
||||
|
||||
#define JS_GPN_STRING_MASK (1 << 0)
|
||||
#define JS_GPN_SYMBOL_MASK (1 << 1)
|
||||
|
@ -711,6 +719,8 @@ JS_EXTERN int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
|
|||
uint32_t *plen, JSValue obj, int flags);
|
||||
JS_EXTERN int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
|
||||
JSValue obj, JSAtom prop);
|
||||
JS_EXTERN void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab,
|
||||
uint32_t len);
|
||||
|
||||
JS_EXTERN JSValue JS_Call(JSContext *ctx, JSValue func_obj, JSValue this_obj,
|
||||
int argc, JSValue *argv);
|
||||
|
@ -780,7 +790,15 @@ typedef struct {
|
|||
} JSSharedArrayBufferFunctions;
|
||||
JS_EXTERN void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf);
|
||||
|
||||
typedef enum JSPromiseStateEnum {
|
||||
JS_PROMISE_PENDING,
|
||||
JS_PROMISE_FULFILLED,
|
||||
JS_PROMISE_REJECTED,
|
||||
} JSPromiseStateEnum;
|
||||
|
||||
JS_EXTERN JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
|
||||
JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
|
||||
JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
|
||||
|
||||
JS_EXTERN JSValue JS_NewSymbol(JSContext *ctx, const char *description, JS_BOOL is_global);
|
||||
|
||||
|
@ -852,8 +870,8 @@ JS_EXTERN int JS_ResolveModule(JSContext *ctx, JSValue obj);
|
|||
/* only exported for os.Worker() */
|
||||
JS_EXTERN JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
|
||||
/* only exported for os.Worker() */
|
||||
JS_EXTERN JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
|
||||
const char *filename);
|
||||
JS_EXTERN JSValue JS_LoadModule(JSContext *ctx, const char *basename,
|
||||
const char *filename);
|
||||
|
||||
/* C function definition */
|
||||
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
|
||||
|
@ -956,21 +974,21 @@ typedef struct JSCFunctionListEntry {
|
|||
#define JS_DEF_ALIAS 9
|
||||
|
||||
/* Note: c++ does not like nested designators */
|
||||
#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
#define JS_CFUNC_DEF2(name, length, func1, prop_flags) { name, prop_flags, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } }
|
||||
#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } }
|
||||
#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }
|
||||
#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
|
||||
#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } }
|
||||
#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } }
|
||||
#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } }
|
||||
#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } }
|
||||
#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } }
|
||||
#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } }
|
||||
#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } }
|
||||
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } }
|
||||
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } }
|
||||
#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
#define JS_CFUNC_DEF2(name, length, func1, prop_flags) { name, prop_flags, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } }
|
||||
#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } }
|
||||
#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }
|
||||
#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
|
||||
#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } }
|
||||
#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, { .str = cstr } }
|
||||
#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, { .i32 = val } }
|
||||
#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, { .i64 = val } }
|
||||
#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, { .f64 = val } }
|
||||
#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, { .i32 = 0 } }
|
||||
#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, { .prop_list = { tab, len } } }
|
||||
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, -1 } } }
|
||||
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, base } } }
|
||||
|
||||
JS_EXTERN void JS_SetPropertyFunctionList(JSContext *ctx, JSValue obj,
|
||||
const JSCFunctionListEntry *tab,
|
||||
|
@ -992,25 +1010,10 @@ JS_EXTERN int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *exp
|
|||
JS_EXTERN int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
|
||||
const JSCFunctionListEntry *tab, int len);
|
||||
|
||||
/* Promise */
|
||||
|
||||
#define JS_INVALID_PROMISE_STATE (-1)
|
||||
|
||||
typedef enum JSPromiseStateEnum {
|
||||
JS_PROMISE_PENDING,
|
||||
JS_PROMISE_FULFILLED,
|
||||
JS_PROMISE_REJECTED,
|
||||
} JSPromiseStateEnum;
|
||||
|
||||
/* Returns JSPromiseReactionEnum for the promise or JS_INVALID_PROMISE_STATE if the value is not a promise. */
|
||||
JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
|
||||
/* Return the result of the promise if the promise's state is in the FULFILLED or REJECTED state. Otherwise returns JS_UNDEFINED. */
|
||||
JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
|
||||
|
||||
/* Version */
|
||||
|
||||
#define QJS_VERSION_MAJOR 0
|
||||
#define QJS_VERSION_MINOR 5
|
||||
#define QJS_VERSION_MINOR 6
|
||||
#define QJS_VERSION_PATCH 0
|
||||
#define QJS_VERSION_SUFFIX "dev"
|
||||
|
||||
|
|
102
repl.js
102
repl.js
|
@ -129,6 +129,7 @@ import * as os from "os";
|
|||
var plen = 0;
|
||||
var ps1 = "qjs > ";
|
||||
var ps2 = " ... ";
|
||||
var eval_start_time;
|
||||
var eval_time = 0;
|
||||
var mexpr = "";
|
||||
var level = 0;
|
||||
|
@ -838,10 +839,8 @@ import * as os from "os";
|
|||
prompt += ps2;
|
||||
} else {
|
||||
if (show_time) {
|
||||
var t = Math.round(eval_time) + " ";
|
||||
eval_time = 0;
|
||||
t = dupstr("0", 5 - t.length) + t;
|
||||
prompt += t.substring(0, t.length - 4) + "." + t.substring(t.length - 4);
|
||||
var t = eval_time / 1000;
|
||||
prompt += t.toFixed(6) + " ";
|
||||
}
|
||||
plen = prompt.length;
|
||||
prompt += ps1;
|
||||
|
@ -1507,34 +1506,6 @@ import * as os from "os";
|
|||
"quit": () => { exit(0); },
|
||||
}, null);
|
||||
|
||||
function eval_and_print(expr) {
|
||||
var result;
|
||||
|
||||
try {
|
||||
if (use_strict)
|
||||
expr = '"use strict"; void 0;' + expr;
|
||||
var now = Date.now();
|
||||
/* eval as a script */
|
||||
result = std.evalScript(expr, { backtrace_barrier: true });
|
||||
eval_time = Date.now() - now;
|
||||
print(result);
|
||||
/* set the last result */
|
||||
g._ = result;
|
||||
} catch (error) {
|
||||
std.puts(colors[styles.error]);
|
||||
if (error instanceof Error) {
|
||||
console.log(error);
|
||||
if (error.stack) {
|
||||
std.puts(error.stack);
|
||||
}
|
||||
} else {
|
||||
std.puts("Throw: ");
|
||||
console.log(error);
|
||||
}
|
||||
std.puts(colors.none);
|
||||
}
|
||||
}
|
||||
|
||||
function cmd_start() {
|
||||
std.puts('QuickJS-ng - Type ".help" for help\n');
|
||||
cmd_readline_start();
|
||||
|
@ -1545,33 +1516,88 @@ import * as os from "os";
|
|||
}
|
||||
|
||||
function readline_handle_cmd(expr) {
|
||||
handle_cmd(expr);
|
||||
cmd_readline_start();
|
||||
if (!handle_cmd(expr)) {
|
||||
cmd_readline_start();
|
||||
}
|
||||
}
|
||||
|
||||
/* return true if async termination */
|
||||
function handle_cmd(expr) {
|
||||
if (!expr)
|
||||
return;
|
||||
return false;
|
||||
if (mexpr) {
|
||||
expr = mexpr + '\n' + expr;
|
||||
} else {
|
||||
if (handle_directive(expr))
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
var colorstate = colorize_js(expr);
|
||||
pstate = colorstate[0];
|
||||
level = colorstate[1];
|
||||
if (pstate) {
|
||||
mexpr = expr;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
mexpr = "";
|
||||
|
||||
eval_and_print(expr);
|
||||
eval_and_print_start(expr, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function eval_and_print_start(expr, is_async) {
|
||||
var result;
|
||||
|
||||
try {
|
||||
if (use_strict)
|
||||
expr = '"use strict"; void 0;' + expr;
|
||||
eval_start_time = os.now();
|
||||
/* eval as a script */
|
||||
result = std.evalScript(expr, { backtrace_barrier: true, async: is_async });
|
||||
if (is_async) {
|
||||
/* result is a promise */
|
||||
result.then(print_eval_result, print_eval_error);
|
||||
} else {
|
||||
print_eval_result({ value: result });
|
||||
}
|
||||
} catch (error) {
|
||||
print_eval_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function print_eval_result(result) {
|
||||
result = result.value;
|
||||
eval_time = os.now() - eval_start_time;
|
||||
print(result);
|
||||
/* set the last result */
|
||||
g._ = result;
|
||||
|
||||
handle_cmd_end();
|
||||
}
|
||||
|
||||
function print_eval_error(error) {
|
||||
std.puts(colors[styles.error]);
|
||||
if (error instanceof Error) {
|
||||
console.log(error);
|
||||
if (error.stack) {
|
||||
std.puts(error.stack);
|
||||
}
|
||||
} else {
|
||||
std.puts("Throw: ");
|
||||
console.log(error);
|
||||
}
|
||||
std.puts(colors.none);
|
||||
|
||||
handle_cmd_end();
|
||||
}
|
||||
|
||||
function handle_cmd_end() {
|
||||
level = 0;
|
||||
|
||||
/* run the garbage collector after each command */
|
||||
std.gc();
|
||||
|
||||
cmd_readline_start();
|
||||
}
|
||||
|
||||
function colorize_js(str) {
|
||||
|
|
|
@ -1198,7 +1198,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
|||
{
|
||||
JSValue res_val, exception_val;
|
||||
int ret, error_line, pos, pos_line;
|
||||
BOOL is_error, has_error_line;
|
||||
BOOL is_error, has_error_line, ret_promise;
|
||||
const char *error_name;
|
||||
|
||||
pos = skip_comments(buf, 1, &pos_line);
|
||||
|
@ -1207,12 +1207,19 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
|||
exception_val = JS_UNDEFINED;
|
||||
error_name = NULL;
|
||||
|
||||
/* a module evaluation returns a promise */
|
||||
ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0);
|
||||
async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */
|
||||
|
||||
res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
||||
|
||||
if (is_async && !JS_IsException(res_val)) {
|
||||
JS_FreeValue(ctx, res_val);
|
||||
if ((is_async || ret_promise) && !JS_IsException(res_val)) {
|
||||
JSValue promise = JS_UNDEFINED;
|
||||
if (ret_promise) {
|
||||
promise = res_val;
|
||||
} else {
|
||||
JS_FreeValue(ctx, res_val);
|
||||
}
|
||||
for(;;) {
|
||||
JSContext *ctx1;
|
||||
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
||||
|
@ -1220,37 +1227,26 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
|||
res_val = JS_EXCEPTION;
|
||||
break;
|
||||
} else if (ret == 0) {
|
||||
/* test if the test called $DONE() once */
|
||||
if (async_done != 1) {
|
||||
res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
|
||||
if (is_async) {
|
||||
/* test if the test called $DONE() once */
|
||||
if (async_done != 1) {
|
||||
res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
|
||||
} else {
|
||||
res_val = JS_UNDEFINED;
|
||||
}
|
||||
} else {
|
||||
res_val = JS_UNDEFINED;
|
||||
/* check that the returned promise is fulfilled */
|
||||
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
|
||||
if (state == JS_PROMISE_FULFILLED)
|
||||
res_val = JS_UNDEFINED;
|
||||
else if (state == JS_PROMISE_REJECTED)
|
||||
res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));
|
||||
else
|
||||
res_val = JS_ThrowTypeError(ctx, "promise is pending");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ((eval_flags & JS_EVAL_TYPE_MODULE) &&
|
||||
!JS_IsUndefined(res_val) &&
|
||||
!JS_IsException(res_val)) {
|
||||
JSValue promise = res_val;
|
||||
for(;;) {
|
||||
JSContext *ctx1;
|
||||
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
||||
if (ret < 0) {
|
||||
res_val = JS_EXCEPTION;
|
||||
break;
|
||||
}
|
||||
if (ret == 0) {
|
||||
JSPromiseStateEnum s = JS_PromiseState(ctx, promise);
|
||||
if (s == JS_PROMISE_FULFILLED)
|
||||
res_val = JS_UNDEFINED;
|
||||
else if (s == JS_PROMISE_REJECTED)
|
||||
res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));
|
||||
else
|
||||
res_val = JS_EXCEPTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, promise);
|
||||
}
|
||||
|
||||
|
@ -1887,17 +1883,32 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
|
|||
js_std_dump_error(ctx);
|
||||
ret_code = 1;
|
||||
} else {
|
||||
JS_FreeValue(ctx, res_val);
|
||||
JSValue promise = JS_UNDEFINED;
|
||||
if (is_module) {
|
||||
promise = res_val;
|
||||
} else {
|
||||
JS_FreeValue(ctx, res_val);
|
||||
}
|
||||
for(;;) {
|
||||
JSContext *ctx1;
|
||||
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
||||
if (ret < 0) {
|
||||
js_std_dump_error(ctx1);
|
||||
ret_code = 1;
|
||||
js_std_dump_error(ctx1);
|
||||
ret_code = 1;
|
||||
} else if (ret == 0) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* dump the error if the module returned an error. */
|
||||
if (is_module) {
|
||||
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
|
||||
if (state == JS_PROMISE_REJECTED) {
|
||||
JS_Throw(ctx, JS_PromiseResult(ctx, promise));
|
||||
js_std_dump_error(ctx);
|
||||
ret_code = 1;
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, promise);
|
||||
}
|
||||
free(buf);
|
||||
#ifdef CONFIG_AGENT
|
||||
|
|
|
@ -919,6 +919,42 @@ function float_toString(n)
|
|||
return n * 3;
|
||||
}
|
||||
|
||||
function float_toFixed(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
s = (j % 10 + 0.1).toFixed(j % 16);
|
||||
s = (j + 0.1).toFixed(j % 16);
|
||||
s = (j * 12345678 + 0.1).toFixed(j % 16);
|
||||
}
|
||||
return n * 3;
|
||||
}
|
||||
|
||||
function float_toPrecision(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
s = (j % 10 + 0.1).toPrecision(j % 16 + 1);
|
||||
s = (j + 0.1).toPrecision(j % 16 + 1);
|
||||
s = (j * 12345678 + 0.1).toPrecision(j % 16 + 1);
|
||||
}
|
||||
return n * 3;
|
||||
}
|
||||
|
||||
function float_toExponential(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
s = (j % 10 + 0.1).toExponential(j % 16);
|
||||
s = (j + 0.1).toExponential(j % 16);
|
||||
s = (j * 12345678 + 0.1).toExponential(j % 16);
|
||||
}
|
||||
return n * 3;
|
||||
}
|
||||
|
||||
function string_to_int(n)
|
||||
{
|
||||
var s, r, j;
|
||||
|
@ -1014,11 +1050,14 @@ function main(argc, argv, g)
|
|||
int_toString,
|
||||
float_to_string,
|
||||
float_toString,
|
||||
float_toFixed,
|
||||
float_toPrecision,
|
||||
float_toExponential,
|
||||
string_to_int,
|
||||
string_to_float,
|
||||
];
|
||||
var tests = [];
|
||||
var i, j, n, f, name;
|
||||
var i, j, n, f, name, found;
|
||||
|
||||
if (typeof BigInt == "function") {
|
||||
/* BigInt test */
|
||||
|
@ -1045,14 +1084,14 @@ function main(argc, argv, g)
|
|||
sort_bench.array_size = +argv[i++];
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < test_list.length; j++) {
|
||||
for (j = 0, found = false; j < test_list.length; j++) {
|
||||
f = test_list[j];
|
||||
if (name === f.name) {
|
||||
if (f.name.startsWith(name)) {
|
||||
tests.push(f);
|
||||
break;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (j == test_list.length) {
|
||||
if (!found) {
|
||||
console.log("unknown benchmark: " + name);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1080,6 +1119,9 @@ function main(argc, argv, g)
|
|||
save_result("microbench-new.txt", log_data);
|
||||
}
|
||||
|
||||
if (!scriptArgs)
|
||||
if (typeof scriptArgs === "undefined") {
|
||||
scriptArgs = [];
|
||||
if (typeof process.argv === "object")
|
||||
scriptArgs = process.argv.slice(1);
|
||||
}
|
||||
main(scriptArgs.length, scriptArgs, this);
|
||||
|
|
|
@ -434,18 +434,17 @@ function test_number()
|
|||
assert(Number.isNaN(Number("-")));
|
||||
assert(Number.isNaN(Number("\x00a")));
|
||||
|
||||
// TODO: Fix rounding errors on Windows/Cygwin.
|
||||
if (['win32', 'cygwin'].includes(os.platform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert((1-2**-53).toString(12), "0.bbbbbbbbbbbbbba");
|
||||
assert((1000000000000000128).toString(), "1000000000000000100");
|
||||
assert((1000000000000000128).toFixed(0), "1000000000000000128");
|
||||
assert((25).toExponential(0), "3e+1");
|
||||
assert((-25).toExponential(0), "-3e+1");
|
||||
assert((2.5).toPrecision(1), "3");
|
||||
assert((-2.5).toPrecision(1), "-3");
|
||||
assert((1.125).toFixed(2), "1.13");
|
||||
assert((-1.125).toFixed(2), "-1.13");
|
||||
assert((0.5).toFixed(0), "1");
|
||||
assert((-0.5).toFixed(0), "-1");
|
||||
}
|
||||
|
||||
function test_eval2()
|
||||
|
|
|
@ -864,6 +864,8 @@ static uint8_t const radix_shift[64] = {
|
|||
|
||||
size_t u32toa_radix_length(char buf[minimum_length(33)], uint32_t n, unsigned base)
|
||||
{
|
||||
int shift;
|
||||
|
||||
#ifdef USE_SPECIAL_RADIX_10
|
||||
if (likely(base == 10))
|
||||
return u32toa_length_loop(buf, n);
|
||||
|
@ -873,13 +875,13 @@ size_t u32toa_radix_length(char buf[minimum_length(33)], uint32_t n, unsigned ba
|
|||
buf[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
int shift = radix_shift[base & 63];
|
||||
shift = radix_shift[base & 63];
|
||||
if (shift) {
|
||||
uint32_t mask = (1 << shift) - 1;
|
||||
size_t len = (32 - clz32(n) + shift - 1) / shift;
|
||||
size_t last = n & mask;
|
||||
n /= base;
|
||||
char *end = buf + len;
|
||||
n >>= shift;
|
||||
*end-- = '\0';
|
||||
*end-- = digits36[last];
|
||||
while (n >= base) {
|
||||
|
@ -913,11 +915,13 @@ size_t u32toa_radix_length(char buf[minimum_length(33)], uint32_t n, unsigned ba
|
|||
|
||||
size_t u64toa_radix_length(char buf[minimum_length(65)], uint64_t n, unsigned base)
|
||||
{
|
||||
int shift;
|
||||
|
||||
#ifdef USE_SPECIAL_RADIX_10
|
||||
if (likely(base == 10))
|
||||
return u64toa_length_loop(buf, n);
|
||||
#endif
|
||||
int shift = radix_shift[base & 63];
|
||||
shift = radix_shift[base & 63];
|
||||
if (shift) {
|
||||
if (n < base) {
|
||||
buf[0] = digits36[n];
|
||||
|
@ -927,8 +931,8 @@ size_t u64toa_radix_length(char buf[minimum_length(65)], uint64_t n, unsigned ba
|
|||
uint64_t mask = (1 << shift) - 1;
|
||||
size_t len = (64 - clz64(n) + shift - 1) / shift;
|
||||
size_t last = n & mask;
|
||||
n /= base;
|
||||
char *end = buf + len;
|
||||
n >>= shift;
|
||||
*end-- = '\0';
|
||||
*end-- = digits36[last];
|
||||
while (n >= base) {
|
||||
|
@ -1511,6 +1515,9 @@ int main(int argc, char *argv[]) {
|
|||
clock_t times1[countof(impl1)][4][37];
|
||||
char buf[100];
|
||||
uint64_t bases = 0;
|
||||
#define set_base(bases, b) (*(bases) |= (1ULL << (b)))
|
||||
#define has_base(bases, b) ((bases) & (1ULL << (b)))
|
||||
#define single_base(bases) (!((bases) & ((bases) - 1)))
|
||||
int verbose = 0;
|
||||
int average = 1;
|
||||
int enabled = 3;
|
||||
|
@ -1521,14 +1528,13 @@ int main(int argc, char *argv[]) {
|
|||
for (int a = 1; a < argc; a++) {
|
||||
char *arg = argv[a];
|
||||
if (isdigit((unsigned char)*arg)) {
|
||||
verbose = 1;
|
||||
while (isdigit((unsigned char)*arg)) {
|
||||
int b1 = strtol(arg, &arg, 10);
|
||||
bases |= (1ULL << b1);
|
||||
set_base(&bases, b1);
|
||||
if (*arg == '-') {
|
||||
int b2 = strtol(arg, &arg, 10);
|
||||
int b2 = strtol(arg + 1, &arg, 10);
|
||||
while (++b1 <= b2)
|
||||
bases |= (1ULL << b1);
|
||||
set_base(&bases, b1);
|
||||
}
|
||||
if (*arg == ',') {
|
||||
arg++;
|
||||
|
@ -1539,10 +1545,6 @@ int main(int argc, char *argv[]) {
|
|||
fprintf(stderr, "invalid option syntax: %s\n", argv[a]);
|
||||
return 2;
|
||||
}
|
||||
if (!(bases & (bases - 1))) { /* single base */
|
||||
average = 0;
|
||||
verbose = 1;
|
||||
}
|
||||
continue;
|
||||
} else if (!strcmp(arg, "-t") || !strcmp(arg, "--terse")) {
|
||||
verbose = 0;
|
||||
|
@ -1578,14 +1580,19 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
if (!bases)
|
||||
bases = -1;
|
||||
if (bases & (bases - 1)) /* multiple bases */
|
||||
if (single_base(bases)) {
|
||||
average = 0;
|
||||
verbose = 1;
|
||||
} else {
|
||||
average = 1;
|
||||
}
|
||||
|
||||
int numvariant = 0;
|
||||
int numvariant1 = 0;
|
||||
int nerrors = 0;
|
||||
|
||||
if (bases & (1ULL << 10)) {
|
||||
/* Checking for correctness */
|
||||
if (has_base(bases, 10)) {
|
||||
for (size_t i = 0; i < countof(impl); i++) {
|
||||
unsigned base = 10;
|
||||
if (impl[i].enabled & enabled) {
|
||||
|
@ -1599,7 +1606,7 @@ int main(int argc, char *argv[]) {
|
|||
for (size_t i = 0; i < countof(impl1); i++) {
|
||||
if (impl1[i].enabled & enabled) {
|
||||
for (unsigned base = 2; base <= 36; base++) {
|
||||
if (bases & (1ULL << base)) {
|
||||
if (has_base(bases, base)) {
|
||||
CHECK(impl1[i], 1000, 0, 32, u32toa_radix(buf, x, base), strtoull(buf, NULL, base));
|
||||
CHECK(impl1[i], 1000, 1, 32, i32toa_radix(buf, x, base), strtoll(buf, NULL, base));
|
||||
CHECK(impl1[i], 1000, 0, 64, u64toa_radix(buf, x, base), strtoull(buf, NULL, base));
|
||||
|
@ -1611,13 +1618,14 @@ int main(int argc, char *argv[]) {
|
|||
if (nerrors)
|
||||
return 1;
|
||||
|
||||
if (bases & (1ULL << 10)) {
|
||||
/* Timing conversions */
|
||||
if (has_base(bases, 10)) {
|
||||
for (int rep = 0; rep < 100; rep++) {
|
||||
for (size_t i = 0; i < countof(impl); i++) {
|
||||
if (impl[i].enabled & enabled) {
|
||||
numvariant++;
|
||||
#ifdef TEST_SNPRINTF
|
||||
if (strstr(impl[i].name, "snprintf")) { // avoid function call overhead
|
||||
if (strstr(impl[i].name, "snprintf")) { // avoid wrapper overhead
|
||||
TIME(times[i][0], 1000, 0, 32, snprintf(buf, 11, "%"PRIu32, x));
|
||||
TIME(times[i][1], 1000, 1, 32, snprintf(buf, 12, "%"PRIi32, x));
|
||||
TIME(times[i][2], 1000, 0, 64, snprintf(buf, 21, "%"PRIu64, x));
|
||||
|
@ -1639,42 +1647,42 @@ int main(int argc, char *argv[]) {
|
|||
if (impl1[i].enabled & enabled) {
|
||||
numvariant1++;
|
||||
#ifdef TEST_SNPRINTF
|
||||
if (strstr(impl[i].name, "snprintf")) { // avoid function call overhead
|
||||
if (strstr(impl[i].name, "snprintf")) { // avoid wrapper overhead
|
||||
#ifdef PRIb32
|
||||
if (bases & (1ULL << 1)) {
|
||||
if (has_base(bases, 2)) {
|
||||
unsigned base = 2;
|
||||
TIME(times1[i][0][2], 1000, 0, 32, snprintf(buf, 33, "%"PRIb32, x));
|
||||
TIME(times1[i][0][base], 1000, 0, 32, snprintf(buf, 33, "%"PRIb32, x));
|
||||
TIME(times1[i][1][base], 1000, 1, 32, impl1[i].i32toa_radix(buf, x, base));
|
||||
TIME(times1[i][2][2], 1000, 0, 64, snprintf(buf, 65, "%"PRIb64, x));
|
||||
TIME(times1[i][2][base], 1000, 0, 64, snprintf(buf, 65, "%"PRIb64, x));
|
||||
TIME(times1[i][3][base], 1000, 1, 64, impl1[i].i64toa_radix(buf, x, base));
|
||||
}
|
||||
#endif
|
||||
if (bases & (1ULL << 8)) {
|
||||
if (has_base(bases, 8)) {
|
||||
unsigned base = 8;
|
||||
TIME(times1[i][0][8], 1000, 0, 32, snprintf(buf, 33, "%"PRIo32, x));
|
||||
TIME(times1[i][0][base], 1000, 0, 32, snprintf(buf, 33, "%"PRIo32, x));
|
||||
TIME(times1[i][1][base], 1000, 1, 32, impl1[i].i32toa_radix(buf, x, base));
|
||||
TIME(times1[i][2][8], 1000, 0, 64, snprintf(buf, 65, "%"PRIo64, x));
|
||||
TIME(times1[i][2][base], 1000, 0, 64, snprintf(buf, 65, "%"PRIo64, x));
|
||||
TIME(times1[i][3][base], 1000, 1, 64, impl1[i].i64toa_radix(buf, x, base));
|
||||
}
|
||||
if (bases & (1ULL << 10)) {
|
||||
if (has_base(bases, 10)) {
|
||||
unsigned base = 10;
|
||||
TIME(times1[i][0][10], 1000, 0, 32, snprintf(buf, 33, "%"PRIu32, x));
|
||||
TIME(times1[i][1][10], 1000, 1, 32, snprintf(buf, 34, "%"PRIi32, x));
|
||||
TIME(times1[i][2][10], 1000, 0, 64, snprintf(buf, 64, "%"PRIu64, x));
|
||||
TIME(times1[i][3][10], 1000, 1, 64, snprintf(buf, 65, "%"PRIi64, x));
|
||||
TIME(times1[i][0][base], 1000, 0, 32, snprintf(buf, 33, "%"PRIu32, x));
|
||||
TIME(times1[i][1][base], 1000, 1, 32, snprintf(buf, 34, "%"PRIi32, x));
|
||||
TIME(times1[i][2][base], 1000, 0, 64, snprintf(buf, 64, "%"PRIu64, x));
|
||||
TIME(times1[i][3][base], 1000, 1, 64, snprintf(buf, 65, "%"PRIi64, x));
|
||||
}
|
||||
if (bases & (1ULL << 16)) {
|
||||
if (has_base(bases, 16)) {
|
||||
unsigned base = 16;
|
||||
TIME(times1[i][0][16], 1000, 0, 32, snprintf(buf, 33, "%"PRIx32, x));
|
||||
TIME(times1[i][0][base], 1000, 0, 32, snprintf(buf, 33, "%"PRIx32, x));
|
||||
TIME(times1[i][1][base], 1000, 1, 32, impl1[i].i32toa_radix(buf, x, base));
|
||||
TIME(times1[i][2][16], 1000, 0, 64, snprintf(buf, 65, "%"PRIx64, x));
|
||||
TIME(times1[i][2][base], 1000, 0, 64, snprintf(buf, 65, "%"PRIx64, x));
|
||||
TIME(times1[i][3][base], 1000, 1, 64, impl1[i].i64toa_radix(buf, x, base));
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
for (unsigned base = 2; base <= 36; base++) {
|
||||
if (bases & (1ULL << base)) {
|
||||
if (has_base(bases, base)) {
|
||||
TIME(times1[i][0][base], 1000, 0, 32, impl1[i].u32toa_radix(buf, x, base));
|
||||
TIME(times1[i][1][base], 1000, 1, 32, impl1[i].i32toa_radix(buf, x, base));
|
||||
TIME(times1[i][2][base], 1000, 0, 64, impl1[i].u64toa_radix(buf, x, base));
|
||||
|
@ -1704,7 +1712,7 @@ int main(int argc, char *argv[]) {
|
|||
for (size_t i = 0; i < countof(impl1); i++) {
|
||||
int numbases = 0;
|
||||
for (unsigned base = 2; base <= 36; base++) {
|
||||
if (bases & (1ULL << base)) {
|
||||
if (has_base(bases, base)) {
|
||||
if (times1[i][0][base]) {
|
||||
numbases++;
|
||||
for (int j = 0; j < 4; j++)
|
||||
|
|
|
@ -5,6 +5,10 @@ function assert(actual, expected, message) {
|
|||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (typeof actual == 'number' && isNaN(actual)
|
||||
&& typeof expected == 'number' && isNaN(expected))
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
|
@ -343,10 +347,13 @@ function test_class()
|
|||
assert(S.x === 42);
|
||||
assert(S.y === 42);
|
||||
assert(S.z === 42);
|
||||
|
||||
class P {
|
||||
get = () => "123"
|
||||
get = () => "123";
|
||||
static() { return 42; }
|
||||
}
|
||||
assert(new P().get() === "123");
|
||||
assert(new P().static() === 42);
|
||||
};
|
||||
|
||||
function test_template()
|
||||
|
@ -613,6 +620,23 @@ function test_number_literals()
|
|||
assert(01.a, undefined);
|
||||
assert(0o1.a, undefined);
|
||||
test_expr('0.a', SyntaxError);
|
||||
assert(parseInt("0_1"), 0);
|
||||
assert(parseInt("1_0"), 1);
|
||||
assert(parseInt("0_1", 8), 0);
|
||||
assert(parseInt("1_0", 8), 1);
|
||||
assert(parseFloat("0_1"), 0);
|
||||
assert(parseFloat("1_0"), 1);
|
||||
assert(1_0, 10);
|
||||
assert(parseInt("Infinity"), NaN);
|
||||
assert(parseFloat("Infinity"), Infinity);
|
||||
assert(parseFloat("Infinity1"), Infinity);
|
||||
assert(parseFloat("Infinity_"), Infinity);
|
||||
assert(parseFloat("Infinity."), Infinity);
|
||||
test_expr('0_0', SyntaxError);
|
||||
test_expr('00_0', SyntaxError);
|
||||
test_expr('01_0', SyntaxError);
|
||||
test_expr('08_0', SyntaxError);
|
||||
test_expr('09_0', SyntaxError);
|
||||
}
|
||||
|
||||
function test_syntax()
|
||||
|
|
Loading…
Reference in a new issue