@scriptc/cli-darwin-x64 0.2.4 → 0.2.5
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/dist/THIRD_PARTY_NOTICES +1 -1
- package/dist/bin/scriptc +0 -0
- package/dist/bin/scriptc.json +1 -1
- package/dist/lib/declarations/scriptc-node-fallback.d.ts +915 -215
- package/dist/lib/declarations/scriptc-overrides.d.ts +5 -1
- package/dist/lib/declarations/scriptc.d.ts +22 -2
- package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
- package/dist/lib/llvm/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/runtime-pack.json +183 -183
- package/dist/lib/runtime-sources/package.json +1 -1
- package/dist/lib/runtime-sources/src/scr_array.c +267 -6
- package/dist/lib/runtime-sources/src/scr_async.test.ts +16 -6
- package/dist/lib/runtime-sources/src/scr_bytes.c +437 -216
- package/dist/lib/runtime-sources/src/scr_bytes.test.c +85 -0
- package/dist/lib/runtime-sources/src/scr_bytes_io.c +0 -34
- package/dist/lib/runtime-sources/src/scr_copying.c +12 -2
- package/dist/lib/runtime-sources/src/scr_json.c +479 -150
- package/dist/lib/runtime-sources/src/scr_json.test.c +323 -1
- package/dist/lib/runtime-sources/src/scr_json.test.ts +58 -25
- package/dist/lib/runtime-sources/src/scr_key.h +68 -0
- package/dist/lib/runtime-sources/src/scr_lib.c +132 -73
- package/dist/lib/runtime-sources/src/scr_map.c +50 -66
- package/dist/lib/runtime-sources/src/scr_number.c +2 -4
- package/dist/lib/runtime-sources/src/scr_numeric.h +25 -0
- package/dist/lib/runtime-sources/src/scr_numeric.test.c +37 -0
- package/dist/lib/runtime-sources/src/scr_numeric.test.ts +33 -0
- package/dist/lib/runtime-sources/src/scr_regex.c +238 -167
- package/dist/lib/runtime-sources/src/scr_runtime.h +37 -6
- package/dist/lib/runtime-sources/src/scr_string.c +155 -42
- package/package.json +1 -1
|
@@ -2299,34 +2299,125 @@ static FILE *scr_fs_fopen(const ScrStr *path, const char *mode) {
|
|
|
2299
2299
|
#endif
|
|
2300
2300
|
}
|
|
2301
2301
|
|
|
2302
|
+
/* File sizes are hints, never EOF. Pseudo-files, pipes and concurrently
|
|
2303
|
+
* changing files still read to EOF; descriptor reads keep their position
|
|
2304
|
+
* and ownership. Limit individual reads for the CRT and small ssize_t. */
|
|
2305
|
+
typedef struct {
|
|
2306
|
+
ScrStr *text;
|
|
2307
|
+
uint8_t *bytes;
|
|
2308
|
+
size_t len, cap;
|
|
2309
|
+
} ScrFileRead;
|
|
2310
|
+
|
|
2311
|
+
static size_t scr_file_read_hint(FILE *stream, int fd) {
|
|
2312
|
+
if (stream) fd = fileno(stream);
|
|
2313
|
+
#ifdef _WIN32
|
|
2314
|
+
struct _stat64 st;
|
|
2315
|
+
if (_fstat64(fd, &st) != 0 || !S_ISREG(st.st_mode) || st.st_size <= 0) return 4096;
|
|
2316
|
+
int64_t position = stream ? 0 : _lseeki64(fd, 0, SEEK_CUR);
|
|
2317
|
+
#else
|
|
2318
|
+
struct stat st;
|
|
2319
|
+
if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode) || st.st_size <= 0) return 4096;
|
|
2320
|
+
off_t position = stream ? 0 : lseek(fd, 0, SEEK_CUR);
|
|
2321
|
+
#endif
|
|
2322
|
+
if (position < 0 || position >= st.st_size) return 4096;
|
|
2323
|
+
uintmax_t remaining = (uintmax_t)st.st_size - (uintmax_t)position;
|
|
2324
|
+
/* A bounded initial allocation also tolerates sparse files that shrink
|
|
2325
|
+
* between metadata and the first read without reserving their full size. */
|
|
2326
|
+
size_t limit = 64 * 1024 * 1024;
|
|
2327
|
+
return remaining > limit ? limit : (size_t)remaining;
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
static uint8_t *scr_file_read_data(ScrFileRead *out) {
|
|
2331
|
+
return out->text ? (uint8_t *)out->text->data : out->bytes;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
static void scr_file_read_grow(ScrFileRead *out) {
|
|
2335
|
+
size_t limit = SIZE_MAX - sizeof(ScrStr) - 1;
|
|
2336
|
+
if (out->cap >= limit) scr_trap("scriptc: file too large\n");
|
|
2337
|
+
size_t cap = out->cap > limit / 2 ? limit : out->cap * 2;
|
|
2338
|
+
if (out->text) {
|
|
2339
|
+
out->text->len = out->len;
|
|
2340
|
+
out->text = scr_str_regrow(out->text, cap);
|
|
2341
|
+
} else {
|
|
2342
|
+
uint8_t *grown = realloc(out->bytes, cap);
|
|
2343
|
+
if (!grown) scr_trap("scriptc: out of memory\n");
|
|
2344
|
+
out->bytes = grown;
|
|
2345
|
+
}
|
|
2346
|
+
out->cap = cap;
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
/* Fill the final allocation. At a full capacity, probe one byte before
|
|
2350
|
+
* growing so an exact-size regular file never doubles its retained space. */
|
|
2351
|
+
static int scr_file_read_all(FILE *stream, int fd, bool text, ScrFileRead *out) {
|
|
2352
|
+
*out = (ScrFileRead){0};
|
|
2353
|
+
out->cap = scr_file_read_hint(stream, fd);
|
|
2354
|
+
if (text) {
|
|
2355
|
+
out->text = scr_str_alloc_raw(0, out->cap);
|
|
2356
|
+
out->cap = out->text->cap;
|
|
2357
|
+
out->text->data[0] = '\0';
|
|
2358
|
+
} else {
|
|
2359
|
+
out->bytes = malloc(out->cap);
|
|
2360
|
+
if (!out->bytes) scr_trap("scriptc: out of memory\n");
|
|
2361
|
+
}
|
|
2362
|
+
for (;;) {
|
|
2363
|
+
uint8_t extra;
|
|
2364
|
+
bool full = out->len == out->cap;
|
|
2365
|
+
size_t room = full ? 1 : out->cap - out->len;
|
|
2366
|
+
if (room > 512 * 1024) room = 512 * 1024;
|
|
2367
|
+
uint8_t *dest = full ? &extra : scr_file_read_data(out) + out->len;
|
|
2368
|
+
size_t count;
|
|
2369
|
+
int error = 0;
|
|
2370
|
+
if (stream) {
|
|
2371
|
+
count = fread(dest, 1, room, stream);
|
|
2372
|
+
if (ferror(stream)) error = errno ? errno : EIO;
|
|
2373
|
+
} else {
|
|
2374
|
+
ssize_t n = read(fd, dest, room);
|
|
2375
|
+
if (n < 0) { count = 0; error = errno; }
|
|
2376
|
+
else count = (size_t)n;
|
|
2377
|
+
}
|
|
2378
|
+
if (count) {
|
|
2379
|
+
if (full) {
|
|
2380
|
+
scr_file_read_grow(out);
|
|
2381
|
+
scr_file_read_data(out)[out->len] = extra;
|
|
2382
|
+
}
|
|
2383
|
+
out->len += count;
|
|
2384
|
+
}
|
|
2385
|
+
if (error == EINTR) {
|
|
2386
|
+
if (stream) clearerr(stream);
|
|
2387
|
+
continue;
|
|
2388
|
+
}
|
|
2389
|
+
if (error) {
|
|
2390
|
+
/* Raw strings must be safe for the normal cache-aware destructor. */
|
|
2391
|
+
if (out->text) { out->text->len = out->len; out->text->data[out->len] = '\0'; }
|
|
2392
|
+
scr_str_release(out->text);
|
|
2393
|
+
free(out->bytes);
|
|
2394
|
+
*out = (ScrFileRead){0};
|
|
2395
|
+
return error;
|
|
2396
|
+
}
|
|
2397
|
+
if (!count) break;
|
|
2398
|
+
}
|
|
2399
|
+
if (out->text) { out->text->len = out->len; out->text->data[out->len] = '\0'; }
|
|
2400
|
+
// Do not retain a large hint after truncation or a tiny pipe result.
|
|
2401
|
+
if (out->cap > 256 && out->len < out->cap / 2) {
|
|
2402
|
+
if (out->text) out->text = scr_str_regrow(out->text, out->len);
|
|
2403
|
+
else {
|
|
2404
|
+
uint8_t *trimmed = realloc(out->bytes, out->len ? out->len : 1);
|
|
2405
|
+
if (trimmed) out->bytes = trimmed;
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
return 0;
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2302
2411
|
static ScrStr *scr_fs_read_file_core(ScrStr *path, bool env_file) {
|
|
2303
2412
|
FILE *f = scr_fs_fopen(path, "rb");
|
|
2304
2413
|
if (!f) {
|
|
2305
2414
|
scr_fs_throw(errno, "open", path);
|
|
2306
2415
|
return NULL;
|
|
2307
2416
|
}
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
}
|
|
2313
|
-
for (;;) {
|
|
2314
|
-
if (cap - len < 2048) {
|
|
2315
|
-
cap *= 2;
|
|
2316
|
-
char *grown = realloc(buf, cap);
|
|
2317
|
-
if (!grown) {
|
|
2318
|
-
scr_trap("scriptc: out of memory\n");
|
|
2319
|
-
}
|
|
2320
|
-
buf = grown;
|
|
2321
|
-
}
|
|
2322
|
-
size_t n = fread(buf + len, 1, cap - len, f);
|
|
2323
|
-
len += n;
|
|
2324
|
-
if (n == 0) break;
|
|
2325
|
-
}
|
|
2326
|
-
if (ferror(f)) {
|
|
2327
|
-
int e = errno;
|
|
2328
|
-
fclose(f);
|
|
2329
|
-
free(buf);
|
|
2417
|
+
ScrFileRead out;
|
|
2418
|
+
int error = scr_file_read_all(f, -1, true, &out);
|
|
2419
|
+
fclose(f);
|
|
2420
|
+
if (error) {
|
|
2330
2421
|
if (env_file) {
|
|
2331
2422
|
ScrJsonBuf b;
|
|
2332
2423
|
scr_jb_init(&b);
|
|
@@ -2336,13 +2427,20 @@ static ScrStr *scr_fs_read_file_core(ScrStr *path, bool env_file) {
|
|
|
2336
2427
|
ScrStr *message = scr_jb_finish(&b);
|
|
2337
2428
|
scr_throw_error_msg_code(SCR_ERR_TYPE, message->data, message->len, "ERR_INVALID_ARG_TYPE");
|
|
2338
2429
|
scr_str_release(message);
|
|
2339
|
-
} else scr_fs_throw(
|
|
2430
|
+
} else scr_fs_throw(error, "read", path);
|
|
2340
2431
|
return NULL;
|
|
2341
2432
|
}
|
|
2433
|
+
return out.text;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
ScrBytes *scr_fs_read_file_bytes(ScrStr *path) {
|
|
2437
|
+
FILE *f = scr_fs_fopen(path, "rb");
|
|
2438
|
+
if (!f) { scr_fs_throw(errno, "open", path); return NULL; }
|
|
2439
|
+
ScrFileRead out;
|
|
2440
|
+
int error = scr_file_read_all(f, -1, false, &out);
|
|
2342
2441
|
fclose(f);
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
return s;
|
|
2442
|
+
if (error) { scr_fs_throw(error, "read", path); return NULL; }
|
|
2443
|
+
return scr_bytes_take_data(out.bytes, out.len);
|
|
2346
2444
|
}
|
|
2347
2445
|
|
|
2348
2446
|
ScrStr *scr_fs_read_file(ScrStr *path) {
|
|
@@ -3799,57 +3897,18 @@ static void scr_fs_throw_nopath(int e, const char *op) {
|
|
|
3799
3897
|
scr_throw_error_msg_code(SCR_ERR_ERROR, msg, (size_t)len, name);
|
|
3800
3898
|
}
|
|
3801
3899
|
|
|
3802
|
-
/* read(2) loop to EOF from the CURRENT position — Node's
|
|
3803
|
-
* readFileSync(fd) semantics for pipes and files alike (the stdin
|
|
3804
|
-
* pattern: readFileSync(0, "utf8")). Returns the malloc'd buffer and
|
|
3805
|
-
* its length, or NULL with the exception pending. */
|
|
3806
|
-
static char *scr_read_fd_all(double fd, size_t *out_len) {
|
|
3807
|
-
size_t cap = 4096, len = 0;
|
|
3808
|
-
char *buf = malloc(cap);
|
|
3809
|
-
if (!buf) {
|
|
3810
|
-
scr_trap("scriptc: out of memory\n");
|
|
3811
|
-
}
|
|
3812
|
-
for (;;) {
|
|
3813
|
-
if (cap - len < 2048) {
|
|
3814
|
-
cap *= 2;
|
|
3815
|
-
char *grown = realloc(buf, cap);
|
|
3816
|
-
if (!grown) {
|
|
3817
|
-
scr_trap("scriptc: out of memory\n");
|
|
3818
|
-
}
|
|
3819
|
-
buf = grown;
|
|
3820
|
-
}
|
|
3821
|
-
ssize_t n = read((int)fd, buf + len, cap - len);
|
|
3822
|
-
if (n < 0) {
|
|
3823
|
-
if (errno == EINTR) continue;
|
|
3824
|
-
int e = errno;
|
|
3825
|
-
free(buf);
|
|
3826
|
-
scr_fs_throw_nopath(e, "read");
|
|
3827
|
-
return NULL;
|
|
3828
|
-
}
|
|
3829
|
-
if (n == 0) break;
|
|
3830
|
-
len += (size_t)n;
|
|
3831
|
-
}
|
|
3832
|
-
*out_len = len;
|
|
3833
|
-
return buf;
|
|
3834
|
-
}
|
|
3835
|
-
|
|
3836
3900
|
ScrStr *scr_fs_read_fd(double fd) {
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
if (
|
|
3840
|
-
|
|
3841
|
-
free(buf);
|
|
3842
|
-
return s;
|
|
3901
|
+
ScrFileRead out;
|
|
3902
|
+
int error = scr_file_read_all(NULL, (int)fd, true, &out);
|
|
3903
|
+
if (error) { scr_fs_throw_nopath(error, "read"); return NULL; }
|
|
3904
|
+
return out.text;
|
|
3843
3905
|
}
|
|
3844
3906
|
|
|
3845
3907
|
ScrBytes *scr_fs_read_fd_bytes(double fd) {
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
if (
|
|
3849
|
-
|
|
3850
|
-
if (len > 0) memcpy(b->data, buf, len);
|
|
3851
|
-
free(buf);
|
|
3852
|
-
return b;
|
|
3908
|
+
ScrFileRead out;
|
|
3909
|
+
int error = scr_file_read_all(NULL, (int)fd, false, &out);
|
|
3910
|
+
if (error) { scr_fs_throw_nopath(error, "read"); return NULL; }
|
|
3911
|
+
return scr_bytes_take_data(out.bytes, out.len);
|
|
3853
3912
|
}
|
|
3854
3913
|
|
|
3855
3914
|
/* ── Atomics.wait: the synchronous-sleep idiom ───────────────────────
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* keep the lean 1-word header and never touch the collector.
|
|
16
16
|
*/
|
|
17
17
|
#include "scr_runtime.h"
|
|
18
|
+
#include "scr_key.h"
|
|
18
19
|
|
|
19
20
|
#include <stdio.h>
|
|
20
21
|
#include <stdlib.h>
|
|
@@ -46,27 +47,14 @@ static uint64_t scr_map_f64_bits(double k) {
|
|
|
46
47
|
return bits;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
static uint64_t scr_map_fnv1a(const unsigned char *bytes, size_t n) {
|
|
50
|
-
uint64_t h = UINT64_C(0xcbf29ce484222325);
|
|
51
|
-
for (size_t i = 0; i < n; i++) {
|
|
52
|
-
h ^= bytes[i];
|
|
53
|
-
h *= UINT64_C(0x100000001b3);
|
|
54
|
-
}
|
|
55
|
-
return h;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
50
|
static uint64_t scr_map_hash_str(const ScrStr *k) {
|
|
59
|
-
return
|
|
51
|
+
return scr_key_hash(k->data, k->len);
|
|
60
52
|
}
|
|
61
53
|
|
|
62
54
|
/* Mix the complete normalized number or identity word. Float exponents
|
|
63
55
|
* and aligned pointers need high bits to reach the low bucket-index bits. */
|
|
64
56
|
static uint64_t scr_map_hash_word(uint64_t value) {
|
|
65
|
-
|
|
66
|
-
value *= UINT64_C(0xbf58476d1ce4e5b9);
|
|
67
|
-
value ^= value >> 27;
|
|
68
|
-
value *= UINT64_C(0x94d049bb133111eb);
|
|
69
|
-
return value ^ (value >> 31);
|
|
57
|
+
return scr_key_mix(value);
|
|
70
58
|
}
|
|
71
59
|
|
|
72
60
|
/* ── slot packing (8-byte slots, like ScrArr) ──────────────────────────── */
|
|
@@ -209,8 +197,19 @@ static size_t scr_map_probe(const ScrMap *m, uint64_t hash, uint64_t key) {
|
|
|
209
197
|
}
|
|
210
198
|
}
|
|
211
199
|
|
|
200
|
+
#define SCR_MAP_LINEAR_LIMIT 4
|
|
201
|
+
|
|
202
|
+
/* Small collections keep only their ordered entries. Cached hashes make
|
|
203
|
+
* the bounded scan cheap without allocating a separate bucket table. */
|
|
212
204
|
static size_t scr_map_find(const ScrMap *m, uint64_t hash, uint64_t key) {
|
|
213
|
-
|
|
205
|
+
hash = hash ? hash : 1;
|
|
206
|
+
if (m->nbuckets == 0) {
|
|
207
|
+
for (size_t e = 0; e < m->nentries; e++) {
|
|
208
|
+
if (m->entries[e].hash == hash && scr_map_key_eq(m, m->entries[e].key, key)) return e;
|
|
209
|
+
}
|
|
210
|
+
return SCR_MAP_EMPTY;
|
|
211
|
+
}
|
|
212
|
+
size_t slot = scr_map_probe(m, hash, key);
|
|
214
213
|
return slot == SCR_MAP_EMPTY ? SCR_MAP_EMPTY : m->buckets[slot];
|
|
215
214
|
}
|
|
216
215
|
|
|
@@ -248,12 +247,15 @@ static void scr_map_compact(ScrMap *m) {
|
|
|
248
247
|
* reuse their storage) and grows otherwise; while an iteration is active it
|
|
249
248
|
* ONLY grows — indices must stay stable under callback mutation. */
|
|
250
249
|
static void scr_map_reserve_append(ScrMap *m) {
|
|
251
|
-
if (m->nentries < m->ecap &&
|
|
252
|
-
|
|
250
|
+
if (m->nentries < m->ecap &&
|
|
251
|
+
((m->nbuckets == 0 && m->nentries < SCR_MAP_LINEAR_LIMIT) ||
|
|
252
|
+
m->nbuckets >= 2 * (m->nentries + 1))) return;
|
|
253
|
+
if (m->iter_depth == 0 && m->nentries > 0 &&
|
|
254
|
+
(m->nbuckets == 0 ? m->nlive < m->nentries : m->nlive <= m->nentries / 2)) {
|
|
253
255
|
scr_map_compact(m);
|
|
254
256
|
}
|
|
255
257
|
if (m->nentries == m->ecap) {
|
|
256
|
-
size_t cap = m->ecap ? m->ecap :
|
|
258
|
+
size_t cap = m->ecap ? m->ecap : 4;
|
|
257
259
|
while (cap < m->nentries + 1) {
|
|
258
260
|
if (cap > SIZE_MAX / 2 / sizeof(ScrMapEntry)) scr_map_oom();
|
|
259
261
|
cap *= 2;
|
|
@@ -263,6 +265,7 @@ static void scr_map_reserve_append(ScrMap *m) {
|
|
|
263
265
|
m->entries = entries;
|
|
264
266
|
m->ecap = cap;
|
|
265
267
|
}
|
|
268
|
+
if (m->nbuckets == 0 && m->nentries < SCR_MAP_LINEAR_LIMIT) return;
|
|
266
269
|
if (m->nbuckets < 2 * (m->nentries + 1)) {
|
|
267
270
|
size_t nbuckets = m->nbuckets ? m->nbuckets : 16;
|
|
268
271
|
while (nbuckets < 2 * (m->nentries + 1)) {
|
|
@@ -469,7 +472,7 @@ bool scr_map_delete_ref(ScrMap *m, const void *key) {
|
|
|
469
472
|
static void scr_map_set(ScrMap *m, uint64_t hash, uint64_t key, uint64_t val) {
|
|
470
473
|
hash = hash ? hash : 1;
|
|
471
474
|
size_t slot = scr_map_probe(m, hash, key);
|
|
472
|
-
size_t e =
|
|
475
|
+
size_t e = m->nbuckets == 0 ? scr_map_find(m, hash, key) : m->buckets[slot];
|
|
473
476
|
if (e != SCR_MAP_EMPTY) {
|
|
474
477
|
uint64_t old = m->entries[e].val;
|
|
475
478
|
m->entries[e].val = val; /* unlink before releasing (cycle collector) */
|
|
@@ -480,7 +483,7 @@ static void scr_map_set(ScrMap *m, uint64_t hash, uint64_t key, uint64_t val) {
|
|
|
480
483
|
scr_map_reserve_append(m);
|
|
481
484
|
/* Growth or compaction can move the insertion bucket. Otherwise keep the
|
|
482
485
|
* empty slot from the first probe instead of walking the chain twice. */
|
|
483
|
-
if (m->nentries != old_entries || m->nbuckets != old_buckets) {
|
|
486
|
+
if (m->nbuckets && (m->nentries != old_entries || m->nbuckets != old_buckets)) {
|
|
484
487
|
size_t mask = m->nbuckets - 1;
|
|
485
488
|
slot = hash & mask;
|
|
486
489
|
while (m->buckets[slot] != SCR_MAP_EMPTY) slot = (slot + 1) & mask;
|
|
@@ -510,7 +513,7 @@ static void scr_map_set(ScrMap *m, uint64_t hash, uint64_t key, uint64_t val) {
|
|
|
510
513
|
} else if (scr_map_ref_key(m->key_kind)) {
|
|
511
514
|
m->key_retain(scr_map_slot_to_ptr(key)); /* key is borrowed */
|
|
512
515
|
}
|
|
513
|
-
m->buckets[slot] = idx;
|
|
516
|
+
if (m->nbuckets) m->buckets[slot] = idx;
|
|
514
517
|
}
|
|
515
518
|
|
|
516
519
|
static void scr_map_set_f64_key(ScrMap *m, double key, uint64_t val) {
|
|
@@ -792,6 +795,7 @@ ScrMap *scr_map_clone(const ScrMap *source, bool keys_only) {
|
|
|
792
795
|
else if (out->val_kind == SCR_MAP_VAL_REF) out->val_retain(scr_map_slot_to_ptr(copy->val));
|
|
793
796
|
}
|
|
794
797
|
out->nlive = count;
|
|
798
|
+
if (count <= SCR_MAP_LINEAR_LIMIT) return out;
|
|
795
799
|
size_t buckets = 16;
|
|
796
800
|
while (buckets < 2 * count) {
|
|
797
801
|
if (buckets > SIZE_MAX / 2 / sizeof(size_t)) scr_map_oom();
|
|
@@ -890,59 +894,39 @@ void scr_set_add_all(ScrMap *set, ScrArr *values) {
|
|
|
890
894
|
/* Canonical array index test: "0".."4294967294" — digits only, no leading
|
|
891
895
|
* zero (except "0" itself), value <= 2^32 - 2. JS orders these OWN keys
|
|
892
896
|
* first, ascending numerically, before every other string key. */
|
|
893
|
-
static bool scr_map_key_array_index(const ScrStr *
|
|
894
|
-
|
|
895
|
-
if (n == 0 || n > 10) return false;
|
|
896
|
-
const char *s = k->data;
|
|
897
|
-
if (s[0] == '0' && n > 1) return false;
|
|
898
|
-
uint64_t v = 0;
|
|
899
|
-
for (size_t i = 0; i < n; i++) {
|
|
900
|
-
if (s[i] < '0' || s[i] > '9') return false;
|
|
901
|
-
v = v * 10 + (uint64_t)(s[i] - '0');
|
|
902
|
-
}
|
|
903
|
-
if (v > UINT64_C(4294967294)) return false;
|
|
904
|
-
*out = (uint32_t)v;
|
|
905
|
-
return true;
|
|
897
|
+
static bool scr_map_key_array_index(const ScrStr *key, uint32_t *out) {
|
|
898
|
+
return scr_key_array_index(key->data, key->len, out);
|
|
906
899
|
}
|
|
907
900
|
|
|
908
|
-
/*
|
|
909
|
-
*
|
|
910
|
-
* first in ascending numeric order, then the rest in insertion order.
|
|
911
|
-
* Returns a fresh ScrStr* array (+1); the map is borrowed. Insertion sort
|
|
912
|
-
* over the integer-like subset — overflow maps are small, and ties are
|
|
913
|
-
* impossible (keys are unique). */
|
|
901
|
+
/* Enumerate numeric keys in ascending order, then other keys in insertion
|
|
902
|
+
* order. Scratch entries refer to stable map indices, not copied strings. */
|
|
914
903
|
ScrArr *scr_map_keys_js_order(const ScrMap *m) {
|
|
915
|
-
size_t n = m->nentries;
|
|
916
904
|
ScrArr *out = scr_arr_new(SCR_ELEM_STR, m->nlive);
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
905
|
+
if (m->nlive > SIZE_MAX / sizeof(ScrKeyIndex)) scr_map_oom();
|
|
906
|
+
ScrKeyIndex *indices = NULL;
|
|
907
|
+
size_t count = 0;
|
|
908
|
+
for (size_t i = 0; i < m->nentries; i++) {
|
|
920
909
|
if (!m->entries[i].hash) continue;
|
|
921
|
-
ScrStr *
|
|
922
|
-
uint32_t
|
|
923
|
-
if (!scr_map_key_array_index(
|
|
924
|
-
if (
|
|
925
|
-
|
|
926
|
-
if (!
|
|
910
|
+
ScrStr *key = scr_map_slot_to_ptr(m->entries[i].key);
|
|
911
|
+
uint32_t index;
|
|
912
|
+
if (!scr_map_key_array_index(key, &index)) continue;
|
|
913
|
+
if (!indices) {
|
|
914
|
+
indices = malloc(m->nlive * sizeof *indices);
|
|
915
|
+
if (!indices) scr_map_oom();
|
|
927
916
|
}
|
|
928
|
-
|
|
929
|
-
while (j > 0 && idx[j - 1].v > v) {
|
|
930
|
-
idx[j] = idx[j - 1];
|
|
931
|
-
j--;
|
|
932
|
-
}
|
|
933
|
-
idx[j].v = v;
|
|
934
|
-
idx[j].k = k;
|
|
917
|
+
indices[count++] = (ScrKeyIndex){index, i};
|
|
935
918
|
}
|
|
936
|
-
|
|
937
|
-
|
|
919
|
+
scr_key_index_sort(indices, count);
|
|
920
|
+
for (size_t i = 0; i < count; i++) {
|
|
921
|
+
ScrStr *key = scr_map_slot_to_ptr(m->entries[indices[i].entry].key);
|
|
922
|
+
scr_arr_push_ref(out, scr_str_retain(key));
|
|
938
923
|
}
|
|
939
|
-
free(
|
|
940
|
-
for (size_t i = 0; i <
|
|
924
|
+
free(indices);
|
|
925
|
+
for (size_t i = 0; i < m->nentries; i++) {
|
|
941
926
|
if (!m->entries[i].hash) continue;
|
|
942
|
-
ScrStr *
|
|
943
|
-
uint32_t
|
|
944
|
-
if (scr_map_key_array_index(
|
|
945
|
-
scr_arr_push_ref(out, scr_str_retain(k));
|
|
927
|
+
ScrStr *key = scr_map_slot_to_ptr(m->entries[i].key);
|
|
928
|
+
uint32_t index;
|
|
929
|
+
if (!scr_map_key_array_index(key, &index)) scr_arr_push_ref(out, scr_str_retain(key));
|
|
946
930
|
}
|
|
947
931
|
return out;
|
|
948
932
|
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* and the 1M-double fuzz gate (packages/runtime/test/gen-number-cases.mjs).
|
|
15
15
|
*/
|
|
16
16
|
#include "scr_runtime.h"
|
|
17
|
+
#include "scr_numeric.h"
|
|
17
18
|
|
|
18
19
|
#include <math.h>
|
|
19
20
|
#include <stdint.h>
|
|
@@ -27,10 +28,7 @@
|
|
|
27
28
|
/* ECMA ToUint32, shared by bitwise operators and split's limit: non-finite
|
|
28
29
|
* values become zero, finite values truncate toward zero and wrap mod 2^32. */
|
|
29
30
|
uint32_t scr_to_uint32(double d) {
|
|
30
|
-
|
|
31
|
-
double t = fmod(trunc(d), 4294967296.0);
|
|
32
|
-
if (t < 0) t += 4294967296.0;
|
|
33
|
-
return (uint32_t)t;
|
|
31
|
+
return scr_numeric_to_u32(d);
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
/* ── bitwise operators ─────────────────────────────────────────────────
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* Internal numeric coercions shared by scalar operators and typed storage. */
|
|
2
|
+
#ifndef SCR_NUMERIC_H
|
|
3
|
+
#define SCR_NUMERIC_H
|
|
4
|
+
#include <float.h>
|
|
5
|
+
#include <stdint.h>
|
|
6
|
+
#include <string.h>
|
|
7
|
+
|
|
8
|
+
_Static_assert(sizeof(double) == sizeof(uint64_t) && DBL_MANT_DIG == 53 && DBL_MAX_EXP == 1024,
|
|
9
|
+
"numeric coercions require binary64 doubles");
|
|
10
|
+
|
|
11
|
+
/* ToUint32 truncates toward zero and keeps the low 32 bits. Reading the
|
|
12
|
+
* binary64 exponent also handles non-finite values without floating modulo.
|
|
13
|
+
* Subnormals have magnitude below one; exponents >= 84 have no low bits. */
|
|
14
|
+
static inline uint32_t scr_numeric_to_u32(double value) {
|
|
15
|
+
uint64_t bits;
|
|
16
|
+
memcpy(&bits, &value, sizeof bits);
|
|
17
|
+
unsigned exponent = (unsigned)((bits >> 52) & 0x7ff);
|
|
18
|
+
if (exponent < 1023 || exponent >= 1023 + 84) return 0;
|
|
19
|
+
unsigned shift = exponent - 1023;
|
|
20
|
+
uint64_t significand = (bits & UINT64_C(0x000fffffffffffff)) | UINT64_C(0x0010000000000000);
|
|
21
|
+
uint32_t integer = shift >= 52 ? (uint32_t)(significand << (shift - 52))
|
|
22
|
+
: (uint32_t)(significand >> (52 - shift));
|
|
23
|
+
return bits >> 63 ? UINT32_C(0) - integer : integer;
|
|
24
|
+
}
|
|
25
|
+
#endif
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#include "scr_numeric.h"
|
|
2
|
+
#include <assert.h>
|
|
3
|
+
#include <math.h>
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
|
|
6
|
+
/* Independent arithmetic oracle: do not derive expectations from bit fields. */
|
|
7
|
+
static uint32_t reference(double value) {
|
|
8
|
+
if (!isfinite(value)) return 0;
|
|
9
|
+
double residue = fmod(trunc(value), 4294967296.0);
|
|
10
|
+
if (residue < 0) residue += 4294967296.0;
|
|
11
|
+
return (uint32_t)residue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static void check(uint64_t bits) {
|
|
15
|
+
double value;
|
|
16
|
+
memcpy(&value, &bits, sizeof value);
|
|
17
|
+
assert(scr_numeric_to_u32(value) == reference(value));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
int main(void) {
|
|
21
|
+
uint64_t bits = UINT64_C(0x0123456789abcdef);
|
|
22
|
+
for (unsigned i = 0; i < 2000000; i++) {
|
|
23
|
+
bits ^= bits << 13;
|
|
24
|
+
bits ^= bits >> 7;
|
|
25
|
+
bits ^= bits << 17;
|
|
26
|
+
check(bits);
|
|
27
|
+
}
|
|
28
|
+
/* Both signs at every exponent, including non-finite and subnormal values. */
|
|
29
|
+
for (unsigned exponent = 0; exponent < 2048; exponent++) {
|
|
30
|
+
for (unsigned sign = 0; sign < 2; sign++) {
|
|
31
|
+
for (unsigned low = 0; low < 64; low++) {
|
|
32
|
+
check(((uint64_t)sign << 63) | ((uint64_t)exponent << 52) | low);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
puts("numeric coercions passed");
|
|
37
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { expect, test } from "vitest";
|
|
7
|
+
|
|
8
|
+
const exec = promisify(execFile);
|
|
9
|
+
|
|
10
|
+
test("integer coercion matches modular truncation across binary64 encodings", async () => {
|
|
11
|
+
const scratch = await mkdtemp(join(tmpdir(), "scriptc-numeric-"));
|
|
12
|
+
try {
|
|
13
|
+
const binary = join(scratch, "numeric");
|
|
14
|
+
await exec("clang", [
|
|
15
|
+
"-std=c11",
|
|
16
|
+
"-O2",
|
|
17
|
+
"-Wall",
|
|
18
|
+
"-Wextra",
|
|
19
|
+
"-fsanitize=address,undefined",
|
|
20
|
+
join(import.meta.dirname, "scr_numeric.test.c"),
|
|
21
|
+
"-o",
|
|
22
|
+
binary,
|
|
23
|
+
...(process.platform === "linux" ? ["-lm"] : []),
|
|
24
|
+
]);
|
|
25
|
+
const result = await exec(binary, [], {
|
|
26
|
+
env: { ...process.env, UBSAN_OPTIONS: "halt_on_error=1" },
|
|
27
|
+
});
|
|
28
|
+
expect(result.stdout).toBe("numeric coercions passed\n");
|
|
29
|
+
expect(result.stderr).toBe("");
|
|
30
|
+
} finally {
|
|
31
|
+
await rm(scratch, { recursive: true, force: true });
|
|
32
|
+
}
|
|
33
|
+
});
|