mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 00:25:34 +08:00
Support native runtime values used by OpenTUI
- Add shared ArrayBuffer storage and native Unicode grapheme segmentation. - Preserve builtin modules, globals, and byte views across JavaScript bindings. - Compile package initialization expressions and optional native callables.
This commit is contained in:
@@ -50,6 +50,10 @@ const results = await Promise.all(jobs); // number[] — compiles
|
||||
- `URL` supports absolute inputs and relative inputs with runtime string or `URL` bases, including optional bases, and read-only `protocol`, `origin`, `username`, `password`, `pathname`, `href`, `host`, `hostname`, `port`, `search`, and `hash` getters. `searchParams` remains a live view. Setters remain fenced. Non-ASCII and percent-escaped hosts are rejected; opaque paths retain their input bytes without the WHATWG C0 encoding pass.
|
||||
- `fs.openSync` accepts inline bitwise OR expressions of `fs.constants.O_RDONLY`, `O_WRONLY`, `O_RDWR`, `O_CREAT`, `O_EXCL`, `O_NOFOLLOW`, `O_NONBLOCK`, `O_TRUNC`, and `O_APPEND`, with an optional creation mode. Computed numeric flags remain fenced because their bit values differ by target. `fstatSync`, `fchmodSync`, `fsyncSync`, and `linkSync` compile at direct call sites. On Windows, a numeric open with `O_NOFOLLOW` and `fchmodSync` throw `ENOSYS` because the CRT cannot enforce those contracts; programs requiring them should use a POSIX target.
|
||||
- Numeric `process.exitCode = value` writes in statement position set the implicit exit status; `process.exit()` with no argument uses that status. Reading or resetting `process.exitCode`, and assignments used as values, remain fenced.
|
||||
- `process.getBuiltinModule()` exposes native subsets of `path`, `path/posix`, and `path/win32`, native `os` functions, and main-thread `worker_threads` metadata. Module references and stored functions retain identity. Other modules and exports, including `Worker`, throw `SC2020`. `process.versions` is a shared dictionary containing `node` and `openssl`; other component versions are absent unless defined by the program.
|
||||
- Fixed-length `ArrayBuffer` values support shared typed-array and DataView storage. Resizing and transferring buffers remain unsupported. `Uint8Array` and Buffer values preserve shared storage when passed through `unknown`.
|
||||
- `Intl.Segmenter` supports default Unicode grapheme segmentation, segment iteration, and `containing()`. Locale negotiation, word and sentence segmentation, `resolvedOptions()`, and detached method values remain unsupported.
|
||||
- Stored `globalThis` references support identity and probes for absent host capabilities. Most builtin members still require direct global access; reading them through a stored global object can raise `SC2020`.
|
||||
- Map keys and Set elements support numbers and strings by value, and records, class instances, arrays, symbols, and server handles by identity. Unions consisting only of these identity types also compile. Collections with `unknown` slots, including JavaScript's unannotated `new Map()` and `new Set()`, use native checked values: supported primitives compare by value and supported object references retain their identity. BigInts, symbols, nested collections, Error objects, and promises whose payload requires an adapter cannot cross into those checked slots; `Promise<unknown>` retains its original identity. Other statically typed key forms, mixed scalar/reference unions, nullable key unions, and key conversions that copy an existing reference remain fenced.
|
||||
- Static `zlib.deflateSync`, `deflateRawSync`, and `gzipSync` accept default options or an inline `{ level: n }` with an integer literal from `-1` through `9`. Other compression options and runtime-valued levels remain fenced.
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
"schemaVersion": 3,
|
||||
"nodeVersion": "24.15.0",
|
||||
"nodeCommit": "848430679556aed0bd073f2bc263331ad84fa119",
|
||||
"artifactVersion": "413a7021676b19ceaf47",
|
||||
"artifactVersion": "13f2c3f789ea7a8500d1",
|
||||
"rowCount": 3662
|
||||
}
|
||||
|
||||
@@ -842,9 +842,9 @@
|
||||
"apiEntries": 119,
|
||||
"static": {
|
||||
"supported": 0,
|
||||
"partial": 25,
|
||||
"partial": 27,
|
||||
"refused": 0,
|
||||
"not-implemented": 94,
|
||||
"not-implemented": 92,
|
||||
"by-design": 0,
|
||||
"unreviewed": 0,
|
||||
"not-applicable": 0
|
||||
@@ -65658,9 +65658,9 @@
|
||||
"anchor": "processgetbuiltinmoduleid",
|
||||
"nodeStability": null,
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -67734,9 +67734,9 @@
|
||||
"anchor": "",
|
||||
"nodeStability": null,
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"detail": "No static compiler lowering is registered for this API yet.",
|
||||
"verification": "registry-gap"
|
||||
"status": "partial",
|
||||
"detail": "Implemented for the documented scriptc module-loader subset.",
|
||||
"verification": "test-backed"
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"tiers": {
|
||||
"static": {
|
||||
"replace-refusal": 47,
|
||||
"verify-gap": 2570,
|
||||
"audit-partial": 595,
|
||||
"verify-gap": 2568,
|
||||
"audit-partial": 597,
|
||||
"classify": 2,
|
||||
"implement": 81
|
||||
},
|
||||
@@ -71250,12 +71250,15 @@
|
||||
"priority": "normal",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:process",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "compiler-feature:process.process.getBuiltinModule",
|
||||
"tests": [
|
||||
"tests/corpus/process-builtin-values.js",
|
||||
"packages/compiler/test/process-builtin-values.test.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -73852,12 +73855,14 @@
|
||||
"priority": "normal",
|
||||
"tiers": {
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"action": "verify-gap",
|
||||
"verification": "registry-gap",
|
||||
"confidence": "low",
|
||||
"source": "compiler-unmatched:process",
|
||||
"tests": []
|
||||
"status": "partial",
|
||||
"action": "audit-partial",
|
||||
"verification": "test-backed",
|
||||
"confidence": "high",
|
||||
"source": "compiler-feature:process.versions",
|
||||
"tests": [
|
||||
"tests/corpus/process-versions-storage.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
|
||||
@@ -915,9 +915,9 @@
|
||||
"apiEntries": 119,
|
||||
"static": {
|
||||
"supported": 0,
|
||||
"partial": 25,
|
||||
"partial": 27,
|
||||
"refused": 0,
|
||||
"not-implemented": 94,
|
||||
"not-implemented": 92,
|
||||
"by-design": 0,
|
||||
"unreviewed": 0,
|
||||
"not-applicable": 0
|
||||
@@ -86847,13 +86847,16 @@
|
||||
"status": "partial",
|
||||
"evidence": "derived:descendants",
|
||||
"tests": [
|
||||
"packages/compiler/test/process-builtin-values.test.ts",
|
||||
"tests/corpus/2314-process-introspection.ts",
|
||||
"tests/corpus/2941-process-exit-code.ts",
|
||||
"tests/corpus/2942-process-exit-code-override.ts",
|
||||
"tests/corpus/2943-process-exit-code-invalid.ts",
|
||||
"tests/corpus/2944-process-exit-code-wrap.ts",
|
||||
"tests/corpus/2946-child-fork-ipc/main.ts",
|
||||
"tests/corpus/990-process-basics.ts"
|
||||
"tests/corpus/990-process-basics.ts",
|
||||
"tests/corpus/process-builtin-values.js",
|
||||
"tests/corpus/process-versions-storage.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
@@ -87718,8 +87721,12 @@
|
||||
"anchor": "processgetbuiltinmoduleid",
|
||||
"nodeStability": null,
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:process"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:process.process.getBuiltinModule",
|
||||
"tests": [
|
||||
"tests/corpus/process-builtin-values.js",
|
||||
"packages/compiler/test/process-builtin-values.test.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "not-implemented",
|
||||
@@ -89880,8 +89887,11 @@
|
||||
"anchor": "",
|
||||
"nodeStability": null,
|
||||
"static": {
|
||||
"status": "not-implemented",
|
||||
"evidence": "compiler-unmatched:process"
|
||||
"status": "partial",
|
||||
"evidence": "compiler-feature:process.versions",
|
||||
"tests": [
|
||||
"tests/corpus/process-versions-storage.ts"
|
||||
]
|
||||
},
|
||||
"dynamic": {
|
||||
"status": "partial",
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
"node-builtin.path": ["tests/corpus/957-builtins-namespace.ts", "tests/corpus/2915-path-function-values.ts", "tests/corpus/2916-path-function-values-cjs.ts", "tests/corpus/2917-builtin-callable-widths.ts", "tests/corpus/2918-builtin-callable-widths-cjs.ts"],
|
||||
"node-builtin.perf_hooks": ["tests/corpus/957-builtins-namespace.ts"],
|
||||
"node-builtin.process": ["tests/corpus/990-process-basics.ts", "tests/corpus/2314-process-introspection.ts"],
|
||||
"node-builtin.process.getBuiltinModule": ["tests/corpus/process-builtin-values.js", "packages/compiler/test/process-builtin-values.test.ts"],
|
||||
"node-builtin.process.versions": ["tests/corpus/process-versions-storage.ts"],
|
||||
"node-builtin.process.rows": ["tests/corpus/2992-stream-rows.ts", "tests/harness/terminal-geometry.test.ts"],
|
||||
"node-builtin.process.columns": ["tests/corpus/1448-stream-columns.ts", "tests/harness/terminal-geometry.test.ts"],
|
||||
"node-builtin.process.exitCode": ["tests/corpus/2941-process-exit-code.ts", "tests/corpus/2942-process-exit-code-override.ts", "tests/corpus/2943-process-exit-code-invalid.ts", "tests/corpus/2944-process-exit-code-wrap.ts"],
|
||||
@@ -83,6 +85,8 @@
|
||||
"stdlib.abort": ["tests/harness/fetch-conformance.test.ts"]
|
||||
},
|
||||
"features": [
|
||||
{ "chapter": "process", "signatures": ["`process.getBuiltinModule(id)`"], "status": "partial", "evidence": ["tests/corpus/process-builtin-values.js", "packages/compiler/test/process-builtin-values.test.ts"] },
|
||||
{ "chapter": "process", "signatures": ["`versions` Type: {Object}"], "status": "partial", "evidence": ["tests/corpus/process-versions-storage.ts"] },
|
||||
{ "chapter": "http", "signatures": ["Class: `http.ClientRequest`", "Class: `http.Server`", "Class: `http.ServerResponse`", "Class: `http.IncomingMessage`"], "status": "partial", "evidence": ["tests/corpus/2981-http-static-events.ts", "tests/corpus/2976-http-static-incoming-state.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ClientRequest`", "signatures": ["`request.setSocketKeepAlive([enable][, initialDelay])`", "`request.setTimeout(timeout[, callback])`", "`destroyed` Type: {boolean}", "Event: `'timeout'`"], "status": "partial", "evidence": ["tests/corpus/2978-http-static-client-timeout.ts", "tests/corpus/2987-http-static-timeout-errors.ts"] },
|
||||
{ "chapter": "http", "parent": "Class: `http.ClientRequest`", "signatures": ["`request.abort()`", "`aborted` Type: {boolean}", "Event: `'abort'`"], "status": "partial", "evidence": ["tests/corpus/2988-http-static-client-abort.ts"] },
|
||||
|
||||
+9
-8
@@ -24,6 +24,11 @@
|
||||
* friends; reads answer `string | undefined`), errno/syscall/path
|
||||
* typecheck and fence per member. */
|
||||
declare namespace NodeJS {
|
||||
interface ProcessVersions {
|
||||
readonly node: string;
|
||||
readonly openssl?: string;
|
||||
readonly [name: string]: string | undefined;
|
||||
}
|
||||
/* The process introspection records — named interfaces so the type
|
||||
* mapper interns their record shapes (the RemoteInfo pattern; the
|
||||
* names match @types/node's, so the mappings hold when it adopts). */
|
||||
@@ -163,19 +168,15 @@ declare module "console" {
|
||||
* (`kill ESRCH`/`kill EPERM` Errors, TypeErrors for unknown signals and
|
||||
* non-int32 pids). */
|
||||
declare var process: {
|
||||
getBuiltinModule(id: string): unknown;
|
||||
argv: string[];
|
||||
platform: string;
|
||||
/* The binary's OWN architecture ("arm64", "x64") — Node's answer for
|
||||
* its own build on the same machine. */
|
||||
readonly arch: string;
|
||||
/* versions.node is the runtime's Node COMPATIBILITY TARGET — no Node
|
||||
* exists under a compiled binary (SEMANTICS.md divergence 60); the
|
||||
* other components @types/node lists (v8, openssl, ...) do not exist
|
||||
* here. openssl and sqlite are DECLARED (optional, so absence reads
|
||||
* undefined) and LOWER to undefined — the honest capability probe
|
||||
* (`Boolean(process.versions.openssl)`) answers false: no OpenSSL and
|
||||
* no SQLite ship in a scriptc binary. Other members fence per site. */
|
||||
readonly versions: { readonly node: string; readonly openssl?: string; readonly sqlite?: string };
|
||||
/* Stable native dictionary. node and openssl name compatibility targets;
|
||||
* components absent from the runtime have no entries. */
|
||||
readonly versions: NodeJS.ProcessVersions;
|
||||
/* The build-configuration snapshot Node exposes from its gyp config.
|
||||
* A scriptc binary has no V8 and no gyp, so `variables` answers the
|
||||
* honest capability record (v8_enable_i18n_support: 0 — no ICU; asan
|
||||
|
||||
@@ -596,7 +596,7 @@ function emitArgPackAndTrampolinePrologue(
|
||||
if (value === undefined) {
|
||||
lines.push(` scr_bytes_release(sc_value);`);
|
||||
} else if (value.kind === "dyn") {
|
||||
lines.push(` ScrDyn *sc_result = scr_dyn_new_bytes_copy(sc_value);`, ` scr_bytes_release(sc_value);`);
|
||||
lines.push(` ScrDyn *sc_result = scr_dyn_new_bytes(sc_value);`, ` scr_bytes_release(sc_value);`);
|
||||
callTypes.push("ScrDyn *");
|
||||
callArgs.push("sc_result");
|
||||
} else if (value.kind === "bytes" && value.elem === "u8") {
|
||||
@@ -655,7 +655,7 @@ function emitArgPackAndTrampolinePrologue(
|
||||
lines.push(` scr_bytes_release(sc_value);`);
|
||||
} else if (value.kind === "dyn") {
|
||||
lines.push(
|
||||
` ScrDyn *sc_result = sc_value ? scr_dyn_new_bytes_copy(sc_value) : scr_dyn_undefined();`,
|
||||
` ScrDyn *sc_result = sc_value ? scr_dyn_new_bytes(sc_value) : scr_dyn_undefined();`,
|
||||
` scr_bytes_release(sc_value);`,
|
||||
);
|
||||
callTypes.push("ScrDyn *");
|
||||
@@ -1373,7 +1373,7 @@ export function streamDataThunkFor(emitter: CEmitter, cbT: IrType): string {
|
||||
passed.push("scr_str_retain(sc_s)");
|
||||
} else {
|
||||
// dyn: box by runtime tag — the JS lane's adapter parameter.
|
||||
body.push(` ScrDyn *sc_d = sc_b ? scr_dyn_new_buffer_copy(sc_b) : scr_dyn_new_str(sc_s);`);
|
||||
body.push(` ScrDyn *sc_d = sc_b ? scr_dyn_new_buffer(sc_b) : scr_dyn_new_str(sc_s);`);
|
||||
passed.push("sc_d");
|
||||
}
|
||||
const sigParams = ["ScrClosure *", ...cbT.params.map((q) => cType(q).trim())].join(", ");
|
||||
@@ -1462,7 +1462,7 @@ export function streamCbThunkFor(emitter: CEmitter, kind: "r" | "w" | "f" | "d"
|
||||
// boxes the retained stream).
|
||||
if (p.kind === "dyn") {
|
||||
if (isChunkPos) {
|
||||
passed.push(`scr_dyn_new_buffer_copy(sc_chunk)`);
|
||||
passed.push(`scr_dyn_new_buffer(sc_chunk)`);
|
||||
} else if (isEncPos) {
|
||||
body.push(
|
||||
` ScrStr *sc_encs = scr_str_new("buffer", 6);`,
|
||||
|
||||
@@ -2158,6 +2158,8 @@ function emitContainerExpr(
|
||||
// 0 for owners, the view's offset into its owner for a
|
||||
// DataView. Never throws.
|
||||
return emitter.newTemp(e.type, `scr_bytes_byte_offset(${r.name})`);
|
||||
case "buffer":
|
||||
return emitter.newTemp(e.type, `scr_array_buffer_from_bytes(${r.name})`);
|
||||
case "dataViewNew": {
|
||||
// new DataView(x.buffer, byteOffset?, byteLength?) — receiver
|
||||
// is x itself (the frontend peeled `.buffer`). Omitted offset
|
||||
@@ -4446,6 +4448,8 @@ function emitDynamicLibCall(state: LibCallState): Temp {
|
||||
// member retains the value in); throws Node's TypeErrors on
|
||||
// non-object receivers (may-throw seed set).
|
||||
return finish(`scr_dyn_key_set(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "dyn.keySetComputed":
|
||||
return finish(`scr_dyn_key_set_computed(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "dyn.keyDelete":
|
||||
return finish(`scr_dyn_key_delete(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "dyn.globalSymbolGet":
|
||||
@@ -4495,6 +4499,8 @@ function emitDynamicLibCall(state: LibCallState): Temp {
|
||||
return finish(`scr_dyn_add(${arg(0)}, ${arg(1)})`);
|
||||
case "dyn.proxyNew":
|
||||
return finish(`scr_dyn_proxy_new(${arg(0)}, ${arg(1)})`);
|
||||
case "global.native":
|
||||
return finish(`scr_global_native(${arg(0)})`);
|
||||
case "global.undefRead":
|
||||
// A declare-d const nothing defines: Node's catchable
|
||||
// ReferenceError at the access (always throws — the typed
|
||||
@@ -4505,6 +4511,28 @@ function emitDynamicLibCall(state: LibCallState): Temp {
|
||||
);
|
||||
case "dyn.this":
|
||||
return finish(`scr_dyn_this_get()`);
|
||||
case "arrayBuffer.new":
|
||||
return finish(`scr_array_buffer_new(${arg(0)})`);
|
||||
case "arrayBuffer.is":
|
||||
return finish(`scr_array_buffer_is(${arg(0)})`);
|
||||
case "arrayBuffer.isView":
|
||||
return finish(`scr_array_buffer_is_view(${arg(0)})`);
|
||||
case "arrayBuffer.byteLengthGetter":
|
||||
return finish(`scr_array_buffer_byte_length_getter()`);
|
||||
case "arrayBuffer.byteLengthDescriptor":
|
||||
return finish(`scr_array_buffer_byte_length_descriptor(${arg(0)})`);
|
||||
case "arrayBuffer.viewU8":
|
||||
return finish(`scr_array_buffer_view_u8(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "arrayBuffer.viewU32":
|
||||
return finish(`scr_array_buffer_view_u32(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "arrayBuffer.viewI32":
|
||||
return finish(`scr_array_buffer_view_i32(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "arrayBuffer.viewF32":
|
||||
return finish(`scr_array_buffer_view_f32(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "arrayBuffer.viewF64":
|
||||
return finish(`scr_array_buffer_view_f64(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "arrayBuffer.viewDV":
|
||||
return finish(`scr_array_buffer_view_dv(${arg(0)}, ${arg(1)}, ${arg(2)})`);
|
||||
case "dyn.objKeys":
|
||||
return finish(`scr_dyn_obj_keys(${arg(0)})`);
|
||||
case "dyn.forInKeys":
|
||||
@@ -5382,6 +5410,8 @@ function emitPrimitiveLibCall(state: LibCallState): Temp {
|
||||
return finish(`scr_num_same_value(${arg(0)}, ${arg(1)})`);
|
||||
// Intl.NumberFormat("en-US").format / toLocaleString("en-US")
|
||||
// with default options (scr_lib.c). +1 string; no throw.
|
||||
case "intl.segmenterNew":
|
||||
return finish(`scr_intl_segmenter_new()`);
|
||||
case "intl.numFormatEnUs":
|
||||
return finish(`scr_intl_num_format_en_us(${arg(0)})`);
|
||||
// The URL surface (scr_url.c): construction and the two
|
||||
@@ -5685,6 +5715,8 @@ function emitCryptoBytesLibCall(state: LibCallState): Temp {
|
||||
// leniently (never throws), concat copies its borrowed list.
|
||||
case "buffer.fromStr":
|
||||
return finish(`scr_bytes_from_str(${arg(0)}, ${arg(1)})`);
|
||||
case "buffer.brand":
|
||||
return finish(`scr_bytes_as_buffer(${arg(0)})`);
|
||||
case "buffer.fromDyn":
|
||||
return finish(`scr_buffer_from_dyn(${arg(0)}, ${arg(1)})`);
|
||||
case "buffer.concat":
|
||||
@@ -8091,6 +8123,14 @@ function emitProcessLibCall(state: LibCallState): Temp {
|
||||
}
|
||||
case "process.arch":
|
||||
return finish(`scr_process_arch()`);
|
||||
case "process.versions":
|
||||
return finish(`scr_process_versions()`);
|
||||
case "process.builtinId":
|
||||
return finish(`scr_process_builtin_id(${arg(0)}, ${arg(1)})`);
|
||||
case "process.builtinModule":
|
||||
return finish(`scr_process_builtin_module(${arg(0)}, ${arg(1)})`);
|
||||
case "process.builtinUnsupported":
|
||||
return finish(`scr_process_builtin_unsupported(${arg(0)}, ${arg(1)})`);
|
||||
case "process.versionsNode":
|
||||
return finish(`scr_process_versions_node()`);
|
||||
case "process.versionsOpenssl":
|
||||
@@ -9120,6 +9160,7 @@ function emitLibCallExpr(emitter: CEmitter, e: LibCallExpr): Temp {
|
||||
case "island":
|
||||
case "json":
|
||||
return emitWebLibCall(state);
|
||||
case "arrayBuffer":
|
||||
case "dyn":
|
||||
case "global":
|
||||
return emitDynamicLibCall(state);
|
||||
|
||||
@@ -1086,21 +1086,7 @@ export function jsonWriteHelper(emitter: CEmitter, t: IrType): string {
|
||||
d.push(` * loud not-supported ladder (scr_json.c). */`);
|
||||
d.push(` return scr_dyn_handle_key_get(d, k);`);
|
||||
d.push(` }`);
|
||||
d.push(` if (d->kind == SCR_DYN_BYTES) {`);
|
||||
d.push(` /* Buffer-shaped dyn (a stream's 'data' chunk in the JS lane):`);
|
||||
d.push(` * .length and canonical-index byte reads answer like Node. */`);
|
||||
d.push(` if (k->len == 6 && memcmp(k->data, "length", 6) == 0) {`);
|
||||
d.push(` return scr_dyn_new_num((double)d->v.bytes->len);`);
|
||||
d.push(` }`);
|
||||
d.push(` if (k->len > 0 && !(k->len > 1 && k->data[0] == '0')) {`);
|
||||
d.push(` size_t idx = 0; bool digits = true;`);
|
||||
d.push(` for (size_t i = 0; i < k->len; i++) {`);
|
||||
d.push(` if (k->data[i] < '0' || k->data[i] > '9' || idx > (SIZE_MAX - 9) / 10) { digits = false; break; }`);
|
||||
d.push(` idx = idx * 10 + (size_t)(k->data[i] - '0');`);
|
||||
d.push(` }`);
|
||||
d.push(` if (digits && idx < d->v.bytes->len) return scr_dyn_new_num((double)d->v.bytes->data[idx]);`);
|
||||
d.push(` }`);
|
||||
d.push(` }`);
|
||||
d.push(` if (d->kind == SCR_DYN_BYTES) return scr_dyn_bytes_key_get(d, k);`);
|
||||
d.push(` if (d->kind == SCR_DYN_FUNC) {`);
|
||||
d.push(` /* own props (defineProperties writes), then name/length —`);
|
||||
d.push(` * the function-instance members test/common copies. */`);
|
||||
@@ -1254,11 +1240,10 @@ export function jsonWriteHelper(emitter: CEmitter, t: IrType): string {
|
||||
d.push(` return scr_dyn_retain((ScrDyn *)d);`);
|
||||
break;
|
||||
case "bytes":
|
||||
// `u as Uint8Array`: kind check, then a fresh COPY out (the
|
||||
// boundary's aliasing stance in both directions).
|
||||
// `u as Uint8Array`: kind check, then retain the shared view.
|
||||
if (t.elem !== "u8") throw new InternalCompilerError(`emitter bug: dynCheck of bytes<${t.elem}>`);
|
||||
d.push(` if (d->kind != SCR_DYN_BYTES) { scr_dyn_check_fail(path, ${want}, d); return NULL; }`);
|
||||
d.push(` return scr_dyn_bytes_copy_out(d);`);
|
||||
d.push(` return scr_dyn_bytes_unbox(d);`);
|
||||
break;
|
||||
case "object":
|
||||
// The %Error extraction (an instanceof-Error narrow on unknown):
|
||||
@@ -1570,10 +1555,10 @@ export function jsonWriteHelper(emitter: CEmitter, t: IrType): string {
|
||||
d.push(` return ${dynFuncBoxHelper(emitter, t)}(v, NULL);`);
|
||||
break;
|
||||
case "bytes":
|
||||
// bytes<u8> → the checked-dynamic tree's bytes kind, payload COPIED (the boundary
|
||||
// bytes<u8> → a retained native view (the boundary
|
||||
// stance; stdin chunks into unknown-typed helpers).
|
||||
if (t.elem !== "u8") throw new InternalCompilerError(`emitter bug: to-dyn of bytes<${t.elem}>`);
|
||||
d.push(` return scr_dyn_new_bytes_copy(v);`);
|
||||
d.push(` return scr_dyn_new_bytes(v);`);
|
||||
break;
|
||||
case "record": {
|
||||
const shape = emitter.recordsById.get(t.shapeId);
|
||||
|
||||
@@ -783,12 +783,12 @@ export class LlDyn {
|
||||
break;
|
||||
}
|
||||
case "bytes": {
|
||||
// `u as Uint8Array`: kind check, then a fresh COPY out.
|
||||
// `u as Uint8Array`: kind check, then retain the shared view.
|
||||
if (t.elem !== "u8") throw new InternalCompilerError(`llvm emitter bug: dynCheck of bytes<${t.elem}>`);
|
||||
requireKind(DYN_KIND.BYTES, "dc");
|
||||
host.declare(`declare ptr @scr_dyn_bytes_copy_out(ptr)`);
|
||||
host.declare(`declare ptr @scr_dyn_bytes_unbox(ptr)`);
|
||||
const r = B.tmp();
|
||||
B.line(`${r} = call ptr @scr_dyn_bytes_copy_out(ptr %d)`);
|
||||
B.line(`${r} = call ptr @scr_dyn_bytes_unbox(ptr %d)`);
|
||||
B.terminate(`ret ptr ${r}`);
|
||||
break;
|
||||
}
|
||||
@@ -1324,9 +1324,9 @@ export class LlDyn {
|
||||
}
|
||||
case "bytes": {
|
||||
if (t.elem !== "u8") throw new InternalCompilerError(`llvm emitter bug: to-dyn of bytes<${t.elem}>`);
|
||||
host.declare(`declare ptr @scr_dyn_new_bytes_copy(ptr)`);
|
||||
host.declare(`declare ptr @scr_dyn_new_bytes(ptr)`);
|
||||
const r = B.tmp();
|
||||
B.line(`${r} = call ptr @scr_dyn_new_bytes_copy(ptr %v)`);
|
||||
B.line(`${r} = call ptr @scr_dyn_new_bytes(ptr %v)`);
|
||||
B.terminate(`ret ptr ${r}`);
|
||||
break;
|
||||
}
|
||||
@@ -2423,45 +2423,10 @@ export class LlDyn {
|
||||
const lNext = B.newLabel("kg.n");
|
||||
B.condBr(isB, lB, lNext);
|
||||
B.startBlock(lB);
|
||||
host.declare(`declare ptr @scr_dyn_new_num(double)`);
|
||||
const bts = this.payloadOf(B, "%d", "ptr");
|
||||
const blenp = B.tmp();
|
||||
const blen = B.tmp();
|
||||
B.line(`${blenp} = getelementptr inbounds i8, ptr ${bts}, i64 ${this.abiOffset(8, 4)} ; ->len`);
|
||||
B.line(`${blen} = load ${host.sizeType}, ptr ${blenp}`);
|
||||
const lLen = B.newLabel("kg.bl");
|
||||
const lIdx = B.newLabel("kg.bi");
|
||||
B.condBr(lenHit, lLen, lIdx);
|
||||
B.startBlock(lLen);
|
||||
const lenD = B.tmp();
|
||||
const r0 = B.tmp();
|
||||
B.line(`${lenD} = uitofp ${host.sizeType} ${blen} to double`);
|
||||
B.line(`${r0} = call ptr @scr_dyn_new_num(double ${lenD})`);
|
||||
B.terminate(`ret ptr ${r0}`);
|
||||
B.startBlock(lIdx);
|
||||
const inRange = B.tmp();
|
||||
const hit = B.tmp();
|
||||
B.line(`${inRange} = icmp ult ${host.sizeType} ${idx}, ${blen}`);
|
||||
B.line(`${hit} = and i1 ${digits}, ${inRange}`);
|
||||
const lHit = B.newLabel("kg.bh");
|
||||
const lMiss = B.newLabel("kg.bm");
|
||||
B.condBr(hit, lHit, lMiss);
|
||||
B.startBlock(lHit);
|
||||
const bdatap = B.tmp();
|
||||
const bdata = B.tmp();
|
||||
B.line(`${bdatap} = getelementptr inbounds i8, ptr ${bts}, i64 ${this.abiOffset(24, 12)} ; ->data`);
|
||||
B.line(`${bdata} = load ptr, ptr ${bdatap}`);
|
||||
const bp = B.tmp();
|
||||
const bv = B.tmp();
|
||||
const bd = B.tmp();
|
||||
const r1 = B.tmp();
|
||||
B.line(`${bp} = getelementptr inbounds i8, ptr ${bdata}, ${host.sizeType} ${idx}`);
|
||||
B.line(`${bv} = load i8, ptr ${bp}`);
|
||||
B.line(`${bd} = uitofp i8 ${bv} to double`);
|
||||
B.line(`${r1} = call ptr @scr_dyn_new_num(double ${bd})`);
|
||||
B.terminate(`ret ptr ${r1}`);
|
||||
B.startBlock(lMiss);
|
||||
retainUndef();
|
||||
host.declare(`declare ptr @scr_dyn_bytes_key_get(ptr, ptr)`);
|
||||
const result = B.tmp();
|
||||
B.line(`${result} = call ptr @scr_dyn_bytes_key_get(ptr %d, ptr %k)`);
|
||||
B.terminate(`ret ptr ${result}`);
|
||||
B.startBlock(lNext);
|
||||
}
|
||||
// FUNC: own props (defineProperties writes), then name/length.
|
||||
|
||||
@@ -1140,7 +1140,7 @@ export class LlEmitter {
|
||||
// typed-array access GEPs through this directly: the IR type already
|
||||
// fixes elem, so the hot path needs neither a runtime kind load nor
|
||||
// the generic scr_bytes_get/set call.
|
||||
`%ScrBytes = type { ${this.sizeType}, ${this.sizeType}, i32, ptr, ptr }`,
|
||||
`%ScrBytes = type { ${this.sizeType}, ${this.sizeType}, i32, ptr, ptr, i8 }`,
|
||||
// The capture box { rc, kind, obj_retain, obj_release, obj_trace,
|
||||
// slot } — TDZ reads peek the payload slot (offset 40) directly.
|
||||
`%ScrBox = type { ${this.sizeType}, i32, ptr, ptr, ptr, i64 }`,
|
||||
|
||||
@@ -553,6 +553,8 @@ export function emitBytesIntrinsic(host: LlvmEmitterContext, e: IrExpr & { kind:
|
||||
false,
|
||||
true,
|
||||
);
|
||||
case "buffer":
|
||||
return call("scr_array_buffer_from_bytes", "ptr (ptr)", `ptr ${r.name}`, true, false);
|
||||
case "byteOffset":
|
||||
return call("scr_bytes_byte_offset", "double (ptr)", `ptr ${r.name}`, false, false);
|
||||
case "dataViewNew":
|
||||
|
||||
@@ -63,14 +63,14 @@ export function streamDataAdapter(host: LlvmEmitterContext, cbT: IrType & { kind
|
||||
d.push(`}`, ``);
|
||||
} else {
|
||||
// dyn: box by runtime tag — the JS lane's adapter parameter.
|
||||
host.declare(`declare ptr @scr_dyn_new_buffer_copy(ptr)`);
|
||||
host.declare(`declare ptr @scr_dyn_new_buffer(ptr)`);
|
||||
host.declare(`declare ptr @scr_dyn_new_str(ptr)`);
|
||||
d.push(
|
||||
` %dslot = alloca ptr`,
|
||||
` %isb = icmp ne ptr %a0, null`,
|
||||
` br i1 %isb, label %buf, label %str`,
|
||||
`buf:`,
|
||||
` %db = call ptr @scr_dyn_new_buffer_copy(ptr %a0)`,
|
||||
` %db = call ptr @scr_dyn_new_buffer(ptr %a0)`,
|
||||
` store ptr %db, ptr %dslot`,
|
||||
` br label %go`,
|
||||
`str:`,
|
||||
@@ -281,10 +281,10 @@ export function cryptoBytesThunkFor(host: LlvmEmitterContext, cbT: IrType & { ki
|
||||
host.declare(`declare void @scr_bytes_release(ptr)`);
|
||||
d.push(` call void @scr_bytes_release(ptr %value)`);
|
||||
} else if (value.kind === "dyn") {
|
||||
host.declare(`declare ptr @scr_dyn_new_bytes_copy(ptr)`);
|
||||
host.declare(`declare ptr @scr_dyn_new_bytes(ptr)`);
|
||||
host.declare(`declare void @scr_bytes_release(ptr)`);
|
||||
d.push(
|
||||
` %result = call ptr @scr_dyn_new_bytes_copy(ptr %value)`,
|
||||
` %result = call ptr @scr_dyn_new_bytes(ptr %value)`,
|
||||
` call void @scr_bytes_release(ptr %value)`,
|
||||
);
|
||||
passed.push("ptr %result");
|
||||
@@ -360,7 +360,7 @@ export function zlibBytesThunkFor(host: LlvmEmitterContext, cbT: IrType & { kind
|
||||
host.declare(`declare void @scr_bytes_release(ptr)`);
|
||||
d.push(` call void @scr_bytes_release(ptr %value)`);
|
||||
} else if (value.kind === "dyn") {
|
||||
host.declare(`declare ptr @scr_dyn_new_bytes_copy(ptr)`);
|
||||
host.declare(`declare ptr @scr_dyn_new_bytes(ptr)`);
|
||||
host.declare(`declare ptr @scr_dyn_undefined()`);
|
||||
host.declare(`declare void @scr_bytes_release(ptr)`);
|
||||
d.push(
|
||||
@@ -368,7 +368,7 @@ export function zlibBytesThunkFor(host: LlvmEmitterContext, cbT: IrType & { kind
|
||||
` %hasvalue = icmp ne ptr %value, null`,
|
||||
` br i1 %hasvalue, label %value_yes, label %value_no`,
|
||||
`value_yes:`,
|
||||
` %db = call ptr @scr_dyn_new_bytes_copy(ptr %value)`,
|
||||
` %db = call ptr @scr_dyn_new_bytes(ptr %value)`,
|
||||
` call void @scr_bytes_release(ptr %value)`,
|
||||
` store ptr %db, ptr %rslot`,
|
||||
` br label %value_go`,
|
||||
@@ -469,8 +469,8 @@ export function streamCbThunkFor(host: LlvmEmitterContext, kind: "r" | "w" | "f"
|
||||
: (kind === "w" || kind === "t") ? pos === 2 : (kind === "f" || kind === "l") ? pos === 0 : pos === 1;
|
||||
if (p.kind === "dyn") {
|
||||
if (isChunkPos) {
|
||||
host.declare(`declare ptr @scr_dyn_new_buffer_copy(ptr)`);
|
||||
d.push(` %dc${i} = call ptr @scr_dyn_new_buffer_copy(ptr %chunk)`);
|
||||
host.declare(`declare ptr @scr_dyn_new_buffer(ptr)`);
|
||||
d.push(` %dc${i} = call ptr @scr_dyn_new_buffer(ptr %chunk)`);
|
||||
passed.push(`ptr %dc${i}`);
|
||||
} else if (isEncPos) {
|
||||
host.declare(`declare ptr @scr_str_new(ptr, ${host.sizeType})`);
|
||||
|
||||
@@ -264,6 +264,7 @@ export function emitLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue {
|
||||
case "rl":
|
||||
case "strdec":
|
||||
return host.emitIoLibCall(e);
|
||||
case "arrayBuffer":
|
||||
case "util":
|
||||
case "bigint":
|
||||
case "crypto":
|
||||
|
||||
@@ -24,6 +24,19 @@ export function emitAlwaysThrowLibCall(
|
||||
}
|
||||
|
||||
export const LIB_FN_SYMS: Record<string, string> = {
|
||||
"intl.segmenterNew": "scr_intl_segmenter_new",
|
||||
"arrayBuffer.new": "scr_array_buffer_new",
|
||||
"arrayBuffer.is": "scr_array_buffer_is",
|
||||
"arrayBuffer.isView": "scr_array_buffer_is_view",
|
||||
"arrayBuffer.byteLengthGetter": "scr_array_buffer_byte_length_getter",
|
||||
"arrayBuffer.byteLengthDescriptor": "scr_array_buffer_byte_length_descriptor",
|
||||
"arrayBuffer.viewU8": "scr_array_buffer_view_u8",
|
||||
"arrayBuffer.viewU32": "scr_array_buffer_view_u32",
|
||||
"arrayBuffer.viewI32": "scr_array_buffer_view_i32",
|
||||
"arrayBuffer.viewF32": "scr_array_buffer_view_f32",
|
||||
"arrayBuffer.viewF64": "scr_array_buffer_view_f64",
|
||||
"arrayBuffer.viewDV": "scr_array_buffer_view_dv",
|
||||
|
||||
"util.parseArgs": "scr_util_parse_args",
|
||||
"math.maxArr": "scr_math_max_arr",
|
||||
"math.minArr": "scr_math_min_arr",
|
||||
@@ -119,6 +132,11 @@ export const LIB_FN_SYMS: Record<string, string> = {
|
||||
"process.execPath": "scr_process_exec_path",
|
||||
"process.arch": "scr_process_arch",
|
||||
"process.versionsNode": "scr_process_versions_node",
|
||||
"process.versions": "scr_process_versions",
|
||||
"process.builtinId": "scr_process_builtin_id",
|
||||
"global.native": "scr_global_native",
|
||||
"process.builtinModule": "scr_process_builtin_module",
|
||||
"process.builtinUnsupported": "scr_process_builtin_unsupported",
|
||||
"process.versionsOpenssl": "scr_process_versions_openssl",
|
||||
"process.umask": "scr_process_umask",
|
||||
"process.uptime": "scr_process_uptime",
|
||||
@@ -247,6 +265,7 @@ export const LIB_FN_SYMS: Record<string, string> = {
|
||||
// leniently (never throws), concat copies its borrowed list; the sync
|
||||
// fs Buffer pair and zlib.inflateSync ride the may-throw check.
|
||||
"buffer.fromStr": "scr_bytes_from_str",
|
||||
"buffer.brand": "scr_bytes_as_buffer",
|
||||
"buffer.fromDyn": "scr_buffer_from_dyn",
|
||||
"buffer.concat": "scr_bytes_concat",
|
||||
"buffer.concatLen": "scr_bytes_concat_len",
|
||||
@@ -512,6 +531,7 @@ export const LIB_FN_SYMS: Record<string, string> = {
|
||||
"json.parseReviver": "scr_json_parse_reviver",
|
||||
"json.stringifyReplacer": "scr_json_stringify_replacer",
|
||||
"dyn.keySet": "scr_dyn_key_set",
|
||||
"dyn.keySetComputed": "scr_dyn_key_set_computed",
|
||||
"dyn.keyDelete": "scr_dyn_key_delete",
|
||||
"dyn.globalSymbolGet": "scr_dyn_global_symbol_get",
|
||||
"dyn.globalSymbolSet": "scr_dyn_global_symbol_set",
|
||||
|
||||
@@ -81,7 +81,7 @@ function stableTestMemo<T>(
|
||||
return pending;
|
||||
}
|
||||
|
||||
export const EXECUTABLE_RUNTIME_SOURCES = ["scr_number.c", "scr_string.c", "scr_array.c", "scr_bytes.c", "scr_bytes_io.c", "scr_map.c", "scr_closure.c", "scr_ffi.c", "scr_object.c", "scr_union.c", "scr_exception.c", "scr_error.c", "scr_console.c", "scr_lib.c", "scr_path.c", "scr_url.c", "scr_json.c", "scr_async.c", "scr_crypto_async.c", "scr_child.c", "scr_cycle.c"] as const;
|
||||
export const EXECUTABLE_RUNTIME_SOURCES = ["scr_number.c", "scr_string.c", "scr_grapheme.c", "scr_array.c", "scr_bytes.c", "scr_bytes_io.c", "scr_map.c", "scr_closure.c", "scr_ffi.c", "scr_object.c", "scr_union.c", "scr_exception.c", "scr_error.c", "scr_console.c", "scr_lib.c", "scr_path.c", "scr_url.c", "scr_json.c", "scr_node_builtin.c", "scr_async.c", "scr_crypto_async.c", "scr_child.c", "scr_cycle.c"] as const;
|
||||
|
||||
/**
|
||||
* Per-target section-elimination recipe. This belongs beside the native
|
||||
|
||||
@@ -120,6 +120,14 @@ const BYTES_CTORS: Record<string, IrBytesElem | undefined> = {
|
||||
* Null when this isn't a stdlib
|
||||
* typed-array construction. */
|
||||
export function lowerBytesNew(lowerer: Lowerer, expr: ts.NewExpression, symbol: ts.Symbol | null | undefined): IrExpr | null {
|
||||
if (symbol?.name === "ArrayBuffer" && lowerer.isStdlibSymbol(symbol)) {
|
||||
const args = expr.arguments ?? [];
|
||||
if (args.length > 1 || args.some(ts.isSpreadElement)) {
|
||||
lowerer.noLowering("resizable ArrayBuffer construction", expr, "fixed-length ArrayBuffers accept a byte length; resizable storage is not supported yet");
|
||||
}
|
||||
const length = args[0] ? lowerer.coerceInto(args[0], lowerer.lowerExpr(args[0]), DYN) : dynUndefinedExpr(locOf(expr));
|
||||
return { kind: "libCall", fn: "arrayBuffer.new", args: [length], type: DYN, loc: locOf(expr) };
|
||||
}
|
||||
if (symbol && symbol.name === "DataView" && lowerer.isStdlibSymbol(symbol)) {
|
||||
return lowerDataViewNew(lowerer, expr);
|
||||
}
|
||||
@@ -130,6 +138,9 @@ export function lowerBytesNew(lowerer: Lowerer, expr: ts.NewExpression, symbol:
|
||||
const loc = locOf(expr);
|
||||
const args = expr.arguments ?? [];
|
||||
if (args.length === 0) return { kind: "bytesNew", source: null, type, loc };
|
||||
if (args.length >= 2 && args.length <= 3 && !args.some(ts.isSpreadElement)) {
|
||||
return lowerArrayBufferView(lowerer, args, elem, loc);
|
||||
}
|
||||
if (args.length === 1 && !ts.isSpreadElement(args[0]!)) {
|
||||
const argNode = args[0]!;
|
||||
if (ts.isArrayLiteralExpression(argNode) && !argNode.elements.some(ts.isSpreadElement)) {
|
||||
@@ -137,8 +148,7 @@ export function lowerBytesNew(lowerer: Lowerer, expr: ts.NewExpression, symbol:
|
||||
const seed: IrExpr = { kind: "arrayLit", elems, type: arrayOf(F64), loc };
|
||||
return { kind: "bytesNew", source: seed, type, loc };
|
||||
}
|
||||
// The SYNTACTIC `new T(new ArrayBuffer(n))` and `new T(new
|
||||
// SharedArrayBuffer(n))` forms — fresh-buffer construction (the
|
||||
// The SYNTACTIC `new T(new SharedArrayBuffer(n))` form — fresh-buffer construction (the
|
||||
// shared spelling is the Atomics.wait sleep idiom's). The buffer
|
||||
// never exists as a value: n must be a byte-length LITERAL divisible
|
||||
// by the element size (tsc would admit any number; a bad one is
|
||||
@@ -148,12 +158,11 @@ export function lowerBytesNew(lowerer: Lowerer, expr: ts.NewExpression, symbol:
|
||||
// else can ever reference it, so neither sharing (scriptc has no
|
||||
// threads) nor aliasing is observable — SEMANTICS.md documents the
|
||||
// stance. The RESIZABLE form (a maxByteLength options bag) fences by
|
||||
// name: resize needs the buffer to exist as a value, and none does.
|
||||
// name: this erasure has no shared or growable buffer representation.
|
||||
if (
|
||||
ts.isNewExpression(argNode) &&
|
||||
ts.isIdentifier(argNode.expression) &&
|
||||
(argNode.expression.text === "ArrayBuffer" ||
|
||||
argNode.expression.text === "SharedArrayBuffer") &&
|
||||
argNode.expression.text === "SharedArrayBuffer" &&
|
||||
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(argNode.expression) ?? undefined)
|
||||
) {
|
||||
const bufCtor = argNode.expression.text;
|
||||
@@ -161,9 +170,8 @@ export function lowerBytesNew(lowerer: Lowerer, expr: ts.NewExpression, symbol:
|
||||
lowerer.noLowering(
|
||||
`new ${name} over a resizable ${bufCtor}`,
|
||||
argNode,
|
||||
"a maxByteLength options bag makes the buffer resizable, and resizing needs the buffer " +
|
||||
"to exist as a runtime value — no free-standing ArrayBuffer value exists (the buffer here " +
|
||||
"erases into the view): drop the options bag",
|
||||
"a maxByteLength options bag needs growable shared storage; the fixed-length " +
|
||||
"SharedArrayBuffer here erases into the view: drop the options bag",
|
||||
);
|
||||
}
|
||||
const elemSize = elem === "u8" ? 1 : elem === "f64" ? 8 : 4;
|
||||
@@ -225,7 +233,13 @@ export function lowerBytesNew(lowerer: Lowerer, expr: ts.NewExpression, symbol:
|
||||
* array-like semantics separately from constructor length coercion. */
|
||||
export function lowerBytesStaticCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
access: ts.PropertyAccessExpression): IrExpr | null {
|
||||
if (call.questionDotToken || access.questionDotToken || access.name.text !== "from" || !ts.isIdentifier(access.expression)) return null;
|
||||
if (lowerer.chainBlocked(call, access)) return null;
|
||||
if (lowerer.isStdlibGlobal(access.expression, "ArrayBuffer") && access.name.text === "isView") {
|
||||
if (call.arguments.length !== 1 || call.arguments.some(ts.isSpreadElement)) lowerer.noLowering("ArrayBuffer.isView argument count", call);
|
||||
const arg = call.arguments[0]!;
|
||||
return { kind: "libCall", fn: "arrayBuffer.isView", args: [lowerer.coerceInto(arg, lowerer.lowerExpr(arg), DYN)], type: BOOL, loc: locOf(call) };
|
||||
}
|
||||
if (access.name.text !== "from" || !ts.isIdentifier(access.expression)) return null;
|
||||
const symbol = lowerer.resolveValueSymbol(access.expression);
|
||||
const elem = symbol ? own(BYTES_CTORS, symbol.name) : undefined;
|
||||
if (!elem || !lowerer.isStdlibSymbol(symbol ?? undefined)) return null;
|
||||
@@ -240,81 +254,20 @@ export function lowerBytesStaticCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
return { kind: "bytesNew", source: lowerer.coerceInto(node, source, DYN), from: true, type: bytesOf(elem), loc: locOf(call) };
|
||||
}
|
||||
|
||||
/** `new DataView(x.buffer, byteOffset?, byteLength?)` (stdlib provenance).
|
||||
* The first argument must be the SYNTACTIC `.buffer` of a typed-array/
|
||||
* Buffer value — `x.buffer` names x's own storage (scriptc typed arrays
|
||||
* always own it whole, byteOffset 0), so the view construction takes x
|
||||
* itself as the receiver and no ArrayBuffer value ever exists.
|
||||
* byteOffset/byteLength are optional f64s (omitted args OMITTED, like
|
||||
* slice); bad indices THROW Node's RangeErrors catchably. The result is
|
||||
* a true borrowed view: reads and writes through it alias x. */
|
||||
/** Construct a view over the complete branded backing allocation. */
|
||||
function lowerArrayBufferView(lowerer: Lowerer, args: readonly ts.Expression[], elem: IrBytesElem | "dv", loc: SrcLoc): IrExpr {
|
||||
const values = [0, 1, 2].map((index) => {
|
||||
const node = args[index];
|
||||
return node ? lowerer.coerceInto(node, lowerer.lowerExpr(node), DYN) : dynUndefinedExpr(loc);
|
||||
});
|
||||
const fn = { u8: "arrayBuffer.viewU8", u32: "arrayBuffer.viewU32", i32: "arrayBuffer.viewI32", f32: "arrayBuffer.viewF32", f64: "arrayBuffer.viewF64", dv: "arrayBuffer.viewDV" } as const;
|
||||
return { kind: "libCall", fn: fn[elem], args: values, type: elem === "dv" ? BYTES_U8 : bytesOf(elem), loc };
|
||||
}
|
||||
|
||||
function lowerDataViewNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr {
|
||||
const loc = locOf(expr);
|
||||
const args = expr.arguments ?? [];
|
||||
const bufNode = args[0];
|
||||
if (!bufNode || args.length > 3 || args.some(ts.isSpreadElement)) {
|
||||
lowerer.noLowering(
|
||||
`new DataView with ${args.length} arguments`,
|
||||
expr,
|
||||
"supported: new DataView(x.buffer), (x.buffer, byteOffset), or (x.buffer, byteOffset, byteLength)",
|
||||
);
|
||||
}
|
||||
// The FRESH-BUFFER form: `new DataView(new ArrayBuffer(n), ...)` — the
|
||||
// buffer erases into the view (nothing else can ever reference it, so
|
||||
// the aliasing a shared buffer would exhibit is unobservable): the
|
||||
// view's storage is a fresh zero-filled n-byte allocation. n must be a
|
||||
// non-negative integer LITERAL (tsc admits any number; a fractional
|
||||
// one is ToIndex truncation nothing here implements). byteOffset and
|
||||
// byteLength keep their runtime Node-RangeError story. The RESIZABLE
|
||||
// form (a maxByteLength options bag) fences by name.
|
||||
if (
|
||||
ts.isNewExpression(bufNode) &&
|
||||
ts.isIdentifier(bufNode.expression) &&
|
||||
bufNode.expression.text === "ArrayBuffer" &&
|
||||
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(bufNode.expression) ?? undefined)
|
||||
) {
|
||||
if ((bufNode.arguments?.length ?? 0) > 1) {
|
||||
lowerer.noLowering(
|
||||
"new DataView over a resizable ArrayBuffer",
|
||||
bufNode,
|
||||
"a maxByteLength options bag makes the buffer resizable, and resizing needs the buffer " +
|
||||
"to exist as a runtime value — no free-standing ArrayBuffer value exists (the buffer here " +
|
||||
"erases into the view): drop the options bag",
|
||||
);
|
||||
}
|
||||
const lenArg = bufNode.arguments?.length === 1 ? bufNode.arguments[0] : undefined;
|
||||
const lenT = lenArg ? lowerer.typeOf(lenArg) : null;
|
||||
const byteLen = lenT?.isNumberLiteralType() ? lenT.value : null;
|
||||
if (byteLen === null || !Number.isInteger(byteLen) || byteLen < 0) {
|
||||
lowerer.noLowering(
|
||||
"new DataView over this ArrayBuffer",
|
||||
bufNode,
|
||||
"the byte length must be a non-negative integer literal — new DataView(new ArrayBuffer(8))",
|
||||
);
|
||||
}
|
||||
const count: IrExpr = { kind: "numLit", value: byteLen, type: F64, loc };
|
||||
const receiver: IrExpr = { kind: "bytesNew", source: count, type: BYTES_U8, loc };
|
||||
const idxArgs = args.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
|
||||
return { kind: "bytesIntrinsic", method: "dataViewNew", receiver, args: idxArgs, type: BYTES_U8, loc };
|
||||
}
|
||||
const hint =
|
||||
"views compile over a typed array's own storage — new DataView(x.buffer, byteOffset?, byteLength?) " +
|
||||
"where x is a Uint8Array/Uint32Array/Float32Array/Float64Array/Buffer value — or a fresh buffer erased into " +
|
||||
"the view: new DataView(new ArrayBuffer(n), ...); free-standing ArrayBuffers have no representation";
|
||||
if (!ts.isPropertyAccessExpression(bufNode) || bufNode.name.text !== "buffer" || bufNode.questionDotToken) {
|
||||
lowerer.noLowering("new DataView over this buffer expression", bufNode, hint);
|
||||
}
|
||||
const srcIr = lowerer.mapTypeOf(lowerer.typeOf(bufNode.expression));
|
||||
if (srcIr?.kind !== "bytes" || !lowerer.isStdlibMember(bufNode)) {
|
||||
lowerer.noLowering(
|
||||
`new DataView over '.buffer' of a '${lowerer.checker.typeToString(lowerer.typeOf(bufNode.expression))}'`,
|
||||
bufNode,
|
||||
hint,
|
||||
);
|
||||
}
|
||||
const receiver = lowerer.lowerExpr(bufNode.expression);
|
||||
const idxArgs = args.slice(1).map((a) => lowerer.lowerExprExpecting(a, F64));
|
||||
return { kind: "bytesIntrinsic", method: "dataViewNew", receiver, args: idxArgs, type: BYTES_U8, loc };
|
||||
if (!args.length || args.length > 3 || args.some(ts.isSpreadElement)) lowerer.noLowering("DataView constructor argument count", expr);
|
||||
return lowerArrayBufferView(lowerer, args, "dv", locOf(expr));
|
||||
}
|
||||
|
||||
/** Method calls on typed-array/Buffer receivers: slice (copy), subarray
|
||||
@@ -968,6 +921,16 @@ function knownBufferProducer(lowerer: Lowerer, source: ts.Expression, seen = new
|
||||
}
|
||||
|
||||
export function lowerBufferStaticCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
access: ts.PropertyAccessExpression,): IrExpr | null {
|
||||
const value = lowerBufferStaticValue(lowerer, call, access);
|
||||
// Every byte-valued Buffer factory creates a distinct view. Preserve its
|
||||
// brand even when stored as Uint8Array or passed through checked values.
|
||||
return value?.type.kind === "bytes"
|
||||
? { kind: "libCall", fn: "buffer.brand", args: [value], type: value.type, loc: value.loc }
|
||||
: value;
|
||||
}
|
||||
|
||||
function lowerBufferStaticValue(lowerer: Lowerer, call: ts.CallExpression,
|
||||
access: ts.PropertyAccessExpression,): IrExpr | null {
|
||||
if (call.questionDotToken || access.questionDotToken) return null;
|
||||
if (!lowerer.isStdlibGlobal(access.expression, "Buffer")) return null;
|
||||
@@ -975,6 +938,10 @@ export function lowerBufferStaticCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
const loc = locOf(call);
|
||||
const args = call.arguments;
|
||||
if (member === "from") {
|
||||
if (args.length >= 1 && args.length <= 3 && !args.some(ts.isSpreadElement) &&
|
||||
lowerer.typeOf(args[0]!).getSymbol()?.name === "ArrayBuffer") {
|
||||
return lowerArrayBufferView(lowerer, args, "u8", loc);
|
||||
}
|
||||
// Buffer.from(x.buffer[, byteOffset[, length]]): a u8 VIEW sharing
|
||||
// x's storage (Node shares the ArrayBuffer; length is in BYTES).
|
||||
// The first argument must be the SYNTACTIC `.buffer` of a typed
|
||||
@@ -1032,8 +999,8 @@ export function lowerBufferStaticCall(lowerer: Lowerer, call: ts.CallExpression,
|
||||
"Buffer.from with this argument shape",
|
||||
call,
|
||||
"supported: Buffer.from(string, encoding?) with a literal encoding, Buffer.from(u8Array) — a copy — " +
|
||||
"Buffer.from(number[]), or Buffer.from(x.buffer, byteOffset?, length?) — a view sharing x's " +
|
||||
"storage (no free-standing ArrayBuffer value exists; narrow unions first)",
|
||||
"Buffer.from(number[]), or Buffer.from(arrayBuffer, byteOffset?, length?) — a view sharing " +
|
||||
"the buffer's storage; narrow unions first",
|
||||
);
|
||||
}
|
||||
if (member === "alloc" || member === "allocUnsafe") {
|
||||
|
||||
@@ -1124,6 +1124,16 @@ export function lowerObjectLiteral(lowerer: Lowerer, expr: ts.ObjectLiteralExpre
|
||||
};
|
||||
|
||||
const fields: { name: string; value: IrExpr; overflow?: true; drop?: true }[] = [];
|
||||
const spreadStmts: IrStmt[] = [];
|
||||
const hasSpread = expr.properties.some(ts.isSpreadAssignment);
|
||||
const captured = new Set<IrExpr>();
|
||||
const capture = (value: IrExpr): IrExpr => {
|
||||
const local = lowerer.declareHiddenLocal("%spreadValue", value.type);
|
||||
spreadStmts.push({ kind: "varDecl", localId: local.id, init: value, loc: value.loc });
|
||||
const ref = varRef(local.id, value.type, value.loc);
|
||||
captured.add(ref);
|
||||
return ref;
|
||||
};
|
||||
// Field names introduced by conditional spreads: their ternary carries
|
||||
// the spread's whole evaluation (cond once, value lazily), so a LATER
|
||||
// contributor overriding one would silently drop that evaluation —
|
||||
@@ -1133,6 +1143,20 @@ export function lowerObjectLiteral(lowerer: Lowerer, expr: ts.ObjectLiteralExpre
|
||||
// member reads narrow away; see the catch in the property loop).
|
||||
const droppedNames = new Set<string>();
|
||||
for (const prop of expr.properties) {
|
||||
// A later contributor can mutate an earlier source or overwrite a
|
||||
// value with effects. Snapshot pending fields at their source position,
|
||||
// before evaluating the next contributor, even if they are overwritten.
|
||||
if (hasSpread) {
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const field = fields[i]!;
|
||||
if (field.drop) {
|
||||
spreadStmts.push({ kind: "exprStmt", expr: field.value, loc: field.value.loc });
|
||||
fields.splice(i--, 1);
|
||||
continue;
|
||||
}
|
||||
if (!captured.has(field.value)) field.value = capture(field.value);
|
||||
}
|
||||
}
|
||||
if (ts.isSpreadAssignment(prop)) {
|
||||
const cs = conditionalSpreadOf(prop.expression);
|
||||
if (cs && cs !== "unsupported") {
|
||||
@@ -1195,30 +1219,15 @@ export function lowerObjectLiteral(lowerer: Lowerer, expr: ts.ObjectLiteralExpre
|
||||
// shape. Every source field must land on the target shape with an
|
||||
// equal type (a wider source would silently DROP fields JS keeps —
|
||||
// the width fence, same as literals). Later contributors override
|
||||
// earlier ones (JS last-write-wins; the reads are side-effect-free,
|
||||
// so dropping the earlier read is exact). Sources must be a
|
||||
// re-emittable pure read, sharing one lowered node per field.
|
||||
// The desugar's one-entry-per-name list reads spread fields
|
||||
// EAGERLY at the spread's position, so an explicit property
|
||||
// BEFORE a spread would need JS's overwrite — order-fenced (the
|
||||
// index-signature merge path above takes any order).
|
||||
if (
|
||||
expr.properties
|
||||
.slice(0, expr.properties.indexOf(prop))
|
||||
.some((p) => !ts.isSpreadAssignment(p))
|
||||
) {
|
||||
lowerer.unsupported(
|
||||
"SC1090",
|
||||
prop,
|
||||
"object spread after explicit properties (spreads must come first — a later spread would overwrite them with JS semantics the desugar does not model)",
|
||||
);
|
||||
}
|
||||
// earlier ones (JS last-write-wins). Evaluate the source exactly
|
||||
// once, including empty sources and those whose fields are all
|
||||
// overridden. Field snapshots above preserve the copy order.
|
||||
let srcNode: ts.Expression = prop.expression;
|
||||
while (ts.isParenthesizedExpression(srcNode)) srcNode = srcNode.expression;
|
||||
const srcLowered =
|
||||
const srcLowered = capture(
|
||||
prop === expr.properties[0] && leadingSpreadLowered !== null
|
||||
? leadingSpreadLowered
|
||||
: lowerer.lowerExpr(srcNode);
|
||||
: lowerer.lowerExpr(srcNode));
|
||||
// Array callbacks can receive a record-or-undefined ABI even when
|
||||
// TypeScript describes a required record. Select the copy strategy
|
||||
// from that stored representation so absent sources copy nothing.
|
||||
@@ -1248,13 +1257,6 @@ export function lowerObjectLiteral(lowerer: Lowerer, expr: ts.ObjectLiteralExpre
|
||||
`object spread of '${lowerer.fmt(srcType)}' sources (only known record shapes spread — ${NARROW_FIRST})`,
|
||||
);
|
||||
}
|
||||
if (srcLowered && !isSafeToRepeat(srcLowered)) {
|
||||
lowerer.unsupported(
|
||||
"SC1090",
|
||||
prop,
|
||||
"object spread of computed sources (the field copies re-read the source — bind it to a const first)",
|
||||
);
|
||||
}
|
||||
const recArm = recArms[0]! as IrType & { kind: "record" };
|
||||
const recTag = def.arms.indexOf(recArm);
|
||||
// A checked-dynamic VALUE under the union-mapped checker type
|
||||
@@ -1391,13 +1393,6 @@ export function lowerObjectLiteral(lowerer: Lowerer, expr: ts.ObjectLiteralExpre
|
||||
`object spread of '${srcType ? lowerer.fmt(srcType) : lowerer.checker.typeToString(lowerer.typeOf(srcNode))}' sources (only known record shapes spread — ${NARROW_FIRST})`,
|
||||
);
|
||||
}
|
||||
if (srcLowered && !isSafeToRepeat(srcLowered)) {
|
||||
lowerer.unsupported(
|
||||
"SC1090",
|
||||
prop,
|
||||
"object spread of computed sources (the field copies re-read the source — bind it to a const first)",
|
||||
);
|
||||
}
|
||||
const srcShape = lowerer.shapes.get(srcType.shapeId);
|
||||
if (!srcShape) throw new InternalCompilerError(`lowerer bug: spread of unknown shape ${srcType.shapeId}`);
|
||||
fenceAccessorSpreadSource(lowerer, prop, srcShape);
|
||||
@@ -1730,7 +1725,8 @@ export function lowerObjectLiteral(lowerer: Lowerer, expr: ts.ObjectLiteralExpre
|
||||
fields.push({ name: f.name, value: absent });
|
||||
}
|
||||
}
|
||||
return { kind: "recordLit", fields, type, loc };
|
||||
const result: IrExpr = { kind: "recordLit", fields, type, loc };
|
||||
return spreadStmts.length === 0 ? result : { kind: "seqExpr", stmts: spreadStmts, result, type, loc };
|
||||
}
|
||||
|
||||
/** A conditional spread's carrier property: `name: value` or shorthand,
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import * as ts from "../ts7/adapter.js";
|
||||
import { BOOL, DYN, NULL_T, STRING, UNDEFINED_T, type IrExpr, type IrStmt, type SrcLoc } from "../../ir/ir.js";
|
||||
import { strLit, varRef } from "../../ir/build.js";
|
||||
import type { Lowerer } from "./lowerer.js";
|
||||
import { BUILTIN_MODULE_CONSTS, BUILTIN_MODULE_FNS, OBJECT_CALLABLE_VALUES, builtinConstLit, builtinModuleConstOf, builtinModulesArrayLit } from "./surfaces.js";
|
||||
|
||||
/** These native callables own their argument checks. Unannotated JS aliases
|
||||
* keep the checked value instead of narrowing it to the ambient signature.
|
||||
* This selects storage only: reassignment still updates a real runtime slot. */
|
||||
export function isNativeBuiltinValueInitializer(lowerer: Lowerer, expr: ts.Expression | undefined, seen = new Set<ts.Symbol>()): boolean {
|
||||
if (!expr) return false;
|
||||
while (ts.isParenthesizedExpression(expr)) expr = expr.expression;
|
||||
if (ts.isPropertyAccessExpression(expr)) {
|
||||
return lowerer.stdlibGlobalMember(expr, "process") === "getBuiltinModule" ||
|
||||
(lowerer.isStdlibGlobal(expr.expression, "Object") && Object.hasOwn(OBJECT_CALLABLE_VALUES, expr.name.text));
|
||||
}
|
||||
if (!ts.isIdentifier(expr)) return false;
|
||||
const symbol = lowerer.resolveValueSymbol(expr);
|
||||
if (!symbol || seen.has(symbol)) return false;
|
||||
seen.add(symbol);
|
||||
return lowerer.checker.declarationsOf(symbol).some((decl) =>
|
||||
ts.isVariableDeclaration(decl) && isNativeBuiltinValueInitializer(lowerer, decl.initializer, seen));
|
||||
}
|
||||
|
||||
// These module values expose existing native callable lowerings and main-thread
|
||||
// metadata. Other exports keep an explicit runtime refusal, including Worker.
|
||||
const MODULES = ["path/posix", "path/win32", "os", "worker_threads"] as const;
|
||||
|
||||
const box = (value: IrExpr): IrExpr => value.type.kind === "dyn" ? value : { kind: "dynFrom", value, type: DYN, loc: value.loc };
|
||||
|
||||
function moduleValue(lowerer: Lowerer, module: string, loc: SrcLoc): IrExpr {
|
||||
const cacheKey = `%builtin.module.get.${module}`;
|
||||
let name = lowerer.builtinCallableValueFns.get(cacheKey);
|
||||
if (!name) {
|
||||
name = cacheKey;
|
||||
lowerer.builtinCallableValueFns.set(cacheKey, name);
|
||||
const key = varRef("key", STRING, loc);
|
||||
const body: IrStmt[] = [];
|
||||
const add = (member: string, value: IrExpr): void => {
|
||||
body.push({
|
||||
kind: "if", cond: { kind: "strEq", negated: false, left: key, right: strLit(member, loc), type: BOOL, loc },
|
||||
then: [{ kind: "return", value: box(value), loc }], else_: null, loc,
|
||||
});
|
||||
};
|
||||
for (const member of Object.keys(BUILTIN_MODULE_FNS[module] ?? {})) {
|
||||
const callable = lowerer.lowerBuiltinCallableValue({ module, member }, loc);
|
||||
if (callable) add(member, callable);
|
||||
}
|
||||
for (const member of Object.keys(BUILTIN_MODULE_CONSTS[module] ?? {})) {
|
||||
const value = builtinModuleConstOf(lowerer, module, member);
|
||||
if (value !== undefined) add(member, builtinConstLit(value, loc));
|
||||
}
|
||||
if (module.startsWith("path/")) {
|
||||
add("posix", moduleValue(lowerer, "path/posix", loc));
|
||||
add("win32", moduleValue(lowerer, "path/win32", loc));
|
||||
}
|
||||
if (module === "worker_threads") {
|
||||
add("isInternalThread", { kind: "boolLit", value: false, type: BOOL, loc });
|
||||
add("parentPort", { kind: "unitLit", unit: "null", type: NULL_T, loc });
|
||||
add("workerData", { kind: "unitLit", unit: "null", type: NULL_T, loc });
|
||||
}
|
||||
body.push({ kind: "return", value: {
|
||||
kind: "libCall", fn: "process.builtinUnsupported", args: [strLit(module, loc), key], type: DYN, loc,
|
||||
}, loc });
|
||||
lowerer.liftedFns.push({
|
||||
name, params: [{ localId: "key", name: "key", type: STRING }], returnType: DYN,
|
||||
locals: [{ id: "key", name: "key", type: STRING, mutable: false }], body, loc,
|
||||
});
|
||||
}
|
||||
const getter: IrExpr = { kind: "closure", fnName: name, captures: [], type: { kind: "func", params: [STRING], ret: DYN }, loc };
|
||||
return { kind: "libCall", fn: "process.builtinModule", args: [strLit(module, loc), box(getter)], type: DYN, loc };
|
||||
}
|
||||
|
||||
/** A first-class loader uses the same native functions as direct imports.
|
||||
* Module handles cache values and preserve aliases without a JS engine. */
|
||||
export function lowerBuiltinLoaderValue(lowerer: Lowerer, loc: SrcLoc): IrExpr {
|
||||
const cacheKey = "%builtin.process.getBuiltinModule";
|
||||
let name = lowerer.builtinCallableValueFns.get(cacheKey);
|
||||
if (!name) {
|
||||
name = cacheKey;
|
||||
lowerer.builtinCallableValueFns.set(cacheKey, name);
|
||||
const id = varRef("id", STRING, loc);
|
||||
const body: IrStmt[] = [{ kind: "varDecl", localId: "id", init: {
|
||||
kind: "libCall", fn: "process.builtinId", args: [varRef("input", DYN, loc), builtinModulesArrayLit(loc)], type: STRING, loc,
|
||||
}, loc }];
|
||||
const add = (specifier: string, value: IrExpr): void => {
|
||||
body.push({
|
||||
kind: "if", cond: { kind: "strEq", negated: false, left: id, right: strLit(specifier, loc), type: BOOL, loc },
|
||||
then: [{ kind: "return", value, loc }], else_: null, loc,
|
||||
});
|
||||
};
|
||||
add("", box({ kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }));
|
||||
// path's default is the target platform's implementation, including identity.
|
||||
const pathModule = builtinModuleConstOf(lowerer, "path", "sep") === "\\" ? "path/win32" : "path/posix";
|
||||
add("path", moduleValue(lowerer, pathModule, loc));
|
||||
for (const module of MODULES) add(module, moduleValue(lowerer, module, loc));
|
||||
body.push({ kind: "return", value: {
|
||||
kind: "libCall", fn: "process.builtinUnsupported", args: [id, strLit("", loc)], type: DYN, loc,
|
||||
}, loc });
|
||||
lowerer.liftedFns.push({
|
||||
name, params: [{ localId: "input", name: "id", type: DYN }], returnType: DYN,
|
||||
locals: [{ id: "input", name: "id", type: DYN, mutable: false }, { id: "id", name: "module", type: STRING, mutable: false }], body, loc,
|
||||
});
|
||||
}
|
||||
return { kind: "closure", fnName: name, captures: [], type: { kind: "func", params: [DYN], ret: DYN }, loc };
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import { BOOL, BYTES_U8, CHILD_T, CHILDSTREAM_T, CHILDWRITER_T, CRYPTOHASH_T, CR
|
||||
import { boolLit, countedFor, numLit, strLit, varRef } from "../../ir/build.js";
|
||||
import { staticForkModulePath } from "../fork-target.js";
|
||||
import { tsgoPath } from "../dts-paths.js";
|
||||
import { lowerBuiltinLoaderValue } from "./lower-builtin-values.js";
|
||||
|
||||
function optionalStringTags(lowerer: Lowerer, type: IrType): { stringTag: number; undefinedTag: number } | null {
|
||||
if (type.kind !== "union") return null;
|
||||
@@ -7087,12 +7088,8 @@ function lowerProcessIpcSend(lowerer: Lowerer, call: ts.CallExpression): IrExpr
|
||||
* rejected specifically. Null for non-process receivers (the chain keeps
|
||||
* trying other property lowerings). */
|
||||
export function lowerProcessProperty(lowerer: Lowerer, expr: ts.PropertyAccessExpression): IrExpr | null {
|
||||
// process.versions.node — the ONE lowered member of process.versions:
|
||||
// there is no Node under the binary, so the honest answer is the
|
||||
// runtime's own Node compatibility target (the version whose semantics
|
||||
// SEMANTICS.md verifies against — divergence 60, the execPath stance).
|
||||
// Other versions members (v8, openssl, ...) name components that do
|
||||
// not exist here and fall through to the member fence.
|
||||
// node and openssl name the compatibility target, not linked engines.
|
||||
// Read the stable object so descriptor edits through aliases stay visible.
|
||||
if (
|
||||
(expr.name.text === "node" || expr.name.text === "openssl") &&
|
||||
!expr.questionDotToken &&
|
||||
@@ -7104,36 +7101,32 @@ function lowerProcessIpcSend(lowerer: Lowerer, call: ts.CallExpression): IrExpr
|
||||
// "is crypto available" probe, and the crypto module exists here
|
||||
// (unsupported members fence per site). SEMANTICS.md documents that
|
||||
// the string names the compat target, not a linked library.
|
||||
const fn = expr.name.text === "node" ? "process.versionsNode" : "process.versionsOpenssl";
|
||||
return { kind: "libCall", fn, args: [], type: STRING, loc: locOf(expr) };
|
||||
const loc = locOf(expr);
|
||||
return lowerer.coerceToExpected({
|
||||
kind: "dynKeyGet", key: { kind: "strLit", value: expr.name.text, type: STRING, loc },
|
||||
value: { kind: "libCall", fn: "process.versions", args: [], type: DYN, loc }, type: DYN, loc,
|
||||
}, STRING);
|
||||
}
|
||||
// process.versions?.electron is the runtime-capability probe used by
|
||||
// CLI packages to select Electron argument conventions. versions
|
||||
// itself always exists, and a native scriptc binary is not Electron,
|
||||
// so both the optional and ordinary property spellings read undefined.
|
||||
// Other components begin absent. Consult the same object even for the
|
||||
// capability probes: users can define or delete their own entries.
|
||||
if (
|
||||
ts.isPropertyAccessExpression(expr.expression) &&
|
||||
lowerer.stdlibGlobalMember(expr.expression, "process") === "versions" &&
|
||||
expr.name.text === "electron"
|
||||
lowerer.stdlibGlobalMember(expr.expression, "process") === "versions"
|
||||
) {
|
||||
return { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc: locOf(expr) };
|
||||
const loc = locOf(expr);
|
||||
return {
|
||||
kind: "dynKeyGet", key: { kind: "strLit", value: expr.name.text, type: STRING, loc },
|
||||
value: { kind: "libCall", fn: "process.versions", args: [], type: DYN, loc }, type: DYN, loc,
|
||||
};
|
||||
}
|
||||
// The capability-probe members that honestly DON'T EXIST in a
|
||||
// compiled binary — each reads undefined (their declared types carry
|
||||
// the undefined arm), so feature probes take their documented
|
||||
// fallbacks: no OpenSSL/SQLite components (process.versions.openssl/
|
||||
// .sqlite), no gyp build config (process.config.variables.* — no ICU,
|
||||
// fallbacks: no gyp build config (process.config.variables.* — no ICU,
|
||||
// no QUIC — and process.config.target_defaults), no feature flags
|
||||
// (process.features.* — no inspector, not a debug build).
|
||||
if (!expr.questionDotToken && ts.isPropertyAccessExpression(expr.expression)) {
|
||||
const container = lowerer.stdlibGlobalMember(expr.expression, "process");
|
||||
if (container === "versions" && (expr.name.text === "sqlite" || expr.name.text === "bun" || expr.name.text === "deno")) {
|
||||
// versions.bun / versions.deno are the OTHER-runtime probes (a
|
||||
// formatter's config loader picks its package.json reader by
|
||||
// them): a compiled binary is neither, so both read undefined —
|
||||
// exactly Node's own answer.
|
||||
return { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc: locOf(expr) };
|
||||
}
|
||||
if (container === "features") {
|
||||
return { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc: locOf(expr) };
|
||||
}
|
||||
@@ -7157,6 +7150,15 @@ function lowerProcessIpcSend(lowerer: Lowerer, call: ts.CallExpression): IrExpr
|
||||
const member = lowerer.stdlibGlobalMember(expr, "process");
|
||||
if (member === null) return null;
|
||||
const loc = locOf(expr);
|
||||
if (member === "versions") {
|
||||
return { kind: "libCall", fn: "process.versions", args: [], type: DYN, loc };
|
||||
}
|
||||
if (member === "getBuiltinModule") {
|
||||
// Keep the native loader's argument validation when the function is
|
||||
// stored. The declaration's string signature must not insert a checked
|
||||
// adapter before the loader gets to report Node's invalid-id error.
|
||||
return { kind: "dynFrom", value: lowerBuiltinLoaderValue(lowerer, loc), type: DYN, loc };
|
||||
}
|
||||
if (member === "argv") {
|
||||
return { kind: "libCall", fn: "process.argv", args: [], type: arrayOf(STRING), loc };
|
||||
}
|
||||
@@ -7722,6 +7724,17 @@ function lowerProcessIpcSend(lowerer: Lowerer, call: ts.CallExpression): IrExpr
|
||||
access: ts.PropertyAccessExpression,): IrExpr | null {
|
||||
if (call.questionDotToken) return null;
|
||||
const directProcessMember = lowerer.stdlibGlobalMember(access, "process");
|
||||
if (directProcessMember === "getBuiltinModule") {
|
||||
if (call.arguments.some(ts.isSpreadElement)) lowerer.noLowering("process.getBuiltinModule with spread arguments", call);
|
||||
const loc = locOf(call);
|
||||
const id = call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN)
|
||||
: { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc } satisfies IrExpr;
|
||||
const binding = lowerer.declareHiddenLocal("%builtinId", DYN);
|
||||
return { kind: "seqExpr", stmts: [
|
||||
{ kind: "varDecl", localId: binding.id, init: id, loc },
|
||||
...call.arguments.slice(1).map((arg): IrStmt => ({ kind: "exprStmt", expr: lowerer.lowerExpr(arg), loc: locOf(arg) })),
|
||||
], result: { kind: "callValue", callee: lowerBuiltinLoaderValue(lowerer, loc), args: [varRef(binding.id, DYN, loc)], type: DYN, loc }, type: DYN, loc };
|
||||
}
|
||||
if (directProcessMember === "send") return lowerProcessIpcSend(lowerer, call);
|
||||
if (directProcessMember === "disconnect") {
|
||||
if (call.arguments.length !== 0) {
|
||||
|
||||
@@ -5880,6 +5880,7 @@ const DYN_PROTO_METHOD_NAMES = new Set([
|
||||
* is-not-a-function where the kind's prototype lacks the name, and
|
||||
* fences LOUDLY on real-but-unimplemented pairs. */
|
||||
const DYN_DISPATCH_METHODS = new Set([
|
||||
"segment", "containing", "resolvedOptions",
|
||||
"apply", "bind", "call",
|
||||
"push", "pop", "shift", "unshift", "slice", "at",
|
||||
"indexOf", "lastIndexOf", "includes", "join", "concat", "reverse", "sort",
|
||||
@@ -8626,6 +8627,16 @@ export function lowerPromiseMethodCall(lowerer: Lowerer, call: ts.CallExpression
|
||||
if (call.questionDotToken || access.questionDotToken) return null;
|
||||
if (!lowerer.isStdlibGlobal(access.expression, "Object")) return null;
|
||||
const member = access.name.text;
|
||||
if (member === "getOwnPropertyDescriptor" && call.arguments.length === 2) {
|
||||
const [receiver, key] = call.arguments;
|
||||
if (receiver && key && ts.isPropertyAccessExpression(receiver) && receiver.name.text === "prototype" &&
|
||||
lowerer.isStdlibGlobal(receiver.expression, "ArrayBuffer") && ts.isStringLiteral(key) && key.text === "byteLength") {
|
||||
const loc = locOf(call);
|
||||
const getter = lowerer.lowerNativeCallableValue({ fn: "arrayBuffer.byteLengthGetter", params: [], result: F64, valueParams: [] }, "get ArrayBuffer.prototype.byteLength", loc)!;
|
||||
return { kind: "libCall", fn: "arrayBuffer.byteLengthDescriptor", args: [lowerer.coerceToExpected(getter, DYN)], type: DYN, loc };
|
||||
}
|
||||
}
|
||||
|
||||
const cacheKeys = lowerRequireCacheKeys(lowerer, call, member);
|
||||
if (cacheKeys) return cacheKeys;
|
||||
// Object.is — the spec's SameValue over the static kinds. Number
|
||||
|
||||
@@ -4984,6 +4984,32 @@ function assignedThisFieldType(lowerer: Lowerer, expr: ts.NewExpression): IrType
|
||||
|
||||
export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr {
|
||||
const loc = locOf(expr);
|
||||
if (ts.isPropertyAccessExpression(expr.expression) && expr.expression.name.text === "Segmenter" &&
|
||||
lowerer.isStdlibGlobal(expr.expression.expression, "Intl")) {
|
||||
const args = expr.arguments ?? [];
|
||||
const undefinedArg = (arg: ts.Expression): boolean =>
|
||||
(lowerer.typeOf(arg).flags & ts.TypeFlags.Undefined) !== 0;
|
||||
if (args.length > 2 || (args[0] && !undefinedArg(args[0]))) {
|
||||
lowerer.noLowering("Intl.Segmenter locale negotiation", expr,
|
||||
"omit the locale or pass undefined for default Unicode grapheme segmentation");
|
||||
}
|
||||
const options = args[1];
|
||||
if (options && !undefinedArg(options) &&
|
||||
!(ts.isObjectLiteralExpression(options) && options.properties.every((property) =>
|
||||
ts.isPropertyAssignment(property) &&
|
||||
(ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) && property.name.text === "granularity" &&
|
||||
ts.isStringLiteral(property.initializer) && property.initializer.text === "grapheme"))) {
|
||||
lowerer.noLowering("Intl.Segmenter options", options,
|
||||
'the native segmenter supports default options and { granularity: "grapheme" }; word and sentence segmentation remain unsupported');
|
||||
}
|
||||
// Explicit undefined expressions can carry effects; retain argument order.
|
||||
const stmts: IrStmt[] = args.map((arg) => {
|
||||
const value = lowerer.lowerExpr(arg);
|
||||
return { kind: "exprStmt", expr: value.type.kind === "void" ? value : lowerer.coerceInto(arg, value, DYN), loc: locOf(arg) };
|
||||
});
|
||||
const result: IrExpr = { kind: "libCall", fn: "intl.segmenterNew", args: [], type: DYN, loc };
|
||||
return stmts.length ? { kind: "seqExpr", stmts, result, type: DYN, loc } : result;
|
||||
}
|
||||
const consoleCtor = ts.isIdentifier(expr.expression)
|
||||
? lowerer.builtinImportOf(expr.expression)
|
||||
: ts.isPropertyAccessExpression(expr.expression) &&
|
||||
@@ -5244,11 +5270,21 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr {
|
||||
const strArg = (a: ts.Expression | undefined, what: string): IrExpr => {
|
||||
if (!a) return { kind: "strLit", value: "", type: STRING, loc };
|
||||
const v = lowerer.lowerExpr(a);
|
||||
const empty: IrExpr = { kind: "strLit", value: "", type: STRING, loc };
|
||||
if (v.type.kind === "undefinedT") {
|
||||
if (v.kind === "unitLit") return empty;
|
||||
return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: lowerer.coerceToExpected(v, DYN), loc: locOf(a) }], result: empty, type: STRING, loc };
|
||||
}
|
||||
if (v.type.kind === "union" && lowerer.unions.get(v.type.unionId)?.arms.every(
|
||||
(arm) => arm.kind === "string" || arm.kind === "undefinedT",
|
||||
)) {
|
||||
return { kind: "nullish", left: v, right: empty, type: STRING, loc: locOf(a) };
|
||||
}
|
||||
if (v.type.kind !== "string") {
|
||||
lowerer.noLowering(
|
||||
`new RegExp with a '${lowerer.fmt(v.type)}' ${what}`,
|
||||
a,
|
||||
"string arguments are the lowered form (a RegExp copy or ToString coercion has no lowering)",
|
||||
"string or undefined arguments are the lowered form (a RegExp copy or ToString coercion has no lowering)",
|
||||
);
|
||||
}
|
||||
return v;
|
||||
@@ -5739,7 +5775,7 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr {
|
||||
WeakRef: "deref()-after-collect exposes GC timing — genuinely dynamic; hold a strong reference instead",
|
||||
FinalizationRegistry: "finalization callbacks expose GC timing — genuinely dynamic; release resources explicitly instead",
|
||||
SharedArrayBuffer: "no shared-memory threads exist in a compiled program — Uint8Array is the byte storage",
|
||||
ArrayBuffer: "no free-standing ArrayBuffer value exists — typed arrays own their storage: allocate the view directly (new Uint8Array(n)), or erase a fresh buffer into one (new Uint8Array(new ArrayBuffer(n)), new DataView(new ArrayBuffer(n), ...))",
|
||||
ArrayBuffer: "native ArrayBuffer construction supports fixed-length storage; resizable buffers remain unsupported",
|
||||
Proxy: "native Proxy construction requires checked-native plain targets and handlers",
|
||||
Function: "runtime code generation cannot be compiled ahead of time (the eval stance) — write the function",
|
||||
};
|
||||
|
||||
@@ -46,6 +46,7 @@ import { coerceStringSearchValue, defaultAfterUndefined, lowerStaticallyUndefine
|
||||
import { recordTextCodecClass } from "../../ir/ir.js";
|
||||
import { classSymbolKeyOf } from "./symbol-fields.js";
|
||||
import { lowerClassMethodValue } from "./class-method-values.js";
|
||||
import { lowerGlobalValue } from "./lower-global-value.js";
|
||||
|
||||
/** An assignable `obj.field` target — a class field, a record field, or a
|
||||
* class ACCESSOR property (reads become getter calls, writes setter calls;
|
||||
@@ -665,11 +666,9 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Island values ask the engine; static primitives constant-fold to
|
||||
// the JS answer (the operand still evaluates — JS evaluates typeof
|
||||
// operands too — but primitives here are side-effect-free varRefs/
|
||||
// literals after lowering, so folding away the value is safe only
|
||||
// when the operand is trivial; otherwise keep it simple and reject).
|
||||
// A known static result type fixes typeof's answer, but its producer
|
||||
// still evaluates: calls, getters, and checked reads can have effects
|
||||
// or throw. Only trivial operands may disappear.
|
||||
let operand = lowerer.lowerExpr(expr.expression);
|
||||
if (operand.type.kind === "jsval") {
|
||||
return { kind: "jsOp", op: "typeof", args: [operand], type: STRING, loc };
|
||||
@@ -692,8 +691,11 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
undefinedT: "undefined", nullT: "object",
|
||||
};
|
||||
const folded = FOLD[operand.type.kind];
|
||||
if (folded && isSafeToDiscard(operand)) {
|
||||
return { kind: "strLit", value: folded, type: STRING, loc };
|
||||
if (folded) {
|
||||
const result: IrExpr = { kind: "strLit", value: folded, type: STRING, loc };
|
||||
return isSafeToDiscard(operand) ? result : {
|
||||
kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: operand, loc }], result, type: STRING, loc,
|
||||
};
|
||||
}
|
||||
// A union operand: every arm's typeof answer is static, so the value
|
||||
// form is a ternary chain over runtime TAG tests (arms grouped by
|
||||
@@ -1109,6 +1111,9 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
// global, one token; what a token cannot do (be called, answer
|
||||
// typeof "function") meets per-site fences/divergences, and
|
||||
// SEMANTICS.md documents the stance.
|
||||
if (!lowerer.dynamic && stdlibGlobalNameOf(lowerer, expr) === "globalThis") {
|
||||
return lowerGlobalValue(lowerer, expr);
|
||||
}
|
||||
{
|
||||
const sym = lowerer.checker.getSymbolAtLocation(expr);
|
||||
if (lowerer.isStdlibSymbol(sym) || expr.text === "globalThis") {
|
||||
@@ -1128,9 +1133,9 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
const globalHints: Record<string, string | undefined> = {
|
||||
Proxy: "Proxy constructor values have no native lowering; use a direct new Proxy with checked-native plain objects",
|
||||
Reflect: "reflective property access has no static lowering — read and call members directly",
|
||||
Intl: "locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat(\"en-US\").format(x) and x.toLocaleString(\"en-US\") with default options",
|
||||
Intl: "native Intl supports default Unicode grapheme segmentation and the composed new Intl.NumberFormat(\"en-US\").format(x); locale negotiation and other ICU-backed operations remain unsupported",
|
||||
SharedArrayBuffer: "no shared-memory threads exist in a compiled program — Uint8Array is the byte storage",
|
||||
ArrayBuffer: "no free-standing ArrayBuffer value exists — typed arrays own their storage (new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)",
|
||||
ArrayBuffer: "ArrayBuffer constructor values have no native lowering; use new ArrayBuffer(length) for fixed-length shared storage",
|
||||
WeakRef: "deref()-after-collect exposes GC timing — genuinely dynamic; hold a strong reference instead",
|
||||
FinalizationRegistry: "finalization callbacks expose GC timing — genuinely dynamic; release resources explicitly instead",
|
||||
eval: "runtime code evaluation cannot be compiled ahead of time",
|
||||
@@ -1516,6 +1521,14 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
if (requireMain) return requireMain;
|
||||
const moduleProperty = lowerNodeModuleProperty(lowerer, expr);
|
||||
if (moduleProperty) return moduleProperty;
|
||||
// Missing host globals (Bun/Deno capability probes) have no binding
|
||||
// in a native program. Declared globals retain their own lowering;
|
||||
// arbitrary global-object mutation remains fenced. Preserve a dyn
|
||||
// undefined value so stored probes compose with optional calls.
|
||||
if (!lowerer.dynamic && stdlibGlobalNameOf(lowerer, expr.expression) === "globalThis" &&
|
||||
!lowerer.checker.getPropertyOfType(lowerer.typeOf(expr.expression), expr.name.text)) {
|
||||
return { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
|
||||
}
|
||||
if (expr.questionDotToken && expr.name.text === "electron") {
|
||||
const processProperty = lowerer.lowerProcessProperty(expr);
|
||||
if (processProperty) return processProperty;
|
||||
@@ -1837,6 +1850,7 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
) {
|
||||
const canonical = stdlibGlobalNameOf(lowerer, expr);
|
||||
if (canonical !== null) {
|
||||
if (!lowerer.dynamic && canonical === "globalThis") return lowerGlobalValue(lowerer, expr);
|
||||
return { kind: "strLit", value: `[builtin ${canonical}]`, type: STRING, loc };
|
||||
}
|
||||
}
|
||||
@@ -1887,22 +1901,27 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
// best-effort static name and the declared arity; anything else is
|
||||
// the own-property answer, undefined. Function.prototype METHOD
|
||||
// names stay fenced (a stored-member undefined would mis-answer
|
||||
// `f.call` as a value). JS files only; TS keeps the fence.
|
||||
// `f.call` as a value). Static callable values keep the existing TS fence; checked callable
|
||||
// storage can expose its own name and length in both source languages.
|
||||
if (
|
||||
!["apply", "bind", "call", "toString", "constructor", "prototype", "caller", "arguments"].includes(expr.name.text) &&
|
||||
isJsSourceFile(expr.getSourceFile())
|
||||
(isJsSourceFile(expr.getSourceFile()) || expr.name.text === "name" || expr.name.text === "length")
|
||||
) {
|
||||
const probed = tryLowerExpression(lowerer, expr.expression);
|
||||
// Inferred callable returns can use checked storage even when the
|
||||
// checker still describes a function. Read its actual dyn value;
|
||||
// the ambient Function member must not hide its own properties.
|
||||
if (probed?.type.kind === "dyn" && lowerer.checker.getCallSignatures(lowerer.typeOf(expr.expression)).length > 0) {
|
||||
const receiverType = lowerer.typeOf(expr.expression);
|
||||
const receiverSymbol = receiverType.getSymbol();
|
||||
const checkedFunction = lowerer.checker.getCallSignatures(receiverType).length > 0 ||
|
||||
(receiverSymbol?.name === "Function" && lowerer.isStdlibSymbol(receiverSymbol));
|
||||
if (probed?.type.kind === "dyn" && checkedFunction) {
|
||||
const key: IrExpr = { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) };
|
||||
const opt = hasOptionalChainGuard(expr.expression);
|
||||
return lowerer.maybeNarrow({ kind: "dynKeyGet", key, value: probed, ...(opt ? { optional: true as const } : {}), type: DYN, loc }, expr);
|
||||
}
|
||||
if (
|
||||
probed?.type.kind === "func" &&
|
||||
isJsSourceFile(expr.getSourceFile()) && probed?.type.kind === "func" &&
|
||||
canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))
|
||||
) {
|
||||
const fnName = jsFuncNameOf(expr.expression);
|
||||
@@ -1964,7 +1983,10 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
// the generic dyn receiver path below. Provenance is limited to the
|
||||
// node:util parseArgs family; every other stdlib member keeps its
|
||||
// ordinary surface fence.
|
||||
if (isParseArgsDynProperty(lowerer, expr)) {
|
||||
const segmentDataSymbol = lowerer.typeOf(expr.expression).getSymbol();
|
||||
const segmentDataProperty = segmentDataSymbol?.name === "SegmentData" && lowerer.isStdlibSymbol(segmentDataSymbol) &&
|
||||
["segment", "index", "input", "isWordLike"].includes(expr.name.text);
|
||||
if (isParseArgsDynProperty(lowerer, expr) || segmentDataProperty) {
|
||||
const recv = lowerer.lowerExpr(expr.expression);
|
||||
if (recv.type.kind === "dyn") {
|
||||
const key: IrExpr = {
|
||||
@@ -3562,15 +3584,9 @@ function lowerPromiseThenPresence(
|
||||
return { kind: "bytesIntrinsic", method: "byteOffset", receiver, args: [], type: F64, loc };
|
||||
}
|
||||
if (name === "buffer") {
|
||||
// No ArrayBuffer VALUE exists — `.buffer` compiles only in the
|
||||
// one composed position that consumes it, the DataView
|
||||
// constructor's first argument (lowerDataViewNew peels it).
|
||||
lowerer.unsupported(
|
||||
"SC1090",
|
||||
expr,
|
||||
"'.buffer' outside new DataView(x.buffer, ...) / Buffer.from(x.buffer, ...) " +
|
||||
"(no free-standing ArrayBuffer value exists; subarray() answers an aliasing view directly)",
|
||||
);
|
||||
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
||||
const receiver = expected?.kind === "bytes" ? strictReceiver(expected) : lowerer.lowerExpr(expr.expression);
|
||||
return { kind: "bytesIntrinsic", method: "buffer", receiver, args: [], type: DYN, loc };
|
||||
}
|
||||
if (name === "slice" || name === "subarray" || name === "set" || name === "toString") {
|
||||
lowerer.unsupported("SC1090", expr, `typed-array methods as values (call '${name}' directly)`);
|
||||
@@ -5083,6 +5099,34 @@ export function lowerElementCompound(lowerer: Lowerer, expr: ts.BinaryExpression
|
||||
|
||||
/** `a[i] = v` in statement position → arraySet (element writes, like local
|
||||
* assignment, produce no value in our subset). */
|
||||
function lowerDynElementAssignment(lowerer: Lowerer, expr: ts.BinaryExpression, recv: IrExpr): IrExpr {
|
||||
const loc = locOf(expr);
|
||||
const target = expr.left as ts.ElementAccessExpression;
|
||||
const receiver = lowerer.declareHiddenLocal("%setReceiver", DYN);
|
||||
const keyValue = lowerer.lowerExprExpecting(target.argumentExpression, DYN);
|
||||
const key = lowerer.declareHiddenLocal("%setKey", DYN);
|
||||
const raw = lowerer.lowerExpr(expr.right);
|
||||
const value: IrExpr = raw.type.kind === "void"
|
||||
? {
|
||||
kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: raw, loc }],
|
||||
result: dynUndefinedExpr(loc), type: DYN, loc,
|
||||
}
|
||||
: isUnitType(raw.type) ? lowerer.coerceInto(expr.right, raw, DYN) : raw;
|
||||
const assigned = lowerer.declareHiddenLocal("%setValue", value.type);
|
||||
const result = varRef(assigned.id, value.type, loc);
|
||||
const stored = lowerer.coerceInto(expr.right, result, DYN);
|
||||
// Evaluate the reference before the RHS, but defer key coercion until
|
||||
// PutValue. Yield the RHS without rereading a setter-backed property.
|
||||
return {
|
||||
kind: "seqExpr", stmts: [
|
||||
{ kind: "varDecl", localId: receiver.id, init: recv, loc },
|
||||
{ kind: "varDecl", localId: key.id, init: keyValue, loc },
|
||||
{ kind: "varDecl", localId: assigned.id, init: value, loc },
|
||||
{ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySetComputed", args: [varRef(receiver.id, DYN, loc), varRef(key.id, DYN, loc), stored], type: VOID, loc }, loc },
|
||||
], result, type: result.type, loc,
|
||||
};
|
||||
}
|
||||
|
||||
export function lowerElementWrite(lowerer: Lowerer, expr: ts.BinaryExpression): IrStmt {
|
||||
const target = expr.left as ts.ElementAccessExpression;
|
||||
fenceNodeModuleMutation(lowerer, target, "assignment");
|
||||
@@ -5130,6 +5174,10 @@ export function lowerElementCompound(lowerer: Lowerer, expr: ts.BinaryExpression
|
||||
"symbol-keyed property writes outside class fields keyed by a stable module-level literal Symbol()/Symbol.for() (other static shapes have no symbol-keyed storage)",
|
||||
);
|
||||
}
|
||||
const checkedReceiver = tryLowerExpression(lowerer, target.expression);
|
||||
if (checkedReceiver?.type.kind === "dyn") {
|
||||
return { kind: "exprStmt", expr: lowerDynElementAssignment(lowerer, expr, checkedReceiver), loc: locOf(expr) };
|
||||
}
|
||||
const receiverIr = lowerer.mapTypeOf(lowerer.typeOf(target.expression));
|
||||
if (receiverIr?.kind === "jsval") {
|
||||
const obj = lowerer.lowerExpr(target.expression);
|
||||
@@ -6227,6 +6275,15 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr
|
||||
const value = lowerer.lowerExprExpecting(expr.right, target.type);
|
||||
return { kind: "assignExpr", localId: target.id, value, type: target.type, loc };
|
||||
}
|
||||
// Bundled numeric enums use e[e["name"] = value] = "name".
|
||||
// Capture the receiver and key before the RHS. PutValue coerces the
|
||||
// key afterward, then yields the RHS without rereading the property.
|
||||
if (ts.isElementAccessExpression(expr.left) && !expr.left.questionDotToken) {
|
||||
const recv = tryLowerExpression(lowerer, expr.left.expression);
|
||||
if (recv?.type.kind === "dyn") {
|
||||
return lowerDynElementAssignment(lowerer, expr, recv);
|
||||
}
|
||||
}
|
||||
// `h.k = v` on an ISLAND receiver in VALUE position: the engine
|
||||
// property write (setProp throws the engine's TypeErrors on
|
||||
// nullish receivers, bridged catchably), the RHS value threaded
|
||||
@@ -7835,6 +7892,10 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr
|
||||
const right = lowerer.lowerExpr(expr.right);
|
||||
return { kind: "jsOp", op: "instanceOf", args: [left, right], type: BOOL, loc };
|
||||
}
|
||||
if (lowerer.isStdlibGlobal(expr.right, "ArrayBuffer")) {
|
||||
const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN);
|
||||
return { kind: "libCall", fn: "arrayBuffer.is", args: [value], type: BOOL, loc };
|
||||
}
|
||||
const rhsSymbol = ts.isIdentifier(expr.right) ? lowerer.resolveValueSymbol(expr.right) : null;
|
||||
// `x instanceof events.EventEmitter` — the namespace-member spelling
|
||||
// resolves to the same ambient class as the named import.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import * as ts from "../ts7/adapter.js";
|
||||
import { DYN, STRING, arrayOf, type IrExpr } from "../../ir/ir.js";
|
||||
import { strLit } from "../../ir/build.js";
|
||||
import { locOf } from "../program.js";
|
||||
import type { Lowerer } from "./lowerer.js";
|
||||
|
||||
/** A stored global object has identity and survives module/function boundaries.
|
||||
* Known globals without a value implementation refuse at runtime; absent host
|
||||
* capabilities answer undefined. The checker supplies names, never values. */
|
||||
export function lowerGlobalValue(lowerer: Lowerer, expr: ts.Expression): IrExpr {
|
||||
const loc = locOf(expr);
|
||||
const names = lowerer.checker.getPropertiesOfType(lowerer.typeOf(expr)).map((property) => property.name);
|
||||
return {
|
||||
kind: "libCall", fn: "global.native", args: [{
|
||||
kind: "arrayLit", elems: names.map((name) => strLit(name, loc)), type: arrayOf(STRING), loc,
|
||||
}], type: DYN, loc,
|
||||
};
|
||||
}
|
||||
@@ -19,7 +19,8 @@ import { builtinMemberRequireDecl, builtinNamespaceDestructureModuleOf, createRe
|
||||
import { bindingContextualGenericFnNodeOf, bindingGenericFnAliasInfoOf, bindingGenericFnInfoOf, bindingGenericFnNodeOf, bindingNeverReassigned, deadUnmappableBinding, implicitLocalFnInfoOf, implicitLocalFnNodeOf, nullishGenericBindingUnitOf, registerOverloadedCallableAlias } from "./lower-calls.js";
|
||||
import { hasJsTypeAnnotation, isVarDeclared, numericIteratorSourceOf, provenanceElidedConstDecl } from "./lower-stmts.js";
|
||||
import { streamClassAliasDecl } from "./lower-stream.js";
|
||||
import { OBJECT_CALLABLE_VALUES, stdlibGlobalAliasDecl, stdlibGlobalAliasNameOf } from "./surfaces.js";
|
||||
import { stdlibGlobalAliasDecl, stdlibGlobalAliasNameOf, stdlibGlobalNameOf } from "./surfaces.js";
|
||||
import { isNativeBuiltinValueInitializer } from "./lower-builtin-values.js";
|
||||
import { collectNamespaceStmt, nsPathPrefix, trapDeclRootOf } from "./lower-namespaces.js";
|
||||
import { collectExpandoMembers } from "./lower-expando.js";
|
||||
import { recordTextCodecClass } from "../../ir/ir.js";
|
||||
@@ -1410,15 +1411,14 @@ export function collectGlobals(lowerer: Lowerer, sf: ts.SourceFile, topStmts: ts
|
||||
for (const nameNode of boundIdentifiersOf(decl.name)) {
|
||||
const diagsBefore = lowerer.diags.length;
|
||||
try {
|
||||
// Generic Object declarations do not describe the concrete
|
||||
// native adapter ABI. Keep their stored values in shared module
|
||||
// storage so separately lowered export helpers see the same closure.
|
||||
// Builtin declarations do not always describe the concrete native
|
||||
// callable ABI. Preserve checked-native values in shared storage;
|
||||
// adapting the loader to (string) would replace its validation.
|
||||
const initializer = decl.initializer ? stripTypeCasts(decl.initializer) : undefined;
|
||||
if (
|
||||
isJsSourceFile(sf) && nameNode === decl.name && initializer &&
|
||||
ts.isPropertyAccessExpression(initializer) &&
|
||||
lowerer.isStdlibGlobal(initializer.expression, "Object") &&
|
||||
Object.hasOwn(OBJECT_CALLABLE_VALUES, initializer.name.text)
|
||||
(isNativeBuiltinValueInitializer(lowerer, initializer) ||
|
||||
(!lowerer.dynamic && stdlibGlobalNameOf(lowerer, initializer) === "globalThis"))
|
||||
) {
|
||||
const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
|
||||
if (symbol && !lowerer.globalsBySymbol.has(symbol)) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { PoisonError, boundIdentifiersOf, dynFallbackType, dynUndefinedExpr, imp
|
||||
import { enforceLibBoundary } from "./lib-boundary.js";
|
||||
import { cjsExportAssignmentOf, cjsExportDiscardReason, cjsExportTargetLiteral, isCjsJsFile, isEsModuleStamp, isJsSourceFile, isNodeEsmFile, locOf, requireSpecOf } from "../program.js";
|
||||
import { COMPOUND_ASSIGN_OPS, CompoundOp, STR_METHODS, UNSUPPORTED_STMT, isStdlibMember, sideEffectFreeOptionValue, stdlibGlobalAliasDecl, stdlibGlobalAliasNameOf, stdlibGlobalNameOf } from "./surfaces.js";
|
||||
import { isNativeBuiltinValueInitializer } from "./lower-builtin-values.js";
|
||||
import { isProvenanceSourceFile } from "../provenance-registry.js";
|
||||
import { ambientUndefVarRootOf, lowerImportEquals, nsUndefRead, nsWritableTarget, trapDeclRootOf } from "./lower-namespaces.js";
|
||||
import { expandoWritableTarget, lowerExpandoAssignStmt } from "./lower-expando.js";
|
||||
@@ -680,6 +681,8 @@ export function provenanceElidedConstDecl(lowerer: Lowerer, decl: ts.VariableDec
|
||||
* binding. */
|
||||
function varBindingType(lowerer: Lowerer, nameNode: ts.Identifier): IrType | null {
|
||||
if (ts.isVariableDeclaration(nameNode.parent) && isNativeProxyInitializer(lowerer, nameNode.parent.initializer)) return DYN;
|
||||
if (isJsSourceFile(nameNode.getSourceFile()) && ts.isVariableDeclaration(nameNode.parent) &&
|
||||
isNativeBuiltinValueInitializer(lowerer, nameNode.parent.initializer)) return DYN;
|
||||
let type = lowerer.mapTypeOf(lowerer.typeOf(nameNode));
|
||||
if (type?.kind === "record" && isJsSourceFile(nameNode.getSourceFile())) {
|
||||
const shape = lowerer.shapes.get(type.shapeId);
|
||||
@@ -1574,6 +1577,10 @@ export function isParseArgsDynCheckerType(lowerer: Lowerer, type: ts.Type): bool
|
||||
out: IrStmt[],
|
||||
dynSpell?: string,
|
||||
allowDynObject = false,): void {
|
||||
if (ts.isObjectBindingPattern(pattern)) {
|
||||
const patternSymbol = lowerer.typeOf(pattern).getSymbol();
|
||||
allowDynObject ||= patternSymbol?.name === "SegmentData" && lowerer.isStdlibSymbol(patternSymbol);
|
||||
}
|
||||
const present = patternSourceValue(lowerer, srcRef(), ts.isArrayBindingPattern(pattern), out, locOf(pattern), dynSpell);
|
||||
if (!typeEquals(present.type, srcType)) {
|
||||
lowerer.lowerBindingPattern(pattern, () => present, present.type, isLet, out, dynSpell, allowDynObject);
|
||||
|
||||
@@ -1157,6 +1157,16 @@ export const AMBIENT_SURFACE_FNS: readonly AmbientSurfaceRow[] = [
|
||||
note: "reads, writes, deletes, and enumeration of the process environment (the process global)",
|
||||
},
|
||||
{ id: "node-builtin.process.argv", kind: "node-builtin", name: "process.argv", fns: ["process.argv"] },
|
||||
{
|
||||
id: "node-builtin.process.getBuiltinModule", kind: "node-builtin", name: "process.getBuiltinModule",
|
||||
fns: ["process.builtinId", "process.builtinModule", "process.builtinUnsupported"],
|
||||
note: "native path and os export subsets plus main-thread worker_threads metadata; other modules and exports throw SC2020",
|
||||
},
|
||||
{
|
||||
id: "node-builtin.process.versions", kind: "node-builtin", name: "process.versions",
|
||||
fns: ["process.versions"],
|
||||
note: "shared version dictionary containing node and openssl; other components are absent unless defined by the program",
|
||||
},
|
||||
{ id: "node-builtin.process.cwd", kind: "node-builtin", name: "process.cwd", fns: ["process.cwd"] },
|
||||
{ id: "node-builtin.process.chdir", kind: "node-builtin", name: "process.chdir", fns: ["process.chdir"] },
|
||||
{ id: "node-builtin.process.pid", kind: "node-builtin", name: "process.pid", fns: ["process.pid"] },
|
||||
@@ -1431,7 +1441,7 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record<string, Record<string, string |
|
||||
},
|
||||
"stream/consumers": {
|
||||
arrayBuffer:
|
||||
"no free-standing ArrayBuffer value exists here (typed arrays own their storage) — " +
|
||||
"collecting a stream directly into an ArrayBuffer has no native lowering yet; " +
|
||||
"buffer(stream) collects the same bytes as a Buffer",
|
||||
blob:
|
||||
"Blob values have no representation in a compiled binary — " +
|
||||
@@ -1641,9 +1651,8 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record<string, Record<string, string |
|
||||
"a RegExp at runtime, which has no lowering";
|
||||
} else if (container === "ArrayBuffer" || container.startsWith("ArrayBuffer<")) {
|
||||
hint =
|
||||
"resize/transfer/maxByteLength need the buffer to exist as a runtime value, and no " +
|
||||
"free-standing ArrayBuffer value does — typed arrays own fixed-length storage " +
|
||||
"(new Uint8Array(n)); allocate a new view and copy instead";
|
||||
"native ArrayBuffer storage is fixed-length; resize and transfer are unsupported — " +
|
||||
"allocate a new buffer and copy through typed-array views instead";
|
||||
} else if (container === "SharedArrayBuffer" || container.startsWith("SharedArrayBuffer<")) {
|
||||
hint =
|
||||
"no shared-memory threads exist in a compiled program — Uint8Array is the byte storage " +
|
||||
@@ -1660,7 +1669,8 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record<string, Record<string, string |
|
||||
"locale- and ICU-backed behavior lives outside the static runtime (the localeCompare " +
|
||||
"stance: code-unit order, no collation/locale data) — what lowers: the composed " +
|
||||
'new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default ' +
|
||||
"options; format with template literals, toFixed, and toString otherwise";
|
||||
"options, plus default Unicode grapheme segmentation with Intl.Segmenter; locale " +
|
||||
"negotiation, word/sentence segmentation, and resolvedOptions remain unsupported";
|
||||
} else if (container === "Object" && member === "assign") {
|
||||
hint =
|
||||
"spread instead: { ...a, ...b } builds the merged record; what lowers: the empty-target " +
|
||||
@@ -1731,11 +1741,11 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record<string, Record<string, string |
|
||||
export function stdlibGlobalNameOf(lowerer: Lowerer, expr: ts.Expression): string | null {
|
||||
if (ts.isParenthesizedExpression(expr)) return stdlibGlobalNameOf(lowerer, expr.expression);
|
||||
if (ts.isIdentifier(expr)) {
|
||||
// `globalThis` itself: a reserved intrinsic — tsc rejects user
|
||||
// bindings of the name, and its special symbol carries no ordinary
|
||||
// declarations for the provenance check to see.
|
||||
if (expr.text === "globalThis") return "globalThis";
|
||||
const symbol = lowerer.checker.getSymbolAtLocation(expr);
|
||||
// `globalThis` itself: a reserved intrinsic — tsc rejects user
|
||||
// global bindings, but local parameters can shadow it. Its special
|
||||
// symbol has no ordinary declarations for the provenance check.
|
||||
if (expr.text === "globalThis" && (!symbol || lowerer.checker.declarationsOf(symbol).length === 0 || lowerer.isStdlibSymbol(symbol))) return "globalThis";
|
||||
if (!symbol) return null;
|
||||
const alias = lowerer.stdlibGlobalAliases.get(symbol);
|
||||
if (alias !== undefined) return alias;
|
||||
@@ -1850,6 +1860,10 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record<string, Record<string, string |
|
||||
if (!ts.isIdentifier(nameNode)) return false;
|
||||
const name = stdlibGlobalAliasNameOf(lowerer, init);
|
||||
if (name === null) return false;
|
||||
// Mutable global-object bindings keep real storage, even when never
|
||||
// reassigned: var can be observed before initialization and let has TDZ.
|
||||
if (name === "globalThis" && ts.isVariableDeclaration(nameNode.parent) &&
|
||||
(ts.getCombinedNodeFlags(nameNode.parent) & ts.NodeFlags.Const) === 0) return false;
|
||||
const symbol = lowerer.checker.getSymbolAtLocation(nameNode);
|
||||
if (!symbol) return false;
|
||||
lowerer.stdlibGlobalAliases.set(symbol, name);
|
||||
|
||||
@@ -954,6 +954,10 @@ function classExprNeverRegisters(decl: ts.ClassLikeDeclaration): boolean {
|
||||
|
||||
function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null {
|
||||
const { checker, unions, classNamer, resolveTypeParam } = ctx;
|
||||
// TypeScript's intrinsic globalThis symbol has no declaration. A stored
|
||||
// reference needs native object identity, including var's undefined state.
|
||||
const intrinsic = type.getSymbol();
|
||||
if (!ctx.dynamic && intrinsic?.name === "globalThis" && checker.declarationsOf(intrinsic).length === 0) return DYN;
|
||||
if (!ctx.dynamic) {
|
||||
const moduleId = ctx.moduleNamespaceId?.(type) ?? null;
|
||||
if (moduleId !== null) return { kind: "moduleNs", moduleId };
|
||||
@@ -1811,6 +1815,7 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null {
|
||||
if (isStdlibInterface("RegExp")) {
|
||||
return { kind: "regex" };
|
||||
}
|
||||
if (isStdlibInterface("Segmenter") || isStdlibInterface("Segments") || isStdlibInterface("SegmentData")) return DYN;
|
||||
// Typed arrays: references to the lib's Uint8Array/Uint32Array/
|
||||
// Float32Array/Float64Array interfaces (provenance, not names). The es2022+ lib
|
||||
// declares them generic over the backing buffer (`Uint8Array<ArrayBuffer>`
|
||||
@@ -1844,6 +1849,7 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null {
|
||||
// the same numeric-handle story over the check-phase queue — its own id
|
||||
// space, so clearTimeout of an Immediate no-ops like Node.
|
||||
if (isStdlibInterface("Immediate")) return F64;
|
||||
if (isStdlibInterface("ArrayBuffer") || isStdlibInterface("PropertyDescriptor") || isStdlibInterface("ProcessVersions")) return DYN;
|
||||
if (isStdlibInterface("Uint8Array")) return bytesOf("u8");
|
||||
if (isStdlibInterface("Uint32Array")) return bytesOf("u32");
|
||||
// Int32Array: the signed 32-bit kind (element reads sign-extend, writes
|
||||
|
||||
@@ -1788,6 +1788,7 @@ export type IrStrIntrinsicMethod =
|
||||
* (integer kinds by modular truncation, Float32 by double→float
|
||||
* rounding). No BIG setters exist — bigint arguments never lower. */
|
||||
export type IrBytesIntrinsicMethod =
|
||||
| "buffer"
|
||||
| "length"
|
||||
| "byteLength"
|
||||
| "get"
|
||||
@@ -1974,6 +1975,18 @@ export type IrRegexIntrinsicMethod =
|
||||
* assume the island runtime is linked when they see it; island exceptions
|
||||
* bridge into the exception cell as catchable strings (may-throw). */
|
||||
export type IrLibFn =
|
||||
| "intl.segmenterNew"
|
||||
| "arrayBuffer.new"
|
||||
| "arrayBuffer.is"
|
||||
| "arrayBuffer.isView"
|
||||
| "arrayBuffer.byteLengthGetter"
|
||||
| "arrayBuffer.byteLengthDescriptor"
|
||||
| "arrayBuffer.viewU8"
|
||||
| "arrayBuffer.viewU32"
|
||||
| "arrayBuffer.viewI32"
|
||||
| "arrayBuffer.viewF32"
|
||||
| "arrayBuffer.viewF64"
|
||||
| "arrayBuffer.viewDV"
|
||||
/** Native static fetch and its Web-platform companions. fetch.start
|
||||
* answers once the response head arrives; the response body readers
|
||||
* consume the native body stream. AbortSignal and ReadableStream values
|
||||
@@ -2032,6 +2045,7 @@ export type IrLibFn =
|
||||
* SEMANTICS.md notes the sloppy divergence: loud, never silent). Void
|
||||
* result; in the may-throw seed set. */
|
||||
| "dyn.keySet"
|
||||
| "dyn.keySetComputed"
|
||||
/** Delete an ordinary checked-native object's own key. Borrows both
|
||||
* arguments; other receiver representations retain a runtime refusal. */
|
||||
| "dyn.keyDelete"
|
||||
@@ -3372,6 +3386,7 @@ export type IrLibFn =
|
||||
* bytes<u8>[] arg (the list) and returns a fresh copy. `Buffer.from(u8)`
|
||||
* and `Buffer.alloc(n)` need no libFn — they lower to bytesNew. */
|
||||
| "buffer.fromStr"
|
||||
| "buffer.brand"
|
||||
/** Buffer.from on checked-native strings, bytes, arrays and data-only
|
||||
* array-like/Buffer-JSON objects. The encoding is a normalized literal;
|
||||
* non-string inputs ignore it. Copies the input and may throw during
|
||||
@@ -3575,6 +3590,12 @@ export type IrLibFn =
|
||||
* "x64") — Node's answer for its own build on the same machine.
|
||||
* Interned; +1 per read. Never throws. */
|
||||
| "process.arch"
|
||||
/** Stable native version dictionary. node/openssl identify compatibility
|
||||
* targets; components absent from the native runtime are omitted. */
|
||||
| "process.versions"
|
||||
| "process.builtinId"
|
||||
| "process.builtinModule"
|
||||
| "process.builtinUnsupported"
|
||||
/** process.versions.node: the runtime's Node COMPATIBILITY TARGET —
|
||||
* there is no Node under the binary, so this reports the version whose
|
||||
* semantics the runtime implements (SEMANTICS.md divergence 60, the
|
||||
@@ -3817,6 +3838,8 @@ export type IrLibFn =
|
||||
* name; the result type is the read's declared type (a typed dummy the
|
||||
* unwind abandons — the value never exists). */
|
||||
| "global.undefRead"
|
||||
/** A native reference to the global object; known names retain value fences. */
|
||||
| "global.native"
|
||||
/** `X.name` through a class VALUE (scr_object.c): args[0] is a borrowed
|
||||
* classval; the result is the class object's stored .name string,
|
||||
* retained (+1 — the string is an interned immortal, so the retain is a
|
||||
@@ -6161,7 +6184,7 @@ export function classDynViewSupported(
|
||||
}
|
||||
|
||||
/** A static type that CONVERTS into a dyn value — the dynFrom domain:
|
||||
* JSON-safe data, bytes<u8> (payload copied), identity-preserving class
|
||||
* JSON-safe data, bytes<u8> (retained views), identity-preserving class
|
||||
* references, undefined-armed unions of those arms, boxable function types,
|
||||
* and the runtime HANDLE kinds (boxed by reference — DYN_HANDLE_KINDS). */
|
||||
export function canConvertToDyn(
|
||||
@@ -6171,7 +6194,7 @@ export function canConvertToDyn(
|
||||
): boolean {
|
||||
if (isJsonSafeType(t, getRecord, getUnion)) return true;
|
||||
// bytes<u8> and boxable functions are dyn kinds the walker boxes
|
||||
// ANYWHERE (bytes copied, functions held by identity), including nested
|
||||
// ANYWHERE (bytes and functions held by identity), including nested
|
||||
// in records/arrays/unions. isJsonSafeType rejects them, but dynFrom
|
||||
// needs only that the walker can build the dyn value, so this composite
|
||||
// fold extends the JSON-safe core.
|
||||
@@ -6262,7 +6285,7 @@ function canBoxDynComposite(
|
||||
}
|
||||
|
||||
/** A type a dyn value can be VALIDATED into — the dynCheck domain:
|
||||
* JSON-safe data, bytes<u8> (a fresh copy out), the %Error extraction,
|
||||
* JSON-safe data, bytes<u8> (retained views), the %Error extraction,
|
||||
* undefined-armed unions of JSON-safe arms, adaptable function types,
|
||||
* and the runtime HANDLE kinds (a tag-checked reference unwrap —
|
||||
* DYN_HANDLE_KINDS). */
|
||||
@@ -6283,7 +6306,10 @@ export function canDynCheckTo(
|
||||
if (DYN_HANDLE_KINDS.has(t.kind)) return true;
|
||||
if (t.kind === "union") {
|
||||
const def = getUnion(t.unionId);
|
||||
return !!def && def.arms.every((a) => a.kind === "undefinedT" || isJsonSafeAt(a, getRecord, getUnion, false, false, new Set(), true));
|
||||
// Optional native callbacks and handles retain the same checked
|
||||
// conversion as their bare value. The union matcher selects the arm
|
||||
// before its adapter/extractor runs.
|
||||
return !!def && def.arms.every((a) => isUnitType(a) || (a.kind !== "union" && canDynCheckTo(a, getRecord, getUnion)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -7535,6 +7561,15 @@ export function moduleLibNondeterministicSurface(mod: IrModule): string | null {
|
||||
* seed on `dynCheck` and `awaitExpr` nodes, which throw on validation
|
||||
* failure / promise rejection). */
|
||||
export const MAY_THROW_LIB_FNS: ReadonlySet<IrLibFn> = new Set([
|
||||
"arrayBuffer.new",
|
||||
"arrayBuffer.byteLengthGetter",
|
||||
"arrayBuffer.viewU8",
|
||||
"arrayBuffer.viewU32",
|
||||
"arrayBuffer.viewI32",
|
||||
"arrayBuffer.viewF32",
|
||||
"arrayBuffer.viewF64",
|
||||
"arrayBuffer.viewDV",
|
||||
|
||||
"bigint.parse",
|
||||
"bigint.fromF64",
|
||||
"bigint.div",
|
||||
@@ -7836,6 +7871,10 @@ export const MAY_THROW_LIB_FNS: ReadonlySet<IrLibFn> = new Set([
|
||||
// throws Node's catchable SyntaxError at construction.
|
||||
"regex.new",
|
||||
"dyn.keySet",
|
||||
"dyn.keySetComputed",
|
||||
"process.builtinId",
|
||||
"process.builtinModule",
|
||||
"process.builtinUnsupported",
|
||||
"dyn.keyDelete",
|
||||
// the destructuring pack throws V8's TypeError on non-iterable dyn kinds
|
||||
"dyn.iterPack",
|
||||
|
||||
@@ -112,6 +112,7 @@ export const LIB_FN_SIGS: Record<IrLibFn, { argTypes: (IrType | null)[]; result:
|
||||
"json.parseReviver": { argTypes: [STRING, DYN], result: DYN },
|
||||
"json.stringifyReplacer": { argTypes: [DYN, DYN, STRING], result: DYN },
|
||||
"dyn.keySet": { argTypes: [DYN, STRING, DYN], result: VOID },
|
||||
"dyn.keySetComputed": { argTypes: [DYN, DYN, DYN], result: VOID },
|
||||
"dyn.keyDelete": { argTypes: [DYN, STRING, BOOL], result: VOID },
|
||||
"dyn.globalSymbolGet": { argTypes: [SYMBOL_T], result: DYN },
|
||||
"dyn.globalSymbolSet": { argTypes: [SYMBOL_T, DYN], result: VOID },
|
||||
@@ -952,6 +953,7 @@ export const LIB_FN_SIGS: Record<IrLibFn, { argTypes: (IrType | null)[]; result:
|
||||
// The Buffer statics and the fs/zlib Buffer forms: fixed always-u8
|
||||
// signatures (Buffer IS a Uint8Array — one bytes kind).
|
||||
"buffer.fromStr": { argTypes: [STRING, STRING], result: BYTES_U8 },
|
||||
"buffer.brand": { argTypes: [BYTES_U8], result: BYTES_U8 },
|
||||
"buffer.fromDyn": { argTypes: [DYN, STRING], result: BYTES_U8 },
|
||||
"buffer.concat": { argTypes: [arrayOf(BYTES_U8)], result: BYTES_U8 },
|
||||
"buffer.byteLenStr": { argTypes: [STRING, STRING], result: F64 },
|
||||
@@ -1056,6 +1058,10 @@ export const LIB_FN_SIGS: Record<IrLibFn, { argTypes: (IrType | null)[]; result:
|
||||
"process.getgid": { argTypes: [], result: F64 },
|
||||
"process.execPath": { argTypes: [], result: STRING },
|
||||
"process.arch": { argTypes: [], result: STRING },
|
||||
"process.versions": { argTypes: [], result: DYN },
|
||||
"process.builtinId": { argTypes: [DYN, arrayOf(STRING)], result: STRING },
|
||||
"process.builtinModule": { argTypes: [STRING, DYN], result: DYN },
|
||||
"process.builtinUnsupported": { argTypes: [STRING, STRING], result: DYN },
|
||||
"process.versionsNode": { argTypes: [], result: STRING },
|
||||
"process.versionsOpenssl": { argTypes: [], result: STRING },
|
||||
"process.kill": { argTypes: [F64, STRING], result: BOOL },
|
||||
@@ -1079,6 +1085,7 @@ export const LIB_FN_SIGS: Record<IrLibFn, { argTypes: (IrType | null)[]; result:
|
||||
// Always throws; the result is the READ's declared type (a typed dummy
|
||||
// the unwind abandons) — the libCall case skips the result check.
|
||||
"global.undefRead": { argTypes: [STRING], result: VOID },
|
||||
"global.native": { argTypes: [arrayOf(STRING)], result: DYN },
|
||||
// `X.name` through a class value: the arg is a program-dependent
|
||||
// classval (a null slot; the libCall case checks the kind).
|
||||
"class.name": { argTypes: [null], result: STRING },
|
||||
@@ -1098,6 +1105,18 @@ export const LIB_FN_SIGS: Record<IrLibFn, { argTypes: (IrType | null)[]; result:
|
||||
"error.domCause": { argTypes: [null], result: DYN },
|
||||
"error.domClone": { argTypes: [null, DYN], result: VOID },
|
||||
"dyn.errInstanceof": { argTypes: [DYN, F64], result: BOOL },
|
||||
"arrayBuffer.new": { argTypes: [DYN], result: DYN },
|
||||
"intl.segmenterNew": { argTypes: [], result: DYN },
|
||||
"arrayBuffer.is": { argTypes: [DYN], result: BOOL },
|
||||
"arrayBuffer.isView": { argTypes: [DYN], result: BOOL },
|
||||
"arrayBuffer.byteLengthGetter": { argTypes: [], result: F64 },
|
||||
"arrayBuffer.byteLengthDescriptor": { argTypes: [DYN], result: DYN },
|
||||
"arrayBuffer.viewU8": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 },
|
||||
"arrayBuffer.viewU32": { argTypes: [DYN, DYN, DYN], result: bytesOf("u32") },
|
||||
"arrayBuffer.viewI32": { argTypes: [DYN, DYN, DYN], result: bytesOf("i32") },
|
||||
"arrayBuffer.viewF32": { argTypes: [DYN, DYN, DYN], result: bytesOf("f32") },
|
||||
"arrayBuffer.viewF64": { argTypes: [DYN, DYN, DYN], result: bytesOf("f64") },
|
||||
"arrayBuffer.viewDV": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 },
|
||||
"dyn.objKeys": { argTypes: [DYN], result: DYN },
|
||||
"dyn.forInKeys": { argTypes: [DYN], result: DYN },
|
||||
"dyn.hasOwn": { argTypes: [DYN, STRING], result: BOOL },
|
||||
@@ -2754,6 +2773,7 @@ function validateFunction(
|
||||
err(`bytesIntrinsic ${e.method} args[1] must be a strLit encoding`, e.loc);
|
||||
}
|
||||
const EXTRA_SIGS: Record<string, { argTypes: IrType[]; minArgs: number; result: IrType } | undefined> = {
|
||||
buffer: { argTypes: [], minArgs: 0, result: DYN },
|
||||
setFromDyn: { argTypes: [DYN, F64], minArgs: 1, result: VOID },
|
||||
copyWithin: { argTypes: [F64, F64, F64], minArgs: 3, result: bytesOf(recv.elem) },
|
||||
equals: { argTypes: [BYTES_U8], minArgs: 1, result: BOOL },
|
||||
|
||||
@@ -1603,6 +1603,13 @@
|
||||
"status": "static",
|
||||
"note": "numeric writes in statement position set the implicit exit status; process.exit() reads it"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.process.getBuiltinModule",
|
||||
"kind": "node-builtin",
|
||||
"name": "process.getBuiltinModule",
|
||||
"status": "static",
|
||||
"note": "native path and os export subsets plus main-thread worker_threads metadata; other modules and exports throw SC2020"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.process.getgid",
|
||||
"kind": "node-builtin",
|
||||
@@ -1668,6 +1675,13 @@
|
||||
"name": "process.uptime",
|
||||
"status": "static"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.process.versions",
|
||||
"kind": "node-builtin",
|
||||
"name": "process.versions",
|
||||
"status": "static",
|
||||
"note": "shared version dictionary containing node and openssl; other components are absent unless defined by the program"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.querystring",
|
||||
"kind": "node-builtin",
|
||||
@@ -1744,7 +1758,7 @@
|
||||
"name": "stream/consumers.arrayBuffer",
|
||||
"status": "unsupported",
|
||||
"code": "SC2020",
|
||||
"note": "no free-standing ArrayBuffer value exists here (typed arrays own their storage) — buffer(stream) collects the same bytes as a Buffer"
|
||||
"note": "collecting a stream directly into an ArrayBuffer has no native lowering yet; buffer(stream) collects the same bytes as a Buffer"
|
||||
},
|
||||
{
|
||||
"id": "node-builtin.stream.consumers.blob",
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { expect, test } from "vitest";
|
||||
import { compile } from "../src/index.js";
|
||||
|
||||
test.each(["c", "llvm"] as const)("native builtin values refuse unimplemented modules and exports (%s)", async (backend) => {
|
||||
const dir = mkdtempSync("/tmp/scriptc-builtin-values-");
|
||||
try {
|
||||
const entry = join(dir, "main.js");
|
||||
writeFileSync(entry, `
|
||||
const load = process.getBuiltinModule;
|
||||
try { load("node:fs"); } catch (error) { console.log(error.code, error.message.includes("native builtin 'fs'")); }
|
||||
const path = load("path");
|
||||
try { path.parse("/a"); } catch (error) { console.log(error.code, error.message.includes(".parse'")); }
|
||||
const worker = load("worker_threads");
|
||||
try { console.log(worker.Worker); } catch (error) { console.log(error.code, error.message.includes("worker_threads.Worker")); }
|
||||
console.log(path.posix.join("still", "works"), worker.isMainThread);
|
||||
var scope = globalThis;
|
||||
try { console.log(scope.process); } catch (error) { console.log(error.code, error.message.includes("globalThis.process")); }
|
||||
const segmenter = new Intl.Segmenter();
|
||||
try { segmenter.resolvedOptions(); } catch (error) { console.log(error.message.includes("Intl.Segmenter locale negotiation")); }
|
||||
try { console.log(segmenter.segment); } catch (error) { console.log(error.message.includes("not supported")); }
|
||||
`);
|
||||
const result = await compile(entry, {
|
||||
backend, dynamic: false, sanitize: process.env["SCRIPTC_SAN"] === "1",
|
||||
outDir: dir, outPath: join(dir, "program"),
|
||||
});
|
||||
expect(result.ok, JSON.stringify(result.diagnostics)).toBe(true);
|
||||
if (!result.ok) return;
|
||||
const child = spawnSync(result.binaryPath, [], { encoding: "utf8" });
|
||||
expect(child.status, child.stderr).toBe(0);
|
||||
expect(child.stderr).toBe("");
|
||||
expect(child.stdout).toBe("SC2020 true\nSC2020 true\nSC2020 true\nstill/works true\nSC2020 true\ntrue\ntrue\n");
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
@@ -10975,6 +10975,92 @@
|
||||
"<repo>/tests/fixtures/node-types/url-getters.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/array-buffer-conversions.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/array-buffer-conversions.js"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/array-buffer-storage.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/array-buffer-storage.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/checked-byte-storage/main.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/checked-byte-storage/values.js",
|
||||
"<repo>/tests/corpus/checked-byte-storage/main.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/expression-runtime-values.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/expression-runtime-values.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/global-runtime-probes.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/global-runtime-probes.js"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/global-stored-probes.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/global-stored-probes.js"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/indexed-assignment-values.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/indexed-assignment-values.js"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/intl-grapheme-conformance/main.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/intl-grapheme-conformance/cases.ts",
|
||||
"<repo>/tests/corpus/intl-grapheme-conformance/main.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/intl-grapheme.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/intl-grapheme.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/object-spread-computed.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/object-spread-computed.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/optional-native-callables.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/optional-native-callables.js"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/process-builtin-values.js": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/process-builtin-values.js"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/process-versions-storage.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/process-versions-storage.ts"
|
||||
],
|
||||
"diags": []
|
||||
},
|
||||
"<repo>/tests/corpus/regexp-optional-constructor.ts": {
|
||||
"order": [
|
||||
"<repo>/tests/corpus/regexp-optional-constructor.ts"
|
||||
],
|
||||
"diags": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ const any = (...features) => ({ any: features });
|
||||
const all = (...features) => ({ all: features });
|
||||
|
||||
const BASE_RUNTIME_SOURCES = [
|
||||
"scr_number.c", "scr_string.c", "scr_array.c", "scr_bytes.c",
|
||||
"scr_number.c", "scr_string.c", "scr_grapheme.c", "scr_array.c", "scr_bytes.c",
|
||||
"scr_bytes_io.c", "scr_map.c", "scr_closure.c", "scr_ffi.c",
|
||||
"scr_object.c", "scr_union.c", "scr_exception.c", "scr_error.c",
|
||||
"scr_console.c", "scr_lib.c", "scr_path.c", "scr_url.c", "scr_json.c",
|
||||
"scr_console.c", "scr_lib.c", "scr_path.c", "scr_url.c", "scr_json.c", "scr_node_builtin.c",
|
||||
"scr_async.c", "scr_crypto_async.c", "scr_child.c", "scr_cycle.c",
|
||||
];
|
||||
|
||||
|
||||
@@ -165,6 +165,7 @@ async function build() {
|
||||
[join(runtimeRoot, "LICENSE"), "artifacts/licenses/scriptc-runtime.txt", "Apache-2.0"],
|
||||
[join(quickjs, "LICENSE"), "artifacts/licenses/quickjs-ng.txt", "MIT"],
|
||||
[join(vendorRoot, "ryu", "LICENSE-Boost"), "artifacts/licenses/ryu.txt", "BSL-1.0"],
|
||||
[join(vendorRoot, "unicode", "LICENSE"), "artifacts/licenses/unicode.txt", "Unicode-3.0"],
|
||||
[join(zlib, "LICENSE"), "artifacts/licenses/zlib.txt", "Zlib"],
|
||||
[join(mbedtls, "LICENSE"), "artifacts/licenses/mbedtls.txt", "Apache-2.0"],
|
||||
];
|
||||
|
||||
@@ -7,10 +7,10 @@ const any = (...features) => ({ any: features });
|
||||
const all = (...features) => ({ all: features });
|
||||
|
||||
const BASE_RUNTIME_SOURCES = [
|
||||
"scr_number.c", "scr_string.c", "scr_array.c", "scr_bytes.c",
|
||||
"scr_number.c", "scr_string.c", "scr_grapheme.c", "scr_array.c", "scr_bytes.c",
|
||||
"scr_bytes_io.c", "scr_map.c", "scr_closure.c", "scr_ffi.c",
|
||||
"scr_object.c", "scr_union.c", "scr_exception.c", "scr_error.c",
|
||||
"scr_console.c", "scr_lib.c", "scr_path.c", "scr_url.c", "scr_json.c",
|
||||
"scr_console.c", "scr_lib.c", "scr_path.c", "scr_url.c", "scr_json.c", "scr_node_builtin.c",
|
||||
"scr_async.c", "scr_crypto_async.c", "scr_child.c", "scr_cycle.c",
|
||||
];
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ async function build() {
|
||||
await assertArtifactsExcludeStrings(stagedOutputRoot, config.forbiddenArtifactStrings ?? []);
|
||||
const archiveSpecs = new Map(matrix.archives.map((entry) => [entry.id, entry]));
|
||||
const licensed = [[join(runtimeRoot, "LICENSE"), "artifacts/licenses/scriptc-runtime.txt", "Apache-2.0"], [join(quickjs, "LICENSE"), "artifacts/licenses/quickjs-ng.txt", "MIT"], [join(vendorRoot, "ryu", "LICENSE-Boost"), "artifacts/licenses/ryu.txt", "BSL-1.0"], [join(zlib, "LICENSE"), "artifacts/licenses/zlib.txt", "Zlib"], [join(mbedtls, "LICENSE"), "artifacts/licenses/mbedtls.txt", "Apache-2.0"]];
|
||||
licensed.push([join(vendorRoot, "unicode", "LICENSE"), "artifacts/licenses/unicode.txt", "Unicode-3.0"]);
|
||||
await Promise.all(licensed.map(async ([source, destination]) => { const output = join(buildRoot, destination); await mkdir(dirname(output), { recursive: true }); await copyFile(source, output); }));
|
||||
const manifest = { schema: "scriptc.runtime-pack.v1", format: 1, package: packageManifest.name, version: packageManifest.version, target: matrix.target, runtime_abi: { version: 3, marker: "scr_runtime_abi_v3" }, compiler: { command: compiler, identity: compilerVersion, target: matrix.target.llvm_triple }, macros: { executable: ["SCR_DYNAMIC", "SCR_TEXT_DECODER_LEGACY"], excluded: ["SCR_LIB", "SCR_THREAD_INSTANCES", "SCR_RC_AUDIT", "SCR_ASAN_FIBERS"], sanitizer: "external-toolchain-required" }, flavors, archives: archives.map((entry) => ({ ...entry, predicate: archiveSpecs.get(entry.id).predicate })), system_libraries: matrix.system_libraries, licenses: licensed.map(([, path, license]) => ({ path, license })) };
|
||||
await writeFile(stagedManifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
|
||||
@@ -40,6 +40,7 @@ static ScrBytes *scr_bytes_alloc(ScrBytesElem elem, size_t len) {
|
||||
b->data = calloc(len ? len : 1, scr_bytes_elem_size(elem));
|
||||
if (!b->data) scr_bytes_oom();
|
||||
b->backing = NULL;
|
||||
b->is_buffer = false;
|
||||
#ifdef SCR_RC_AUDIT
|
||||
scr_live_bytes++;
|
||||
#endif
|
||||
@@ -78,6 +79,11 @@ ScrBytes *scr_bytes_copy(const ScrBytes *src) {
|
||||
return b;
|
||||
}
|
||||
|
||||
ScrBytes *scr_bytes_as_buffer(ScrBytes *bytes) {
|
||||
bytes->is_buffer = true;
|
||||
return scr_bytes_retain(bytes);
|
||||
}
|
||||
|
||||
ScrBytes *scr_bytes_convert(ScrBytesElem elem, const ScrBytes *src) {
|
||||
if (elem == src->elem) return scr_bytes_copy(src);
|
||||
ScrBytes *out = scr_bytes_alloc(elem, src->len);
|
||||
@@ -262,6 +268,7 @@ ScrBytes *scr_bytes_subarray(ScrBytes *b, double start, double end) {
|
||||
v->elem = b->elem;
|
||||
v->data = b->data + s * scr_bytes_elem_size(b->elem);
|
||||
v->backing = scr_bytes_retain(owner);
|
||||
v->is_buffer = b->is_buffer;
|
||||
#ifdef SCR_RC_AUDIT
|
||||
scr_live_bytes++;
|
||||
#endif
|
||||
@@ -365,6 +372,7 @@ ScrBytes *scr_bytes_from_dyn(ScrBytesElem elem, const ScrDyn *value, bool from)
|
||||
return out;
|
||||
}
|
||||
if (value->kind == SCR_DYN_BYTES) return scr_bytes_convert(elem, value->v.bytes);
|
||||
if (!from && scr_array_buffer_is(value)) return scr_array_buffer_view(elem, value, scr_dyn_undefined(), scr_dyn_undefined());
|
||||
if (!from && (value->kind == SCR_DYN_NUM || value->kind == SCR_DYN_BOOL ||
|
||||
value->kind == SCR_DYN_STR || value->kind == SCR_DYN_NULL || value->kind == SCR_DYN_UNDEF)) {
|
||||
double number;
|
||||
@@ -472,12 +480,36 @@ ScrBytes *scr_dataview_new(ScrBytes *src, double byte_off, bool has_len, double
|
||||
v->elem = SCR_BYTES_U8;
|
||||
v->data = owner->data + (size_t)off;
|
||||
v->backing = scr_bytes_retain(owner);
|
||||
v->is_buffer = false;
|
||||
#ifdef SCR_RC_AUDIT
|
||||
scr_live_bytes++;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
ScrBytes *scr_bytes_buffer_view(ScrBytes *src, ScrBytesElem elem,
|
||||
double offset, bool has_len, double length) {
|
||||
ScrBytes *owner = src->backing ? src->backing : src;
|
||||
size_t width = scr_bytes_elem_size(elem);
|
||||
double available = scr_bytes_byte_len(owner);
|
||||
double off = isnan(offset) ? 0 : trunc(offset);
|
||||
double count = isnan(length) ? 0 : trunc(length);
|
||||
if (off < 0 || off > 9007199254740991.0 || off > available ||
|
||||
fmod(off, (double)width) != 0 ||
|
||||
(has_len && (count < 0 || count > 9007199254740991.0 || count > (available - off) / (double)width)) ||
|
||||
(!has_len && fmod(available - off, (double)width) != 0)) {
|
||||
static const char msg[] = "Invalid typed array buffer range";
|
||||
scr_throw_error_msg(SCR_ERR_RANGE, msg, sizeof msg - 1);
|
||||
return NULL;
|
||||
}
|
||||
ScrBytes *view = scr_dataview_new(owner, off, true,
|
||||
has_len ? count * (double)width : available - off);
|
||||
if (!view) return NULL;
|
||||
view->elem = elem;
|
||||
view->len /= width;
|
||||
return view;
|
||||
}
|
||||
|
||||
static size_t scr_dataview_get_size(ScrDataViewGet kind) {
|
||||
switch (kind) {
|
||||
case SCR_DV_U8:
|
||||
|
||||
@@ -70,7 +70,7 @@ ScrDyn *scr_fs_read_file_sync_dyn(ScrStr *path, const ScrDyn *enc) {
|
||||
if (enc->kind == SCR_DYN_UNDEF || enc->kind == SCR_DYN_NULL) {
|
||||
ScrBytes *b = scr_fs_read_file_bytes(path);
|
||||
if (!b) return NULL;
|
||||
ScrDyn *d = scr_dyn_new_buffer_copy(b);
|
||||
ScrDyn *d = scr_dyn_new_buffer(b);
|
||||
scr_bytes_release(b);
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -757,15 +757,15 @@ static ScrDyn *scr_dyn_invoke_impl(
|
||||
return scr_dyn_new_num((double)bytes->data[(size_t)idx]);
|
||||
}
|
||||
if (dyn_name_is(method, "slice") || dyn_name_is(method, "subarray")) {
|
||||
/* Both COPY (no views in this runtime — the static lane's
|
||||
* documented divergence for subarray/Buffer.slice); the result
|
||||
* keeps the receiver's Buffer flavor. */
|
||||
/* subarray and Buffer.slice alias their source. TypedArray.slice
|
||||
* owns an independent copy; all keep the receiver's Buffer flavor. */
|
||||
double startD = dyn_index_arg(args, argc, 0, 0, what);
|
||||
if (scr_exc_pending()) return NULL;
|
||||
double endD = dyn_index_arg(args, argc, 1, (double)blen, what);
|
||||
if (scr_exc_pending()) return NULL;
|
||||
ScrBytes *out = scr_bytes_slice(bytes, startD, endD);
|
||||
ScrDyn *d = recv->buffer ? scr_dyn_new_buffer_copy(out) : scr_dyn_new_bytes_copy(out);
|
||||
ScrBytes *out = recv->buffer || dyn_name_is(method, "subarray")
|
||||
? scr_bytes_subarray(bytes, startD, endD) : scr_bytes_slice(bytes, startD, endD);
|
||||
ScrDyn *d = recv->buffer ? scr_dyn_new_buffer(out) : scr_dyn_new_bytes(out);
|
||||
scr_bytes_release(out);
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -1640,7 +1640,7 @@ static void sf_collector_finish(SfStream *s) {
|
||||
value = scr_dyn_new_str(text);
|
||||
scr_str_release(text);
|
||||
} else {
|
||||
value = scr_dyn_new_bytes_copy(bytes);
|
||||
value = scr_dyn_new_bytes(bytes);
|
||||
}
|
||||
scr_bytes_release(bytes);
|
||||
if (scr_exc_pending()) {
|
||||
@@ -1842,7 +1842,7 @@ static void sf_stream_enqueue_value(SfStream *s, ScrDyn *value) {
|
||||
}
|
||||
|
||||
static void sf_stream_enqueue_bytes(SfStream *s, ScrBytes *bytes) {
|
||||
ScrDyn *value = scr_dyn_new_bytes_copy(bytes);
|
||||
ScrDyn *value = scr_dyn_new_bytes(bytes);
|
||||
sf_stream_enqueue_value(s, value);
|
||||
scr_dyn_release(value);
|
||||
}
|
||||
@@ -3207,7 +3207,7 @@ static ScrPromise *sf_response_collect(SfResponse *r, int mode) {
|
||||
scr_str_release(empty);
|
||||
} else {
|
||||
ScrBytes *empty = scr_bytes_new(SCR_BYTES_U8, 0);
|
||||
value = scr_dyn_new_bytes_copy(empty);
|
||||
value = scr_dyn_new_bytes(empty);
|
||||
scr_bytes_release(empty);
|
||||
}
|
||||
if (scr_exc_pending()) {
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/* Native Intl.Segmenter for default extended grapheme clusters, UAX #29.
|
||||
* Unicode 17 tables are independent of the host locale and need no engine.
|
||||
* Word/sentence segmentation and locale negotiation remain unsupported. */
|
||||
#include "scr_runtime.h"
|
||||
#include "scr_grapheme_data.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static unsigned scr_grapheme_property(uint32_t cp) {
|
||||
if (cp >= 0xac00 && cp <= 0xd7a3)
|
||||
return (cp - 0xac00) % 28 == 0 ? SCR_GCB_LV : SCR_GCB_LVT;
|
||||
size_t lo = 0, hi = sizeof scr_grapheme_ranges / sizeof *scr_grapheme_ranges;
|
||||
while (lo < hi) {
|
||||
size_t mid = lo + (hi - lo) / 2;
|
||||
const ScrGraphemeRange *range = &scr_grapheme_ranges[mid];
|
||||
if (cp < range->start) hi = mid;
|
||||
else if (cp > range->end) lo = mid + 1;
|
||||
else return range->properties;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ScrStr storage is well-formed UTF-8. Public offsets count UTF-16 units. */
|
||||
static uint32_t scr_grapheme_decode(const char *data, size_t *size) {
|
||||
const unsigned char *p = (const unsigned char *)data;
|
||||
if (p[0] < 0x80) { *size = 1; return p[0]; }
|
||||
if (p[0] < 0xe0) { *size = 2; return ((p[0] & 31u) << 6) | (p[1] & 63u); }
|
||||
if (p[0] < 0xf0) {
|
||||
*size = 3;
|
||||
return ((p[0] & 15u) << 12) | ((p[1] & 63u) << 6) | (p[2] & 63u);
|
||||
}
|
||||
*size = 4;
|
||||
return ((p[0] & 7u) << 18) | ((p[1] & 63u) << 12) | ((p[2] & 63u) << 6) | (p[3] & 63u);
|
||||
}
|
||||
|
||||
static bool scr_grapheme_control(unsigned gcb) {
|
||||
return gcb == SCR_GCB_CR || gcb == SCR_GCB_LF || gcb == SCR_GCB_CONTROL;
|
||||
}
|
||||
|
||||
/* One cluster, linear in the bytes visited. Context states encode the
|
||||
* look-behind rules GB9c, GB11 and GB12/13 without rescanning the prefix. */
|
||||
static size_t scr_grapheme_next(const ScrStr *input, size_t start, size_t *units) {
|
||||
unsigned previous = SCR_GCB_OTHER;
|
||||
bool ep_extend = false, ep_zwj = false;
|
||||
unsigned indic = 0, ri_parity = 0;
|
||||
size_t at = start;
|
||||
*units = 0;
|
||||
while (at < input->len) {
|
||||
size_t size;
|
||||
uint32_t cp = scr_grapheme_decode(input->data + at, &size);
|
||||
unsigned property = scr_grapheme_property(cp);
|
||||
unsigned current = property & 15u, incb = (property >> 4) & 3u;
|
||||
bool pictographic = (property & 64u) != 0;
|
||||
if (at != start) {
|
||||
bool join;
|
||||
if (previous == SCR_GCB_CR && current == SCR_GCB_LF) join = true; /* GB3 */
|
||||
else if (scr_grapheme_control(previous) || scr_grapheme_control(current)) join = false; /* GB4/5 */
|
||||
else if (previous == SCR_GCB_L && (current == SCR_GCB_L || current == SCR_GCB_V || current == SCR_GCB_LV || current == SCR_GCB_LVT)) join = true; /* GB6 */
|
||||
else if ((previous == SCR_GCB_LV || previous == SCR_GCB_V) && (current == SCR_GCB_V || current == SCR_GCB_T)) join = true; /* GB7 */
|
||||
else if ((previous == SCR_GCB_LVT || previous == SCR_GCB_T) && current == SCR_GCB_T) join = true; /* GB8 */
|
||||
else if (current == SCR_GCB_EXTEND || current == SCR_GCB_ZWJ || current == SCR_GCB_SPACINGMARK) join = true; /* GB9/9a */
|
||||
else if (previous == SCR_GCB_PREPEND) join = true; /* GB9b */
|
||||
else if (incb == 1 && indic == 2) join = true; /* GB9c: consonant, linker, consonant */
|
||||
else if (pictographic && previous == SCR_GCB_ZWJ && ep_zwj) join = true; /* GB11 */
|
||||
else join = current == SCR_GCB_REGIONAL_INDICATOR && previous == SCR_GCB_REGIONAL_INDICATOR && ri_parity; /* GB12/13, GB999 */
|
||||
if (!join) break;
|
||||
}
|
||||
ep_zwj = current == SCR_GCB_ZWJ && ep_extend;
|
||||
ep_extend = pictographic || (current == SCR_GCB_EXTEND && ep_extend);
|
||||
if (incb == 1) indic = 1;
|
||||
else if (incb == 3 && indic) indic = 2;
|
||||
else if (incb != 2 && incb != 3) indic = 0;
|
||||
ri_parity = current == SCR_GCB_REGIONAL_INDICATOR ? ri_parity ^ 1u : 0;
|
||||
previous = current;
|
||||
*units += cp > 0xffff ? 2 : 1;
|
||||
at += size;
|
||||
}
|
||||
return at;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t rc;
|
||||
ScrStr *input; /* NULL for Segmenter, retained text for Segments */
|
||||
} ScrGraphemes;
|
||||
|
||||
static void *scr_graphemes_retain(void *ptr) {
|
||||
ScrGraphemes *value = ptr;
|
||||
value->rc++;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void scr_graphemes_release(void *ptr) {
|
||||
ScrGraphemes *value = ptr;
|
||||
if (--value->rc) return;
|
||||
scr_str_release(value->input);
|
||||
free(value);
|
||||
}
|
||||
|
||||
static ScrDyn *scr_graphemes_box(ScrStr *input, ScrDynHandleTag tag) {
|
||||
ScrGraphemes *value = calloc(1, sizeof *value);
|
||||
if (!value) scr_trap("scriptc: out of memory\n");
|
||||
value->rc = 1;
|
||||
value->input = input; /* takes ownership */
|
||||
ScrDyn *boxed = scr_dyn_new_handle(value, tag);
|
||||
scr_graphemes_release(value);
|
||||
return boxed;
|
||||
}
|
||||
|
||||
static ScrDyn *scr_grapheme_record(ScrStr *input, size_t start, size_t end, size_t index) {
|
||||
ScrDyn *record = scr_dyn_new_obj();
|
||||
ScrStr *segment = scr_str_new(input->data + start, end - start);
|
||||
scr_dyn_obj_set(record, "segment", 7, scr_dyn_new_str(segment));
|
||||
scr_str_release(segment);
|
||||
scr_dyn_obj_set(record, "index", 5, scr_dyn_new_num((double)index));
|
||||
scr_dyn_obj_set(record, "input", 5, scr_dyn_new_str(input));
|
||||
return record;
|
||||
}
|
||||
|
||||
static ScrDyn *scr_graphemes_iter(void *ptr) {
|
||||
ScrStr *input = ((ScrGraphemes *)ptr)->input;
|
||||
ScrDyn *result = scr_dyn_new_arr();
|
||||
size_t index = 0;
|
||||
for (size_t start = 0; start < input->len;) {
|
||||
size_t units;
|
||||
size_t end = scr_grapheme_next(input, start, &units);
|
||||
scr_dyn_arr_push(result, scr_grapheme_record(input, start, end, index));
|
||||
index += units;
|
||||
start = end;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ScrDyn *scr_graphemes_invoke(void *ptr, ScrDyn *self, const char *method,
|
||||
ScrDyn *const *args, size_t argc, const char *what) {
|
||||
(void)self;
|
||||
ScrGraphemes *value = ptr;
|
||||
ScrDyn *arg = argc ? args[0] : scr_dyn_undefined();
|
||||
if (!value->input && strcmp(method, "segment") == 0) {
|
||||
ScrStr *input = scr_dyn_string_coerce_js(arg);
|
||||
if (!input) return NULL;
|
||||
return scr_graphemes_box(input, SCR_DYNH_SEGMENTS);
|
||||
}
|
||||
if (value->input && strcmp(method, "containing") == 0) {
|
||||
double index;
|
||||
if (!scr_dyn_number_coerce_js(arg, &index)) return NULL;
|
||||
index = isnan(index) ? 0 : trunc(index);
|
||||
if (index >= 0 && isfinite(index)) {
|
||||
size_t offset = 0;
|
||||
for (size_t start = 0; start < value->input->len;) {
|
||||
size_t units;
|
||||
size_t end = scr_grapheme_next(value->input, start, &units);
|
||||
if (index < (double)(offset + units)) return scr_grapheme_record(value->input, start, end, offset);
|
||||
offset += units;
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
return scr_dyn_retain(scr_dyn_undefined());
|
||||
}
|
||||
if (!value->input && strcmp(method, "resolvedOptions") == 0) {
|
||||
static const char msg[] = "Intl.Segmenter locale negotiation is not supported yet";
|
||||
scr_throw_error_msg(SCR_ERR_ERROR, msg, sizeof msg - 1);
|
||||
return NULL;
|
||||
}
|
||||
ScrJsonBuf message;
|
||||
scr_jb_init(&message);
|
||||
scr_jb_puts(&message, what);
|
||||
scr_jb_puts(&message, " is not a function");
|
||||
scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&message));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ScrDyn *scr_graphemes_get(void *ptr, const char *key, size_t len) {
|
||||
ScrGraphemes *value = ptr;
|
||||
if ((!value->input && ((len == 7 && memcmp(key, "segment", len) == 0) ||
|
||||
(len == 15 && memcmp(key, "resolvedOptions", len) == 0))) ||
|
||||
(value->input && len == 10 && memcmp(key, "containing", len) == 0)) {
|
||||
static const char msg[] = "stored Intl.Segmenter methods are not supported yet";
|
||||
scr_throw_error_msg(SCR_ERR_ERROR, msg, sizeof msg - 1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool scr_graphemes_set(void *ptr, const char *key, size_t len, const ScrDyn *value) {
|
||||
(void)ptr; (void)key; (void)len; (void)value;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScrDyn *scr_intl_segmenter_new(void) {
|
||||
static const ScrDynHandleOps segmenter = {
|
||||
.cls = "Segmenter", .retain = scr_graphemes_retain, .release = scr_graphemes_release,
|
||||
.invoke = scr_graphemes_invoke, .get = scr_graphemes_get, .set = scr_graphemes_set,
|
||||
};
|
||||
static const ScrDynHandleOps segments = {
|
||||
.cls = "Segments", .retain = scr_graphemes_retain, .release = scr_graphemes_release,
|
||||
.invoke = scr_graphemes_invoke, .get = scr_graphemes_get, .set = scr_graphemes_set,
|
||||
.iter_pack = scr_graphemes_iter,
|
||||
};
|
||||
scr_dyn_handle_install(SCR_DYNH_SEGMENTER, &segmenter);
|
||||
scr_dyn_handle_install(SCR_DYNH_SEGMENTS, &segments);
|
||||
return scr_graphemes_box(NULL, SCR_DYNH_SEGMENTER);
|
||||
}
|
||||
@@ -0,0 +1,842 @@
|
||||
/* Generated by scripts/gen-grapheme-tables.mjs; Unicode 17.0.0.
|
||||
* Unicode data is licensed under vendor/unicode/LICENSE. Do not edit. */
|
||||
#ifndef SCR_GRAPHEME_DATA_H
|
||||
#define SCR_GRAPHEME_DATA_H
|
||||
enum { SCR_GCB_OTHER = 0, SCR_GCB_CR = 1, SCR_GCB_LF = 2, SCR_GCB_CONTROL = 3, SCR_GCB_EXTEND = 4, SCR_GCB_ZWJ = 5, SCR_GCB_REGIONAL_INDICATOR = 6, SCR_GCB_PREPEND = 7, SCR_GCB_SPACINGMARK = 8, SCR_GCB_L = 9, SCR_GCB_V = 10, SCR_GCB_T = 11, SCR_GCB_LV = 12, SCR_GCB_LVT = 13 };
|
||||
typedef struct { uint32_t start, end; uint8_t properties; } ScrGraphemeRange;
|
||||
static const ScrGraphemeRange scr_grapheme_ranges[] = {
|
||||
{ 0x0, 0x9, 3 },
|
||||
{ 0xa, 0xa, 2 },
|
||||
{ 0xb, 0xc, 3 },
|
||||
{ 0xd, 0xd, 1 },
|
||||
{ 0xe, 0x1f, 3 },
|
||||
{ 0x7f, 0x9f, 3 },
|
||||
{ 0xa9, 0xa9, 64 },
|
||||
{ 0xad, 0xad, 3 },
|
||||
{ 0xae, 0xae, 64 },
|
||||
{ 0x300, 0x36f, 36 },
|
||||
{ 0x483, 0x489, 36 },
|
||||
{ 0x591, 0x5bd, 36 },
|
||||
{ 0x5bf, 0x5bf, 36 },
|
||||
{ 0x5c1, 0x5c2, 36 },
|
||||
{ 0x5c4, 0x5c5, 36 },
|
||||
{ 0x5c7, 0x5c7, 36 },
|
||||
{ 0x600, 0x605, 7 },
|
||||
{ 0x610, 0x61a, 36 },
|
||||
{ 0x61c, 0x61c, 3 },
|
||||
{ 0x64b, 0x65f, 36 },
|
||||
{ 0x670, 0x670, 36 },
|
||||
{ 0x6d6, 0x6dc, 36 },
|
||||
{ 0x6dd, 0x6dd, 7 },
|
||||
{ 0x6df, 0x6e4, 36 },
|
||||
{ 0x6e7, 0x6e8, 36 },
|
||||
{ 0x6ea, 0x6ed, 36 },
|
||||
{ 0x70f, 0x70f, 7 },
|
||||
{ 0x711, 0x711, 36 },
|
||||
{ 0x730, 0x74a, 36 },
|
||||
{ 0x7a6, 0x7b0, 36 },
|
||||
{ 0x7eb, 0x7f3, 36 },
|
||||
{ 0x7fd, 0x7fd, 36 },
|
||||
{ 0x816, 0x819, 36 },
|
||||
{ 0x81b, 0x823, 36 },
|
||||
{ 0x825, 0x827, 36 },
|
||||
{ 0x829, 0x82d, 36 },
|
||||
{ 0x859, 0x85b, 36 },
|
||||
{ 0x890, 0x891, 7 },
|
||||
{ 0x897, 0x89f, 36 },
|
||||
{ 0x8ca, 0x8e1, 36 },
|
||||
{ 0x8e2, 0x8e2, 7 },
|
||||
{ 0x8e3, 0x902, 36 },
|
||||
{ 0x903, 0x903, 8 },
|
||||
{ 0x915, 0x939, 16 },
|
||||
{ 0x93a, 0x93a, 36 },
|
||||
{ 0x93b, 0x93b, 8 },
|
||||
{ 0x93c, 0x93c, 36 },
|
||||
{ 0x93e, 0x940, 8 },
|
||||
{ 0x941, 0x948, 36 },
|
||||
{ 0x949, 0x94c, 8 },
|
||||
{ 0x94d, 0x94d, 52 },
|
||||
{ 0x94e, 0x94f, 8 },
|
||||
{ 0x951, 0x957, 36 },
|
||||
{ 0x958, 0x95f, 16 },
|
||||
{ 0x962, 0x963, 36 },
|
||||
{ 0x978, 0x97f, 16 },
|
||||
{ 0x981, 0x981, 36 },
|
||||
{ 0x982, 0x983, 8 },
|
||||
{ 0x995, 0x9a8, 16 },
|
||||
{ 0x9aa, 0x9b0, 16 },
|
||||
{ 0x9b2, 0x9b2, 16 },
|
||||
{ 0x9b6, 0x9b9, 16 },
|
||||
{ 0x9bc, 0x9bc, 36 },
|
||||
{ 0x9be, 0x9be, 36 },
|
||||
{ 0x9bf, 0x9c0, 8 },
|
||||
{ 0x9c1, 0x9c4, 36 },
|
||||
{ 0x9c7, 0x9c8, 8 },
|
||||
{ 0x9cb, 0x9cc, 8 },
|
||||
{ 0x9cd, 0x9cd, 52 },
|
||||
{ 0x9d7, 0x9d7, 36 },
|
||||
{ 0x9dc, 0x9dd, 16 },
|
||||
{ 0x9df, 0x9df, 16 },
|
||||
{ 0x9e2, 0x9e3, 36 },
|
||||
{ 0x9f0, 0x9f1, 16 },
|
||||
{ 0x9fe, 0x9fe, 36 },
|
||||
{ 0xa01, 0xa02, 36 },
|
||||
{ 0xa03, 0xa03, 8 },
|
||||
{ 0xa3c, 0xa3c, 36 },
|
||||
{ 0xa3e, 0xa40, 8 },
|
||||
{ 0xa41, 0xa42, 36 },
|
||||
{ 0xa47, 0xa48, 36 },
|
||||
{ 0xa4b, 0xa4d, 36 },
|
||||
{ 0xa51, 0xa51, 36 },
|
||||
{ 0xa70, 0xa71, 36 },
|
||||
{ 0xa75, 0xa75, 36 },
|
||||
{ 0xa81, 0xa82, 36 },
|
||||
{ 0xa83, 0xa83, 8 },
|
||||
{ 0xa95, 0xaa8, 16 },
|
||||
{ 0xaaa, 0xab0, 16 },
|
||||
{ 0xab2, 0xab3, 16 },
|
||||
{ 0xab5, 0xab9, 16 },
|
||||
{ 0xabc, 0xabc, 36 },
|
||||
{ 0xabe, 0xac0, 8 },
|
||||
{ 0xac1, 0xac5, 36 },
|
||||
{ 0xac7, 0xac8, 36 },
|
||||
{ 0xac9, 0xac9, 8 },
|
||||
{ 0xacb, 0xacc, 8 },
|
||||
{ 0xacd, 0xacd, 52 },
|
||||
{ 0xae2, 0xae3, 36 },
|
||||
{ 0xaf9, 0xaf9, 16 },
|
||||
{ 0xafa, 0xaff, 36 },
|
||||
{ 0xb01, 0xb01, 36 },
|
||||
{ 0xb02, 0xb03, 8 },
|
||||
{ 0xb15, 0xb28, 16 },
|
||||
{ 0xb2a, 0xb30, 16 },
|
||||
{ 0xb32, 0xb33, 16 },
|
||||
{ 0xb35, 0xb39, 16 },
|
||||
{ 0xb3c, 0xb3c, 36 },
|
||||
{ 0xb3e, 0xb3f, 36 },
|
||||
{ 0xb40, 0xb40, 8 },
|
||||
{ 0xb41, 0xb44, 36 },
|
||||
{ 0xb47, 0xb48, 8 },
|
||||
{ 0xb4b, 0xb4c, 8 },
|
||||
{ 0xb4d, 0xb4d, 52 },
|
||||
{ 0xb55, 0xb57, 36 },
|
||||
{ 0xb5c, 0xb5d, 16 },
|
||||
{ 0xb5f, 0xb5f, 16 },
|
||||
{ 0xb62, 0xb63, 36 },
|
||||
{ 0xb71, 0xb71, 16 },
|
||||
{ 0xb82, 0xb82, 36 },
|
||||
{ 0xbbe, 0xbbe, 36 },
|
||||
{ 0xbbf, 0xbbf, 8 },
|
||||
{ 0xbc0, 0xbc0, 36 },
|
||||
{ 0xbc1, 0xbc2, 8 },
|
||||
{ 0xbc6, 0xbc8, 8 },
|
||||
{ 0xbca, 0xbcc, 8 },
|
||||
{ 0xbcd, 0xbcd, 36 },
|
||||
{ 0xbd7, 0xbd7, 36 },
|
||||
{ 0xc00, 0xc00, 36 },
|
||||
{ 0xc01, 0xc03, 8 },
|
||||
{ 0xc04, 0xc04, 36 },
|
||||
{ 0xc15, 0xc28, 16 },
|
||||
{ 0xc2a, 0xc39, 16 },
|
||||
{ 0xc3c, 0xc3c, 36 },
|
||||
{ 0xc3e, 0xc40, 36 },
|
||||
{ 0xc41, 0xc44, 8 },
|
||||
{ 0xc46, 0xc48, 36 },
|
||||
{ 0xc4a, 0xc4c, 36 },
|
||||
{ 0xc4d, 0xc4d, 52 },
|
||||
{ 0xc55, 0xc56, 36 },
|
||||
{ 0xc58, 0xc5a, 16 },
|
||||
{ 0xc62, 0xc63, 36 },
|
||||
{ 0xc81, 0xc81, 36 },
|
||||
{ 0xc82, 0xc83, 8 },
|
||||
{ 0xcbc, 0xcbc, 36 },
|
||||
{ 0xcbe, 0xcbe, 8 },
|
||||
{ 0xcbf, 0xcc0, 36 },
|
||||
{ 0xcc1, 0xcc1, 8 },
|
||||
{ 0xcc2, 0xcc2, 36 },
|
||||
{ 0xcc3, 0xcc4, 8 },
|
||||
{ 0xcc6, 0xcc8, 36 },
|
||||
{ 0xcca, 0xccd, 36 },
|
||||
{ 0xcd5, 0xcd6, 36 },
|
||||
{ 0xce2, 0xce3, 36 },
|
||||
{ 0xcf3, 0xcf3, 8 },
|
||||
{ 0xd00, 0xd01, 36 },
|
||||
{ 0xd02, 0xd03, 8 },
|
||||
{ 0xd15, 0xd3a, 16 },
|
||||
{ 0xd3b, 0xd3c, 36 },
|
||||
{ 0xd3e, 0xd3e, 36 },
|
||||
{ 0xd3f, 0xd40, 8 },
|
||||
{ 0xd41, 0xd44, 36 },
|
||||
{ 0xd46, 0xd48, 8 },
|
||||
{ 0xd4a, 0xd4c, 8 },
|
||||
{ 0xd4d, 0xd4d, 52 },
|
||||
{ 0xd4e, 0xd4e, 7 },
|
||||
{ 0xd57, 0xd57, 36 },
|
||||
{ 0xd62, 0xd63, 36 },
|
||||
{ 0xd81, 0xd81, 36 },
|
||||
{ 0xd82, 0xd83, 8 },
|
||||
{ 0xdca, 0xdca, 36 },
|
||||
{ 0xdcf, 0xdcf, 36 },
|
||||
{ 0xdd0, 0xdd1, 8 },
|
||||
{ 0xdd2, 0xdd4, 36 },
|
||||
{ 0xdd6, 0xdd6, 36 },
|
||||
{ 0xdd8, 0xdde, 8 },
|
||||
{ 0xddf, 0xddf, 36 },
|
||||
{ 0xdf2, 0xdf3, 8 },
|
||||
{ 0xe31, 0xe31, 36 },
|
||||
{ 0xe33, 0xe33, 8 },
|
||||
{ 0xe34, 0xe3a, 36 },
|
||||
{ 0xe47, 0xe4e, 36 },
|
||||
{ 0xeb1, 0xeb1, 36 },
|
||||
{ 0xeb3, 0xeb3, 8 },
|
||||
{ 0xeb4, 0xebc, 36 },
|
||||
{ 0xec8, 0xece, 36 },
|
||||
{ 0xf18, 0xf19, 36 },
|
||||
{ 0xf35, 0xf35, 36 },
|
||||
{ 0xf37, 0xf37, 36 },
|
||||
{ 0xf39, 0xf39, 36 },
|
||||
{ 0xf3e, 0xf3f, 8 },
|
||||
{ 0xf71, 0xf7e, 36 },
|
||||
{ 0xf7f, 0xf7f, 8 },
|
||||
{ 0xf80, 0xf84, 36 },
|
||||
{ 0xf86, 0xf87, 36 },
|
||||
{ 0xf8d, 0xf97, 36 },
|
||||
{ 0xf99, 0xfbc, 36 },
|
||||
{ 0xfc6, 0xfc6, 36 },
|
||||
{ 0x1000, 0x102a, 16 },
|
||||
{ 0x102d, 0x1030, 36 },
|
||||
{ 0x1031, 0x1031, 8 },
|
||||
{ 0x1032, 0x1037, 36 },
|
||||
{ 0x1039, 0x1039, 52 },
|
||||
{ 0x103a, 0x103a, 36 },
|
||||
{ 0x103b, 0x103c, 8 },
|
||||
{ 0x103d, 0x103e, 36 },
|
||||
{ 0x103f, 0x103f, 16 },
|
||||
{ 0x1050, 0x1055, 16 },
|
||||
{ 0x1056, 0x1057, 8 },
|
||||
{ 0x1058, 0x1059, 36 },
|
||||
{ 0x105a, 0x105d, 16 },
|
||||
{ 0x105e, 0x1060, 36 },
|
||||
{ 0x1061, 0x1061, 16 },
|
||||
{ 0x1065, 0x1066, 16 },
|
||||
{ 0x106e, 0x1070, 16 },
|
||||
{ 0x1071, 0x1074, 36 },
|
||||
{ 0x1075, 0x1081, 16 },
|
||||
{ 0x1082, 0x1082, 36 },
|
||||
{ 0x1084, 0x1084, 8 },
|
||||
{ 0x1085, 0x1086, 36 },
|
||||
{ 0x108d, 0x108d, 36 },
|
||||
{ 0x108e, 0x108e, 16 },
|
||||
{ 0x109d, 0x109d, 36 },
|
||||
{ 0x1100, 0x115f, 9 },
|
||||
{ 0x1160, 0x11a7, 10 },
|
||||
{ 0x11a8, 0x11ff, 11 },
|
||||
{ 0x135d, 0x135f, 36 },
|
||||
{ 0x1712, 0x1715, 36 },
|
||||
{ 0x1732, 0x1734, 36 },
|
||||
{ 0x1752, 0x1753, 36 },
|
||||
{ 0x1772, 0x1773, 36 },
|
||||
{ 0x1780, 0x17b3, 16 },
|
||||
{ 0x17b4, 0x17b5, 36 },
|
||||
{ 0x17b6, 0x17b6, 8 },
|
||||
{ 0x17b7, 0x17bd, 36 },
|
||||
{ 0x17be, 0x17c5, 8 },
|
||||
{ 0x17c6, 0x17c6, 36 },
|
||||
{ 0x17c7, 0x17c8, 8 },
|
||||
{ 0x17c9, 0x17d1, 36 },
|
||||
{ 0x17d2, 0x17d2, 52 },
|
||||
{ 0x17d3, 0x17d3, 36 },
|
||||
{ 0x17dd, 0x17dd, 36 },
|
||||
{ 0x180b, 0x180d, 36 },
|
||||
{ 0x180e, 0x180e, 3 },
|
||||
{ 0x180f, 0x180f, 36 },
|
||||
{ 0x1885, 0x1886, 36 },
|
||||
{ 0x18a9, 0x18a9, 36 },
|
||||
{ 0x1920, 0x1922, 36 },
|
||||
{ 0x1923, 0x1926, 8 },
|
||||
{ 0x1927, 0x1928, 36 },
|
||||
{ 0x1929, 0x192b, 8 },
|
||||
{ 0x1930, 0x1931, 8 },
|
||||
{ 0x1932, 0x1932, 36 },
|
||||
{ 0x1933, 0x1938, 8 },
|
||||
{ 0x1939, 0x193b, 36 },
|
||||
{ 0x1a17, 0x1a18, 36 },
|
||||
{ 0x1a19, 0x1a1a, 8 },
|
||||
{ 0x1a1b, 0x1a1b, 36 },
|
||||
{ 0x1a20, 0x1a54, 16 },
|
||||
{ 0x1a55, 0x1a55, 8 },
|
||||
{ 0x1a56, 0x1a56, 36 },
|
||||
{ 0x1a57, 0x1a57, 8 },
|
||||
{ 0x1a58, 0x1a5e, 36 },
|
||||
{ 0x1a60, 0x1a60, 52 },
|
||||
{ 0x1a62, 0x1a62, 36 },
|
||||
{ 0x1a65, 0x1a6c, 36 },
|
||||
{ 0x1a6d, 0x1a72, 8 },
|
||||
{ 0x1a73, 0x1a7c, 36 },
|
||||
{ 0x1a7f, 0x1a7f, 36 },
|
||||
{ 0x1ab0, 0x1add, 36 },
|
||||
{ 0x1ae0, 0x1aeb, 36 },
|
||||
{ 0x1b00, 0x1b03, 36 },
|
||||
{ 0x1b04, 0x1b04, 8 },
|
||||
{ 0x1b0b, 0x1b0c, 16 },
|
||||
{ 0x1b13, 0x1b33, 16 },
|
||||
{ 0x1b34, 0x1b3d, 36 },
|
||||
{ 0x1b3e, 0x1b41, 8 },
|
||||
{ 0x1b42, 0x1b43, 36 },
|
||||
{ 0x1b44, 0x1b44, 52 },
|
||||
{ 0x1b45, 0x1b4c, 16 },
|
||||
{ 0x1b6b, 0x1b73, 36 },
|
||||
{ 0x1b80, 0x1b81, 36 },
|
||||
{ 0x1b82, 0x1b82, 8 },
|
||||
{ 0x1b83, 0x1ba0, 16 },
|
||||
{ 0x1ba1, 0x1ba1, 8 },
|
||||
{ 0x1ba2, 0x1ba5, 36 },
|
||||
{ 0x1ba6, 0x1ba7, 8 },
|
||||
{ 0x1ba8, 0x1baa, 36 },
|
||||
{ 0x1bab, 0x1bab, 52 },
|
||||
{ 0x1bac, 0x1bad, 36 },
|
||||
{ 0x1bae, 0x1baf, 16 },
|
||||
{ 0x1bbb, 0x1bbd, 16 },
|
||||
{ 0x1be6, 0x1be6, 36 },
|
||||
{ 0x1be7, 0x1be7, 8 },
|
||||
{ 0x1be8, 0x1be9, 36 },
|
||||
{ 0x1bea, 0x1bec, 8 },
|
||||
{ 0x1bed, 0x1bed, 36 },
|
||||
{ 0x1bee, 0x1bee, 8 },
|
||||
{ 0x1bef, 0x1bf3, 36 },
|
||||
{ 0x1c24, 0x1c2b, 8 },
|
||||
{ 0x1c2c, 0x1c33, 36 },
|
||||
{ 0x1c34, 0x1c35, 8 },
|
||||
{ 0x1c36, 0x1c37, 36 },
|
||||
{ 0x1cd0, 0x1cd2, 36 },
|
||||
{ 0x1cd4, 0x1ce0, 36 },
|
||||
{ 0x1ce1, 0x1ce1, 8 },
|
||||
{ 0x1ce2, 0x1ce8, 36 },
|
||||
{ 0x1ced, 0x1ced, 36 },
|
||||
{ 0x1cf4, 0x1cf4, 36 },
|
||||
{ 0x1cf7, 0x1cf7, 8 },
|
||||
{ 0x1cf8, 0x1cf9, 36 },
|
||||
{ 0x1dc0, 0x1dff, 36 },
|
||||
{ 0x200b, 0x200b, 3 },
|
||||
{ 0x200c, 0x200c, 4 },
|
||||
{ 0x200d, 0x200d, 37 },
|
||||
{ 0x200e, 0x200f, 3 },
|
||||
{ 0x2028, 0x202e, 3 },
|
||||
{ 0x203c, 0x203c, 64 },
|
||||
{ 0x2049, 0x2049, 64 },
|
||||
{ 0x2060, 0x206f, 3 },
|
||||
{ 0x20d0, 0x20f0, 36 },
|
||||
{ 0x2122, 0x2122, 64 },
|
||||
{ 0x2139, 0x2139, 64 },
|
||||
{ 0x2194, 0x2199, 64 },
|
||||
{ 0x21a9, 0x21aa, 64 },
|
||||
{ 0x231a, 0x231b, 64 },
|
||||
{ 0x2328, 0x2328, 64 },
|
||||
{ 0x23cf, 0x23cf, 64 },
|
||||
{ 0x23e9, 0x23f3, 64 },
|
||||
{ 0x23f8, 0x23fa, 64 },
|
||||
{ 0x24c2, 0x24c2, 64 },
|
||||
{ 0x25aa, 0x25ab, 64 },
|
||||
{ 0x25b6, 0x25b6, 64 },
|
||||
{ 0x25c0, 0x25c0, 64 },
|
||||
{ 0x25fb, 0x25fe, 64 },
|
||||
{ 0x2600, 0x2604, 64 },
|
||||
{ 0x260e, 0x260e, 64 },
|
||||
{ 0x2611, 0x2611, 64 },
|
||||
{ 0x2614, 0x2615, 64 },
|
||||
{ 0x2618, 0x2618, 64 },
|
||||
{ 0x261d, 0x261d, 64 },
|
||||
{ 0x2620, 0x2620, 64 },
|
||||
{ 0x2622, 0x2623, 64 },
|
||||
{ 0x2626, 0x2626, 64 },
|
||||
{ 0x262a, 0x262a, 64 },
|
||||
{ 0x262e, 0x262f, 64 },
|
||||
{ 0x2638, 0x263a, 64 },
|
||||
{ 0x2640, 0x2640, 64 },
|
||||
{ 0x2642, 0x2642, 64 },
|
||||
{ 0x2648, 0x2653, 64 },
|
||||
{ 0x265f, 0x2660, 64 },
|
||||
{ 0x2663, 0x2663, 64 },
|
||||
{ 0x2665, 0x2666, 64 },
|
||||
{ 0x2668, 0x2668, 64 },
|
||||
{ 0x267b, 0x267b, 64 },
|
||||
{ 0x267e, 0x267f, 64 },
|
||||
{ 0x2692, 0x2697, 64 },
|
||||
{ 0x2699, 0x2699, 64 },
|
||||
{ 0x269b, 0x269c, 64 },
|
||||
{ 0x26a0, 0x26a1, 64 },
|
||||
{ 0x26a7, 0x26a7, 64 },
|
||||
{ 0x26aa, 0x26ab, 64 },
|
||||
{ 0x26b0, 0x26b1, 64 },
|
||||
{ 0x26bd, 0x26be, 64 },
|
||||
{ 0x26c4, 0x26c5, 64 },
|
||||
{ 0x26c8, 0x26c8, 64 },
|
||||
{ 0x26ce, 0x26cf, 64 },
|
||||
{ 0x26d1, 0x26d1, 64 },
|
||||
{ 0x26d3, 0x26d4, 64 },
|
||||
{ 0x26e9, 0x26ea, 64 },
|
||||
{ 0x26f0, 0x26f5, 64 },
|
||||
{ 0x26f7, 0x26fa, 64 },
|
||||
{ 0x26fd, 0x26fd, 64 },
|
||||
{ 0x2702, 0x2702, 64 },
|
||||
{ 0x2705, 0x2705, 64 },
|
||||
{ 0x2708, 0x270d, 64 },
|
||||
{ 0x270f, 0x270f, 64 },
|
||||
{ 0x2712, 0x2712, 64 },
|
||||
{ 0x2714, 0x2714, 64 },
|
||||
{ 0x2716, 0x2716, 64 },
|
||||
{ 0x271d, 0x271d, 64 },
|
||||
{ 0x2721, 0x2721, 64 },
|
||||
{ 0x2728, 0x2728, 64 },
|
||||
{ 0x2733, 0x2734, 64 },
|
||||
{ 0x2744, 0x2744, 64 },
|
||||
{ 0x2747, 0x2747, 64 },
|
||||
{ 0x274c, 0x274c, 64 },
|
||||
{ 0x274e, 0x274e, 64 },
|
||||
{ 0x2753, 0x2755, 64 },
|
||||
{ 0x2757, 0x2757, 64 },
|
||||
{ 0x2763, 0x2764, 64 },
|
||||
{ 0x2795, 0x2797, 64 },
|
||||
{ 0x27a1, 0x27a1, 64 },
|
||||
{ 0x27b0, 0x27b0, 64 },
|
||||
{ 0x27bf, 0x27bf, 64 },
|
||||
{ 0x2934, 0x2935, 64 },
|
||||
{ 0x2b05, 0x2b07, 64 },
|
||||
{ 0x2b1b, 0x2b1c, 64 },
|
||||
{ 0x2b50, 0x2b50, 64 },
|
||||
{ 0x2b55, 0x2b55, 64 },
|
||||
{ 0x2cef, 0x2cf1, 36 },
|
||||
{ 0x2d7f, 0x2d7f, 36 },
|
||||
{ 0x2de0, 0x2dff, 36 },
|
||||
{ 0x302a, 0x302f, 36 },
|
||||
{ 0x3030, 0x3030, 64 },
|
||||
{ 0x303d, 0x303d, 64 },
|
||||
{ 0x3099, 0x309a, 36 },
|
||||
{ 0x3297, 0x3297, 64 },
|
||||
{ 0x3299, 0x3299, 64 },
|
||||
{ 0xa66f, 0xa672, 36 },
|
||||
{ 0xa674, 0xa67d, 36 },
|
||||
{ 0xa69e, 0xa69f, 36 },
|
||||
{ 0xa6f0, 0xa6f1, 36 },
|
||||
{ 0xa802, 0xa802, 36 },
|
||||
{ 0xa806, 0xa806, 36 },
|
||||
{ 0xa80b, 0xa80b, 36 },
|
||||
{ 0xa823, 0xa824, 8 },
|
||||
{ 0xa825, 0xa826, 36 },
|
||||
{ 0xa827, 0xa827, 8 },
|
||||
{ 0xa82c, 0xa82c, 36 },
|
||||
{ 0xa880, 0xa881, 8 },
|
||||
{ 0xa8b4, 0xa8c3, 8 },
|
||||
{ 0xa8c4, 0xa8c5, 36 },
|
||||
{ 0xa8e0, 0xa8f1, 36 },
|
||||
{ 0xa8ff, 0xa8ff, 36 },
|
||||
{ 0xa926, 0xa92d, 36 },
|
||||
{ 0xa947, 0xa951, 36 },
|
||||
{ 0xa952, 0xa952, 8 },
|
||||
{ 0xa953, 0xa953, 36 },
|
||||
{ 0xa960, 0xa97c, 9 },
|
||||
{ 0xa980, 0xa982, 36 },
|
||||
{ 0xa983, 0xa983, 8 },
|
||||
{ 0xa989, 0xa98b, 16 },
|
||||
{ 0xa98f, 0xa9b2, 16 },
|
||||
{ 0xa9b3, 0xa9b3, 36 },
|
||||
{ 0xa9b4, 0xa9b5, 8 },
|
||||
{ 0xa9b6, 0xa9b9, 36 },
|
||||
{ 0xa9ba, 0xa9bb, 8 },
|
||||
{ 0xa9bc, 0xa9bd, 36 },
|
||||
{ 0xa9be, 0xa9bf, 8 },
|
||||
{ 0xa9c0, 0xa9c0, 52 },
|
||||
{ 0xa9e0, 0xa9e4, 16 },
|
||||
{ 0xa9e5, 0xa9e5, 36 },
|
||||
{ 0xa9e7, 0xa9ef, 16 },
|
||||
{ 0xa9fa, 0xa9fe, 16 },
|
||||
{ 0xaa29, 0xaa2e, 36 },
|
||||
{ 0xaa2f, 0xaa30, 8 },
|
||||
{ 0xaa31, 0xaa32, 36 },
|
||||
{ 0xaa33, 0xaa34, 8 },
|
||||
{ 0xaa35, 0xaa36, 36 },
|
||||
{ 0xaa43, 0xaa43, 36 },
|
||||
{ 0xaa4c, 0xaa4c, 36 },
|
||||
{ 0xaa4d, 0xaa4d, 8 },
|
||||
{ 0xaa60, 0xaa6f, 16 },
|
||||
{ 0xaa71, 0xaa73, 16 },
|
||||
{ 0xaa7a, 0xaa7a, 16 },
|
||||
{ 0xaa7c, 0xaa7c, 36 },
|
||||
{ 0xaa7e, 0xaa7f, 16 },
|
||||
{ 0xaab0, 0xaab0, 36 },
|
||||
{ 0xaab2, 0xaab4, 36 },
|
||||
{ 0xaab7, 0xaab8, 36 },
|
||||
{ 0xaabe, 0xaabf, 36 },
|
||||
{ 0xaac1, 0xaac1, 36 },
|
||||
{ 0xaae0, 0xaaea, 16 },
|
||||
{ 0xaaeb, 0xaaeb, 8 },
|
||||
{ 0xaaec, 0xaaed, 36 },
|
||||
{ 0xaaee, 0xaaef, 8 },
|
||||
{ 0xaaf5, 0xaaf5, 8 },
|
||||
{ 0xaaf6, 0xaaf6, 52 },
|
||||
{ 0xabc0, 0xabda, 16 },
|
||||
{ 0xabe3, 0xabe4, 8 },
|
||||
{ 0xabe5, 0xabe5, 36 },
|
||||
{ 0xabe6, 0xabe7, 8 },
|
||||
{ 0xabe8, 0xabe8, 36 },
|
||||
{ 0xabe9, 0xabea, 8 },
|
||||
{ 0xabec, 0xabec, 8 },
|
||||
{ 0xabed, 0xabed, 36 },
|
||||
{ 0xd7b0, 0xd7c6, 10 },
|
||||
{ 0xd7cb, 0xd7fb, 11 },
|
||||
{ 0xfb1e, 0xfb1e, 36 },
|
||||
{ 0xfe00, 0xfe0f, 36 },
|
||||
{ 0xfe20, 0xfe2f, 36 },
|
||||
{ 0xfeff, 0xfeff, 3 },
|
||||
{ 0xff9e, 0xff9f, 36 },
|
||||
{ 0xfff0, 0xfffb, 3 },
|
||||
{ 0x101fd, 0x101fd, 36 },
|
||||
{ 0x102e0, 0x102e0, 36 },
|
||||
{ 0x10376, 0x1037a, 36 },
|
||||
{ 0x10a00, 0x10a00, 16 },
|
||||
{ 0x10a01, 0x10a03, 36 },
|
||||
{ 0x10a05, 0x10a06, 36 },
|
||||
{ 0x10a0c, 0x10a0f, 36 },
|
||||
{ 0x10a10, 0x10a13, 16 },
|
||||
{ 0x10a15, 0x10a17, 16 },
|
||||
{ 0x10a19, 0x10a35, 16 },
|
||||
{ 0x10a38, 0x10a3a, 36 },
|
||||
{ 0x10a3f, 0x10a3f, 52 },
|
||||
{ 0x10ae5, 0x10ae6, 36 },
|
||||
{ 0x10d24, 0x10d27, 36 },
|
||||
{ 0x10d69, 0x10d6d, 36 },
|
||||
{ 0x10eab, 0x10eac, 36 },
|
||||
{ 0x10efa, 0x10eff, 36 },
|
||||
{ 0x10f46, 0x10f50, 36 },
|
||||
{ 0x10f82, 0x10f85, 36 },
|
||||
{ 0x11000, 0x11000, 8 },
|
||||
{ 0x11001, 0x11001, 36 },
|
||||
{ 0x11002, 0x11002, 8 },
|
||||
{ 0x11038, 0x11046, 36 },
|
||||
{ 0x11070, 0x11070, 36 },
|
||||
{ 0x11073, 0x11074, 36 },
|
||||
{ 0x1107f, 0x11081, 36 },
|
||||
{ 0x11082, 0x11082, 8 },
|
||||
{ 0x110b0, 0x110b2, 8 },
|
||||
{ 0x110b3, 0x110b6, 36 },
|
||||
{ 0x110b7, 0x110b8, 8 },
|
||||
{ 0x110b9, 0x110ba, 36 },
|
||||
{ 0x110bd, 0x110bd, 7 },
|
||||
{ 0x110c2, 0x110c2, 36 },
|
||||
{ 0x110cd, 0x110cd, 7 },
|
||||
{ 0x11100, 0x11102, 36 },
|
||||
{ 0x11103, 0x11126, 16 },
|
||||
{ 0x11127, 0x1112b, 36 },
|
||||
{ 0x1112c, 0x1112c, 8 },
|
||||
{ 0x1112d, 0x11132, 36 },
|
||||
{ 0x11133, 0x11133, 52 },
|
||||
{ 0x11134, 0x11134, 36 },
|
||||
{ 0x11144, 0x11144, 16 },
|
||||
{ 0x11145, 0x11146, 8 },
|
||||
{ 0x11147, 0x11147, 16 },
|
||||
{ 0x11173, 0x11173, 36 },
|
||||
{ 0x11180, 0x11181, 36 },
|
||||
{ 0x11182, 0x11182, 8 },
|
||||
{ 0x111b3, 0x111b5, 8 },
|
||||
{ 0x111b6, 0x111be, 36 },
|
||||
{ 0x111bf, 0x111bf, 8 },
|
||||
{ 0x111c0, 0x111c0, 36 },
|
||||
{ 0x111c2, 0x111c3, 7 },
|
||||
{ 0x111c9, 0x111cc, 36 },
|
||||
{ 0x111ce, 0x111ce, 8 },
|
||||
{ 0x111cf, 0x111cf, 36 },
|
||||
{ 0x1122c, 0x1122e, 8 },
|
||||
{ 0x1122f, 0x11231, 36 },
|
||||
{ 0x11232, 0x11233, 8 },
|
||||
{ 0x11234, 0x11237, 36 },
|
||||
{ 0x1123e, 0x1123e, 36 },
|
||||
{ 0x11241, 0x11241, 36 },
|
||||
{ 0x112df, 0x112df, 36 },
|
||||
{ 0x112e0, 0x112e2, 8 },
|
||||
{ 0x112e3, 0x112ea, 36 },
|
||||
{ 0x11300, 0x11301, 36 },
|
||||
{ 0x11302, 0x11303, 8 },
|
||||
{ 0x1133b, 0x1133c, 36 },
|
||||
{ 0x1133e, 0x1133e, 36 },
|
||||
{ 0x1133f, 0x1133f, 8 },
|
||||
{ 0x11340, 0x11340, 36 },
|
||||
{ 0x11341, 0x11344, 8 },
|
||||
{ 0x11347, 0x11348, 8 },
|
||||
{ 0x1134b, 0x1134c, 8 },
|
||||
{ 0x1134d, 0x1134d, 36 },
|
||||
{ 0x11357, 0x11357, 36 },
|
||||
{ 0x11362, 0x11363, 8 },
|
||||
{ 0x11366, 0x1136c, 36 },
|
||||
{ 0x11370, 0x11374, 36 },
|
||||
{ 0x11380, 0x11389, 16 },
|
||||
{ 0x1138b, 0x1138b, 16 },
|
||||
{ 0x1138e, 0x1138e, 16 },
|
||||
{ 0x11390, 0x113b5, 16 },
|
||||
{ 0x113b8, 0x113b8, 36 },
|
||||
{ 0x113b9, 0x113ba, 8 },
|
||||
{ 0x113bb, 0x113c0, 36 },
|
||||
{ 0x113c2, 0x113c2, 36 },
|
||||
{ 0x113c5, 0x113c5, 36 },
|
||||
{ 0x113c7, 0x113c9, 36 },
|
||||
{ 0x113ca, 0x113ca, 8 },
|
||||
{ 0x113cc, 0x113cd, 8 },
|
||||
{ 0x113ce, 0x113cf, 36 },
|
||||
{ 0x113d0, 0x113d0, 52 },
|
||||
{ 0x113d1, 0x113d1, 7 },
|
||||
{ 0x113d2, 0x113d2, 36 },
|
||||
{ 0x113e1, 0x113e2, 36 },
|
||||
{ 0x11435, 0x11437, 8 },
|
||||
{ 0x11438, 0x1143f, 36 },
|
||||
{ 0x11440, 0x11441, 8 },
|
||||
{ 0x11442, 0x11444, 36 },
|
||||
{ 0x11445, 0x11445, 8 },
|
||||
{ 0x11446, 0x11446, 36 },
|
||||
{ 0x1145e, 0x1145e, 36 },
|
||||
{ 0x114b0, 0x114b0, 36 },
|
||||
{ 0x114b1, 0x114b2, 8 },
|
||||
{ 0x114b3, 0x114b8, 36 },
|
||||
{ 0x114b9, 0x114b9, 8 },
|
||||
{ 0x114ba, 0x114ba, 36 },
|
||||
{ 0x114bb, 0x114bc, 8 },
|
||||
{ 0x114bd, 0x114bd, 36 },
|
||||
{ 0x114be, 0x114be, 8 },
|
||||
{ 0x114bf, 0x114c0, 36 },
|
||||
{ 0x114c1, 0x114c1, 8 },
|
||||
{ 0x114c2, 0x114c3, 36 },
|
||||
{ 0x115af, 0x115af, 36 },
|
||||
{ 0x115b0, 0x115b1, 8 },
|
||||
{ 0x115b2, 0x115b5, 36 },
|
||||
{ 0x115b8, 0x115bb, 8 },
|
||||
{ 0x115bc, 0x115bd, 36 },
|
||||
{ 0x115be, 0x115be, 8 },
|
||||
{ 0x115bf, 0x115c0, 36 },
|
||||
{ 0x115dc, 0x115dd, 36 },
|
||||
{ 0x11630, 0x11632, 8 },
|
||||
{ 0x11633, 0x1163a, 36 },
|
||||
{ 0x1163b, 0x1163c, 8 },
|
||||
{ 0x1163d, 0x1163d, 36 },
|
||||
{ 0x1163e, 0x1163e, 8 },
|
||||
{ 0x1163f, 0x11640, 36 },
|
||||
{ 0x116ab, 0x116ab, 36 },
|
||||
{ 0x116ac, 0x116ac, 8 },
|
||||
{ 0x116ad, 0x116ad, 36 },
|
||||
{ 0x116ae, 0x116af, 8 },
|
||||
{ 0x116b0, 0x116b7, 36 },
|
||||
{ 0x1171d, 0x1171d, 36 },
|
||||
{ 0x1171e, 0x1171e, 8 },
|
||||
{ 0x1171f, 0x1171f, 36 },
|
||||
{ 0x11722, 0x11725, 36 },
|
||||
{ 0x11726, 0x11726, 8 },
|
||||
{ 0x11727, 0x1172b, 36 },
|
||||
{ 0x1182c, 0x1182e, 8 },
|
||||
{ 0x1182f, 0x11837, 36 },
|
||||
{ 0x11838, 0x11838, 8 },
|
||||
{ 0x11839, 0x1183a, 36 },
|
||||
{ 0x11900, 0x11906, 16 },
|
||||
{ 0x11909, 0x11909, 16 },
|
||||
{ 0x1190c, 0x11913, 16 },
|
||||
{ 0x11915, 0x11916, 16 },
|
||||
{ 0x11918, 0x1192f, 16 },
|
||||
{ 0x11930, 0x11930, 36 },
|
||||
{ 0x11931, 0x11935, 8 },
|
||||
{ 0x11937, 0x11938, 8 },
|
||||
{ 0x1193b, 0x1193d, 36 },
|
||||
{ 0x1193e, 0x1193e, 52 },
|
||||
{ 0x1193f, 0x1193f, 7 },
|
||||
{ 0x11940, 0x11940, 8 },
|
||||
{ 0x11941, 0x11941, 7 },
|
||||
{ 0x11942, 0x11942, 8 },
|
||||
{ 0x11943, 0x11943, 36 },
|
||||
{ 0x119d1, 0x119d3, 8 },
|
||||
{ 0x119d4, 0x119d7, 36 },
|
||||
{ 0x119da, 0x119db, 36 },
|
||||
{ 0x119dc, 0x119df, 8 },
|
||||
{ 0x119e0, 0x119e0, 36 },
|
||||
{ 0x119e4, 0x119e4, 8 },
|
||||
{ 0x11a00, 0x11a00, 16 },
|
||||
{ 0x11a01, 0x11a0a, 36 },
|
||||
{ 0x11a0b, 0x11a32, 16 },
|
||||
{ 0x11a33, 0x11a38, 36 },
|
||||
{ 0x11a39, 0x11a39, 8 },
|
||||
{ 0x11a3b, 0x11a3e, 36 },
|
||||
{ 0x11a47, 0x11a47, 52 },
|
||||
{ 0x11a50, 0x11a50, 16 },
|
||||
{ 0x11a51, 0x11a56, 36 },
|
||||
{ 0x11a57, 0x11a58, 8 },
|
||||
{ 0x11a59, 0x11a5b, 36 },
|
||||
{ 0x11a5c, 0x11a83, 16 },
|
||||
{ 0x11a84, 0x11a89, 7 },
|
||||
{ 0x11a8a, 0x11a96, 36 },
|
||||
{ 0x11a97, 0x11a97, 8 },
|
||||
{ 0x11a98, 0x11a98, 36 },
|
||||
{ 0x11a99, 0x11a99, 52 },
|
||||
{ 0x11b60, 0x11b60, 36 },
|
||||
{ 0x11b61, 0x11b61, 8 },
|
||||
{ 0x11b62, 0x11b64, 36 },
|
||||
{ 0x11b65, 0x11b65, 8 },
|
||||
{ 0x11b66, 0x11b66, 36 },
|
||||
{ 0x11b67, 0x11b67, 8 },
|
||||
{ 0x11c2f, 0x11c2f, 8 },
|
||||
{ 0x11c30, 0x11c36, 36 },
|
||||
{ 0x11c38, 0x11c3d, 36 },
|
||||
{ 0x11c3e, 0x11c3e, 8 },
|
||||
{ 0x11c3f, 0x11c3f, 36 },
|
||||
{ 0x11c92, 0x11ca7, 36 },
|
||||
{ 0x11ca9, 0x11ca9, 8 },
|
||||
{ 0x11caa, 0x11cb0, 36 },
|
||||
{ 0x11cb1, 0x11cb1, 8 },
|
||||
{ 0x11cb2, 0x11cb3, 36 },
|
||||
{ 0x11cb4, 0x11cb4, 8 },
|
||||
{ 0x11cb5, 0x11cb6, 36 },
|
||||
{ 0x11d31, 0x11d36, 36 },
|
||||
{ 0x11d3a, 0x11d3a, 36 },
|
||||
{ 0x11d3c, 0x11d3d, 36 },
|
||||
{ 0x11d3f, 0x11d45, 36 },
|
||||
{ 0x11d46, 0x11d46, 7 },
|
||||
{ 0x11d47, 0x11d47, 36 },
|
||||
{ 0x11d8a, 0x11d8e, 8 },
|
||||
{ 0x11d90, 0x11d91, 36 },
|
||||
{ 0x11d93, 0x11d94, 8 },
|
||||
{ 0x11d95, 0x11d95, 36 },
|
||||
{ 0x11d96, 0x11d96, 8 },
|
||||
{ 0x11d97, 0x11d97, 36 },
|
||||
{ 0x11ef3, 0x11ef4, 36 },
|
||||
{ 0x11ef5, 0x11ef6, 8 },
|
||||
{ 0x11f00, 0x11f01, 36 },
|
||||
{ 0x11f02, 0x11f02, 7 },
|
||||
{ 0x11f03, 0x11f03, 8 },
|
||||
{ 0x11f04, 0x11f10, 16 },
|
||||
{ 0x11f12, 0x11f33, 16 },
|
||||
{ 0x11f34, 0x11f35, 8 },
|
||||
{ 0x11f36, 0x11f3a, 36 },
|
||||
{ 0x11f3e, 0x11f3f, 8 },
|
||||
{ 0x11f40, 0x11f41, 36 },
|
||||
{ 0x11f42, 0x11f42, 52 },
|
||||
{ 0x11f5a, 0x11f5a, 36 },
|
||||
{ 0x13430, 0x1343f, 3 },
|
||||
{ 0x13440, 0x13440, 36 },
|
||||
{ 0x13447, 0x13455, 36 },
|
||||
{ 0x1611e, 0x16129, 36 },
|
||||
{ 0x1612a, 0x1612c, 8 },
|
||||
{ 0x1612d, 0x1612f, 36 },
|
||||
{ 0x16af0, 0x16af4, 36 },
|
||||
{ 0x16b30, 0x16b36, 36 },
|
||||
{ 0x16d63, 0x16d63, 10 },
|
||||
{ 0x16d67, 0x16d6a, 10 },
|
||||
{ 0x16f4f, 0x16f4f, 36 },
|
||||
{ 0x16f51, 0x16f87, 8 },
|
||||
{ 0x16f8f, 0x16f92, 36 },
|
||||
{ 0x16fe4, 0x16fe4, 36 },
|
||||
{ 0x16ff0, 0x16ff1, 36 },
|
||||
{ 0x1bc9d, 0x1bc9e, 36 },
|
||||
{ 0x1bca0, 0x1bca3, 3 },
|
||||
{ 0x1cf00, 0x1cf2d, 36 },
|
||||
{ 0x1cf30, 0x1cf46, 36 },
|
||||
{ 0x1d165, 0x1d169, 36 },
|
||||
{ 0x1d16d, 0x1d172, 36 },
|
||||
{ 0x1d173, 0x1d17a, 3 },
|
||||
{ 0x1d17b, 0x1d182, 36 },
|
||||
{ 0x1d185, 0x1d18b, 36 },
|
||||
{ 0x1d1aa, 0x1d1ad, 36 },
|
||||
{ 0x1d242, 0x1d244, 36 },
|
||||
{ 0x1da00, 0x1da36, 36 },
|
||||
{ 0x1da3b, 0x1da6c, 36 },
|
||||
{ 0x1da75, 0x1da75, 36 },
|
||||
{ 0x1da84, 0x1da84, 36 },
|
||||
{ 0x1da9b, 0x1da9f, 36 },
|
||||
{ 0x1daa1, 0x1daaf, 36 },
|
||||
{ 0x1e000, 0x1e006, 36 },
|
||||
{ 0x1e008, 0x1e018, 36 },
|
||||
{ 0x1e01b, 0x1e021, 36 },
|
||||
{ 0x1e023, 0x1e024, 36 },
|
||||
{ 0x1e026, 0x1e02a, 36 },
|
||||
{ 0x1e08f, 0x1e08f, 36 },
|
||||
{ 0x1e130, 0x1e136, 36 },
|
||||
{ 0x1e2ae, 0x1e2ae, 36 },
|
||||
{ 0x1e2ec, 0x1e2ef, 36 },
|
||||
{ 0x1e4ec, 0x1e4ef, 36 },
|
||||
{ 0x1e5ee, 0x1e5ef, 36 },
|
||||
{ 0x1e6e3, 0x1e6e3, 36 },
|
||||
{ 0x1e6e6, 0x1e6e6, 36 },
|
||||
{ 0x1e6ee, 0x1e6ef, 36 },
|
||||
{ 0x1e6f5, 0x1e6f5, 36 },
|
||||
{ 0x1e8d0, 0x1e8d6, 36 },
|
||||
{ 0x1e944, 0x1e94a, 36 },
|
||||
{ 0x1f004, 0x1f004, 64 },
|
||||
{ 0x1f02c, 0x1f02f, 64 },
|
||||
{ 0x1f094, 0x1f09f, 64 },
|
||||
{ 0x1f0af, 0x1f0b0, 64 },
|
||||
{ 0x1f0c0, 0x1f0c0, 64 },
|
||||
{ 0x1f0cf, 0x1f0d0, 64 },
|
||||
{ 0x1f0f6, 0x1f0ff, 64 },
|
||||
{ 0x1f170, 0x1f171, 64 },
|
||||
{ 0x1f17e, 0x1f17f, 64 },
|
||||
{ 0x1f18e, 0x1f18e, 64 },
|
||||
{ 0x1f191, 0x1f19a, 64 },
|
||||
{ 0x1f1ae, 0x1f1e5, 64 },
|
||||
{ 0x1f1e6, 0x1f1ff, 6 },
|
||||
{ 0x1f201, 0x1f20f, 64 },
|
||||
{ 0x1f21a, 0x1f21a, 64 },
|
||||
{ 0x1f22f, 0x1f22f, 64 },
|
||||
{ 0x1f232, 0x1f23a, 64 },
|
||||
{ 0x1f23c, 0x1f23f, 64 },
|
||||
{ 0x1f249, 0x1f25f, 64 },
|
||||
{ 0x1f266, 0x1f321, 64 },
|
||||
{ 0x1f324, 0x1f393, 64 },
|
||||
{ 0x1f396, 0x1f397, 64 },
|
||||
{ 0x1f399, 0x1f39b, 64 },
|
||||
{ 0x1f39e, 0x1f3f0, 64 },
|
||||
{ 0x1f3f3, 0x1f3f5, 64 },
|
||||
{ 0x1f3f7, 0x1f3fa, 64 },
|
||||
{ 0x1f3fb, 0x1f3ff, 36 },
|
||||
{ 0x1f400, 0x1f4fd, 64 },
|
||||
{ 0x1f4ff, 0x1f53d, 64 },
|
||||
{ 0x1f549, 0x1f54e, 64 },
|
||||
{ 0x1f550, 0x1f567, 64 },
|
||||
{ 0x1f56f, 0x1f570, 64 },
|
||||
{ 0x1f573, 0x1f57a, 64 },
|
||||
{ 0x1f587, 0x1f587, 64 },
|
||||
{ 0x1f58a, 0x1f58d, 64 },
|
||||
{ 0x1f590, 0x1f590, 64 },
|
||||
{ 0x1f595, 0x1f596, 64 },
|
||||
{ 0x1f5a4, 0x1f5a5, 64 },
|
||||
{ 0x1f5a8, 0x1f5a8, 64 },
|
||||
{ 0x1f5b1, 0x1f5b2, 64 },
|
||||
{ 0x1f5bc, 0x1f5bc, 64 },
|
||||
{ 0x1f5c2, 0x1f5c4, 64 },
|
||||
{ 0x1f5d1, 0x1f5d3, 64 },
|
||||
{ 0x1f5dc, 0x1f5de, 64 },
|
||||
{ 0x1f5e1, 0x1f5e1, 64 },
|
||||
{ 0x1f5e3, 0x1f5e3, 64 },
|
||||
{ 0x1f5e8, 0x1f5e8, 64 },
|
||||
{ 0x1f5ef, 0x1f5ef, 64 },
|
||||
{ 0x1f5f3, 0x1f5f3, 64 },
|
||||
{ 0x1f5fa, 0x1f64f, 64 },
|
||||
{ 0x1f680, 0x1f6c5, 64 },
|
||||
{ 0x1f6cb, 0x1f6d2, 64 },
|
||||
{ 0x1f6d5, 0x1f6e5, 64 },
|
||||
{ 0x1f6e9, 0x1f6e9, 64 },
|
||||
{ 0x1f6eb, 0x1f6f0, 64 },
|
||||
{ 0x1f6f3, 0x1f6ff, 64 },
|
||||
{ 0x1f7da, 0x1f7ff, 64 },
|
||||
{ 0x1f80c, 0x1f80f, 64 },
|
||||
{ 0x1f848, 0x1f84f, 64 },
|
||||
{ 0x1f85a, 0x1f85f, 64 },
|
||||
{ 0x1f888, 0x1f88f, 64 },
|
||||
{ 0x1f8ae, 0x1f8af, 64 },
|
||||
{ 0x1f8bc, 0x1f8bf, 64 },
|
||||
{ 0x1f8c2, 0x1f8cf, 64 },
|
||||
{ 0x1f8d9, 0x1f8ff, 64 },
|
||||
{ 0x1f90c, 0x1f93a, 64 },
|
||||
{ 0x1f93c, 0x1f945, 64 },
|
||||
{ 0x1f947, 0x1f9ff, 64 },
|
||||
{ 0x1fa58, 0x1fa5f, 64 },
|
||||
{ 0x1fa6e, 0x1faff, 64 },
|
||||
{ 0x1fc00, 0x1fffd, 64 },
|
||||
{ 0xe0000, 0xe001f, 3 },
|
||||
{ 0xe0020, 0xe007f, 36 },
|
||||
{ 0xe0080, 0xe00ff, 3 },
|
||||
{ 0xe0100, 0xe01ef, 36 },
|
||||
{ 0xe01f0, 0xe0fff, 3 },
|
||||
};
|
||||
#endif
|
||||
+254
-14
@@ -515,6 +515,13 @@ void scr_dyn_arr_push(ScrDyn *arr, ScrDyn *item) {
|
||||
* the generic "Spread syntax requires ...iterable[Symbol.iterator] to be
|
||||
* a function". Borrows src. */
|
||||
void scr_dyn_arr_push_spread(ScrDyn *arr, const ScrDyn *src, const char *what) {
|
||||
if (src->kind == SCR_DYN_HANDLE && scr_dyn_handle_ops_of(src)->iter_pack) {
|
||||
ScrDyn *pack = scr_dyn_handle_ops_of(src)->iter_pack(src->v.handle.ptr);
|
||||
if (!pack) return;
|
||||
scr_dyn_arr_push_spread(arr, pack, what);
|
||||
scr_dyn_release(pack);
|
||||
return;
|
||||
}
|
||||
if (src->kind == SCR_DYN_TYPED_REF) {
|
||||
ScrDyn *materialized = scr_dyn_typed_ref_materialize(src);
|
||||
scr_dyn_arr_push_spread(arr, materialized, what);
|
||||
@@ -583,6 +590,8 @@ void scr_dyn_arr_push_spread(ScrDyn *arr, const ScrDyn *src, const char *what) {
|
||||
* undefined no kind prefix, null V8's "object null"). Borrows both; +1 or
|
||||
* NULL with the TypeError pending. */
|
||||
ScrDyn *scr_dyn_iter_pack(const ScrDyn *src, const ScrStr *msg) {
|
||||
if (src->kind == SCR_DYN_HANDLE && scr_dyn_handle_ops_of(src)->iter_pack)
|
||||
return scr_dyn_handle_ops_of(src)->iter_pack(src->v.handle.ptr);
|
||||
if (src->kind == SCR_DYN_TYPED_REF) {
|
||||
ScrDyn *materialized = scr_dyn_typed_ref_materialize(src);
|
||||
ScrDyn *out = scr_dyn_iter_pack(materialized, msg);
|
||||
@@ -978,15 +987,21 @@ void scr_dyn_proxy_delete(ScrDyn *proxy, const ScrStr *key) {
|
||||
scr_dyn_release(result);
|
||||
}
|
||||
|
||||
ScrDyn *scr_dyn_new_bytes_copy(const ScrBytes *b) {
|
||||
ScrDyn *scr_dyn_new_bytes(const ScrBytes *b) {
|
||||
ScrDyn *d = scr_dyn_alloc(SCR_DYN_BYTES);
|
||||
d->v.bytes = scr_bytes_copy(b); /* the static→dyn boundary copies */
|
||||
d->v.bytes = scr_bytes_retain((ScrBytes *)b);
|
||||
d->buffer = b->is_buffer;
|
||||
return d;
|
||||
}
|
||||
|
||||
ScrDyn *scr_dyn_new_buffer_copy(const ScrBytes *b) {
|
||||
ScrDyn *d = scr_dyn_new_bytes_copy(b);
|
||||
d->buffer = true;
|
||||
ScrDyn *scr_dyn_new_buffer(const ScrBytes *b) {
|
||||
if (b->is_buffer) return scr_dyn_new_bytes(b);
|
||||
// Converting a Uint8Array chunk to Buffer creates a distinct view while
|
||||
// retaining the same allocation; the source keeps its Uint8Array brand.
|
||||
ScrBytes *view = scr_bytes_subarray((ScrBytes *)b, 0, (double)b->len);
|
||||
view->is_buffer = true;
|
||||
ScrDyn *d = scr_dyn_new_bytes(view);
|
||||
scr_bytes_release(view);
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -1133,8 +1148,27 @@ void scr_dyn_typed_ref_cache_cast(
|
||||
d->v.typed_ref.casts = cast;
|
||||
}
|
||||
|
||||
ScrBytes *scr_dyn_bytes_copy_out(const ScrDyn *d) {
|
||||
return scr_bytes_copy(d->v.bytes); /* extraction copies too (+1) */
|
||||
ScrBytes *scr_dyn_bytes_unbox(const ScrDyn *d) {
|
||||
return scr_bytes_retain(d->v.bytes);
|
||||
}
|
||||
|
||||
/* Shared view metadata and indexed reads for both compiler backends. */
|
||||
ScrDyn *scr_dyn_bytes_key_get(const ScrDyn *value, const ScrStr *key) {
|
||||
ScrBytes *bytes = value->v.bytes;
|
||||
if (key->len == 6 && memcmp(key->data, "length", 6) == 0) return scr_dyn_new_num(scr_bytes_len(bytes));
|
||||
if (key->len == 10 && memcmp(key->data, "byteLength", 10) == 0) return scr_dyn_new_num(scr_bytes_byte_len(bytes));
|
||||
if (key->len == 10 && memcmp(key->data, "byteOffset", 10) == 0) return scr_dyn_new_num(scr_bytes_byte_offset(bytes));
|
||||
if (key->len == 6 && memcmp(key->data, "buffer", 6) == 0) return scr_array_buffer_from_bytes(bytes);
|
||||
if (key->len && !(key->len > 1 && key->data[0] == '0')) {
|
||||
size_t index = 0;
|
||||
bool digits = true;
|
||||
for (size_t i = 0; i < key->len; i++) {
|
||||
if (key->data[i] < '0' || key->data[i] > '9' || index > (SIZE_MAX - 9) / 10) { digits = false; break; }
|
||||
index = index * 10 + (size_t)(key->data[i] - '0');
|
||||
}
|
||||
if (digits && index < bytes->len) return scr_dyn_new_num(scr_bytes_get(bytes, (double)index));
|
||||
}
|
||||
return scr_dyn_retain(scr_dyn_undefined());
|
||||
}
|
||||
|
||||
/* ── the data-chunk encoding window (setEncoding) ─────────────────────
|
||||
@@ -1158,7 +1192,7 @@ ScrDyn *scr_dyn_new_chunk(const ScrBytes *b) {
|
||||
scr_str_release(s);
|
||||
return d;
|
||||
}
|
||||
return scr_dyn_new_buffer_copy(b);
|
||||
return scr_dyn_new_buffer(b);
|
||||
}
|
||||
|
||||
/* A boxed static function value (the compiler's static→dyn converters).
|
||||
@@ -1951,8 +1985,8 @@ ScrStr *scr_dyn_object_tag(const ScrDyn *d) {
|
||||
case SCR_DYN_ARR: tag = "[object Array]"; break;
|
||||
case SCR_DYN_OBJ: tag = "[object Object]"; break;
|
||||
case SCR_DYN_HANDLE:
|
||||
if (d->v.handle.tag >= SCR_DYNH_ABORT_SIGNAL &&
|
||||
d->v.handle.tag <= SCR_DYNH_ABORT_CONTROLLER) {
|
||||
if ((d->v.handle.tag >= SCR_DYNH_ABORT_SIGNAL &&
|
||||
d->v.handle.tag <= SCR_DYNH_ABORT_CONTROLLER) || d->v.handle.tag == SCR_DYNH_ARRAY_BUFFER) {
|
||||
ScrJsonBuf b;
|
||||
scr_jb_init(&b);
|
||||
scr_jb_puts(&b, "[object ");
|
||||
@@ -2310,8 +2344,8 @@ ScrStr *scr_dyn_to_string(const ScrDyn *d, const ScrStr *enc) {
|
||||
case SCR_DYN_OBJ:
|
||||
return scr_str_new("[object Object]", 15);
|
||||
case SCR_DYN_HANDLE:
|
||||
if (d->v.handle.tag >= SCR_DYNH_ABORT_SIGNAL &&
|
||||
d->v.handle.tag <= SCR_DYNH_ABORT_CONTROLLER) {
|
||||
if ((d->v.handle.tag >= SCR_DYNH_ABORT_SIGNAL &&
|
||||
d->v.handle.tag <= SCR_DYNH_ABORT_CONTROLLER) || d->v.handle.tag == SCR_DYNH_ARRAY_BUFFER) {
|
||||
ScrJsonBuf b;
|
||||
scr_jb_init(&b);
|
||||
scr_jb_puts(&b, "[object ");
|
||||
@@ -2734,6 +2768,22 @@ void scr_dyn_key_set(ScrDyn *recv, ScrStr *key, ScrDyn *value) {
|
||||
scr_dyn_handle_key_set(recv, key, value);
|
||||
return;
|
||||
}
|
||||
if (recv->kind == SCR_DYN_BYTES) {
|
||||
/* Integer-indexed exotic writes coerce even for an invalid canonical
|
||||
* numeric index, then silently ignore an out-of-range index. */
|
||||
double index = scr_string_to_number(key);
|
||||
char spelling[32];
|
||||
size_t length = scr_f64_to_str(index, spelling);
|
||||
bool negative_zero = key->len == 2 && memcmp(key->data, "-0", 2) == 0;
|
||||
if (negative_zero || (length == key->len && memcmp(spelling, key->data, length) == 0)) {
|
||||
double number;
|
||||
if (!scr_dyn_number_coerce_js(value, &number)) return;
|
||||
if (!negative_zero && index >= 0 && index < (double)recv->v.bytes->len && trunc(index) == index) {
|
||||
scr_bytes_set(recv->v.bytes, index, number);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (recv->kind == SCR_DYN_JSVAL) {
|
||||
/* The write lands on the REAL engine object (aliasing preserved —
|
||||
* island-side readers see it); the value crosses through the uniform
|
||||
@@ -2774,6 +2824,22 @@ void scr_dyn_key_set(ScrDyn *recv, ScrStr *key, ScrDyn *value) {
|
||||
scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&b));
|
||||
}
|
||||
|
||||
void scr_dyn_key_set_computed(ScrDyn *recv, ScrDyn *key, ScrDyn *value) {
|
||||
/* A nullish receiver fails before object-key coercion. V8 includes a
|
||||
* primitive key in the error, but never calls user code to describe it. */
|
||||
if ((recv->kind == SCR_DYN_UNDEF || recv->kind == SCR_DYN_NULL) &&
|
||||
scr_dyn_to_primitive_result_is_object(key)) {
|
||||
const char *message = recv->kind == SCR_DYN_NULL
|
||||
? "Cannot set properties of null" : "Cannot set properties of undefined";
|
||||
scr_throw_error_msg(SCR_ERR_TYPE, message, strlen(message));
|
||||
return;
|
||||
}
|
||||
ScrStr *name = scr_dyn_string_coerce_js(key);
|
||||
if (!name) return;
|
||||
scr_dyn_key_set(recv, name, value);
|
||||
scr_str_release(name);
|
||||
}
|
||||
|
||||
/* Node's JSON.stringify over a dyn: object members holding undefined DROP,
|
||||
* array slots holding undefined print null. A bare undefined never arrives
|
||||
* (the record serializer drops the entry first); print null defensively. */
|
||||
@@ -3769,6 +3835,8 @@ bool scr_dyn_strict_eq(const ScrDyn *a, const ScrDyn *b) {
|
||||
* dyn boundary twice is still ONE JS function value, so identity
|
||||
* lives in the boxed closure, not the box. */
|
||||
return a == b || a->v.fn.clo == b->v.fn.clo;
|
||||
case SCR_DYN_BYTES:
|
||||
return a->v.bytes == b->v.bytes;
|
||||
case SCR_DYN_HANDLE:
|
||||
/* Same story: identity is the HANDLE — one req boxed into two
|
||||
* listeners is still one JS object. */
|
||||
@@ -3871,10 +3939,14 @@ static ScrDyn *scr_sc_clone(const ScrDyn *v, const ScrScParent *up) {
|
||||
return scr_dyn_new_num(v->v.num);
|
||||
case SCR_DYN_STR:
|
||||
return scr_dyn_new_str(v->v.str);
|
||||
case SCR_DYN_BYTES:
|
||||
case SCR_DYN_BYTES: {
|
||||
/* A fresh byte copy; the Buffer flavor drops (Node: structuredClone
|
||||
* of a Buffer answers a plain Uint8Array). */
|
||||
return scr_dyn_new_bytes_copy(v->v.bytes);
|
||||
ScrBytes *copy = scr_bytes_copy(v->v.bytes);
|
||||
ScrDyn *result = scr_dyn_new_bytes(copy);
|
||||
scr_bytes_release(copy);
|
||||
return result;
|
||||
}
|
||||
case SCR_DYN_ARR:
|
||||
case SCR_DYN_OBJ: {
|
||||
for (const ScrScParent *p = up; p != NULL; p = p->up) {
|
||||
@@ -4826,3 +4898,171 @@ ScrStr *scr_b64_missing_arg(void) {
|
||||
"ERR_MISSING_ARGS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SCR_TL ScrDyn *scr_versions_object;
|
||||
|
||||
static void scr_versions_object_cleanup(void) {
|
||||
scr_dyn_release(scr_versions_object);
|
||||
scr_versions_object = NULL;
|
||||
}
|
||||
|
||||
ScrDyn *scr_process_versions(void) {
|
||||
if (!scr_versions_object) {
|
||||
scr_versions_object = scr_dyn_new_obj();
|
||||
ScrStr *node = scr_process_versions_node();
|
||||
ScrStr *openssl = scr_process_versions_openssl();
|
||||
scr_dyn_obj_set(scr_versions_object, "node", 4, scr_dyn_new_str(node));
|
||||
scr_dyn_obj_set(scr_versions_object, "openssl", 7, scr_dyn_new_str(openssl));
|
||||
scr_str_release(node);
|
||||
scr_str_release(openssl);
|
||||
for (size_t i = 0; i < scr_versions_object->v.obj.len; i++) {
|
||||
scr_versions_object->v.obj.entries[i].writable = false;
|
||||
}
|
||||
scr_atexit(&scr_versions_object_cleanup);
|
||||
}
|
||||
return scr_dyn_retain(scr_versions_object);
|
||||
}
|
||||
|
||||
/* Fixed-length ArrayBuffers use the same retained root allocation as native
|
||||
* typed-array views. The handle brand distinguishes storage from a view;
|
||||
* repeated .buffer reads box the same root pointer and preserve identity. */
|
||||
bool scr_array_buffer_is(const ScrDyn *value) {
|
||||
return value->kind == SCR_DYN_HANDLE && value->v.handle.tag == SCR_DYNH_ARRAY_BUFFER;
|
||||
}
|
||||
|
||||
bool scr_array_buffer_is_view(const ScrDyn *value) {
|
||||
return value->kind == SCR_DYN_BYTES;
|
||||
}
|
||||
|
||||
static ScrDyn *scr_array_buffer_get(void *h, const char *key, size_t len) {
|
||||
if ((len == 10 && memcmp(key, "byteLength", len) == 0) ||
|
||||
(len == 13 && memcmp(key, "maxByteLength", len) == 0))
|
||||
return scr_dyn_new_num(scr_bytes_byte_len(h));
|
||||
if ((len == 9 && memcmp(key, "resizable", len) == 0) ||
|
||||
(len == 8 && memcmp(key, "detached", len) == 0)) return scr_dyn_new_bool(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool scr_array_buffer_set(void *h, const char *key, size_t len, const ScrDyn *value) {
|
||||
(void)h; (void)key; (void)len; (void)value;
|
||||
return false;
|
||||
}
|
||||
|
||||
static ScrDyn *scr_array_buffer_invoke(void *h, ScrDyn *self, const char *method,
|
||||
ScrDyn *const *args, size_t argc, const char *what) {
|
||||
(void)self; (void)what;
|
||||
if (strcmp(method, "slice") == 0) {
|
||||
double start = 0, end = scr_bytes_byte_len(h);
|
||||
if (argc && !scr_dyn_number_coerce_js(args[0], &start)) return NULL;
|
||||
if (argc > 1 && args[1]->kind != SCR_DYN_UNDEF && !scr_dyn_number_coerce_js(args[1], &end)) return NULL;
|
||||
ScrBytes *view = scr_bytes_buffer_view(h, SCR_BYTES_U8, 0, false, 0);
|
||||
if (!view) return NULL;
|
||||
ScrBytes *copy = scr_bytes_slice(view, start, end);
|
||||
scr_bytes_release(view);
|
||||
ScrDyn *result = scr_array_buffer_from_bytes(copy);
|
||||
scr_bytes_release(copy);
|
||||
return result;
|
||||
}
|
||||
static const char msg[] = "ArrayBuffer method is not supported yet";
|
||||
scr_throw_error_msg(SCR_ERR_ERROR, msg, sizeof msg - 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScrDyn *scr_array_buffer_from_bytes(ScrBytes *view) {
|
||||
static const ScrDynHandleOps ops = {
|
||||
"ArrayBuffer", &scr_bytes_retain_v, &scr_bytes_release_v,
|
||||
&scr_array_buffer_invoke, &scr_array_buffer_get, &scr_array_buffer_set, NULL,
|
||||
};
|
||||
scr_dyn_handle_install(SCR_DYNH_ARRAY_BUFFER, &ops);
|
||||
return scr_dyn_new_handle(view->backing ? view->backing : view, SCR_DYNH_ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
ScrDyn *scr_array_buffer_new(ScrDyn *length) {
|
||||
double number;
|
||||
if (!scr_dyn_number_coerce_js(length, &number)) return NULL;
|
||||
double size = isnan(number) ? 0 : trunc(number);
|
||||
if (!(size >= 0) || size > 9007199254740991.0 || size > (double)(SIZE_MAX / 8)) {
|
||||
static const char msg[] = "Invalid array buffer length";
|
||||
scr_throw_error_msg(SCR_ERR_RANGE, msg, sizeof msg - 1);
|
||||
return NULL;
|
||||
}
|
||||
ScrBytes *storage = scr_bytes_new(SCR_BYTES_U8, size);
|
||||
if (!storage) return NULL;
|
||||
ScrDyn *result = scr_array_buffer_from_bytes(storage);
|
||||
scr_bytes_release(storage);
|
||||
return result;
|
||||
}
|
||||
|
||||
double scr_array_buffer_byte_length_getter(void) {
|
||||
ScrDyn *receiver = scr_dyn_this_get();
|
||||
if (!scr_array_buffer_is(receiver)) {
|
||||
scr_dyn_release(receiver);
|
||||
static const char msg[] = "Method get ArrayBuffer.prototype.byteLength called on incompatible receiver";
|
||||
scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1);
|
||||
return 0;
|
||||
}
|
||||
double length = scr_bytes_byte_len(receiver->v.handle.ptr);
|
||||
scr_dyn_release(receiver);
|
||||
return length;
|
||||
}
|
||||
|
||||
ScrDyn *scr_array_buffer_byte_length_descriptor(ScrDyn *getter) {
|
||||
ScrDyn *descriptor = scr_dyn_new_obj();
|
||||
ScrDyn *named = scr_dyn_new_func(scr_closure_retain(getter->v.fn.clo),
|
||||
getter->v.fn.thunk, 0, getter->v.fn.sig, "get byteLength");
|
||||
scr_dyn_obj_set(descriptor, "get", 3, named);
|
||||
scr_dyn_obj_set(descriptor, "set", 3, scr_dyn_retain(scr_dyn_undefined()));
|
||||
scr_dyn_obj_set(descriptor, "enumerable", 10, scr_dyn_new_bool(false));
|
||||
scr_dyn_obj_set(descriptor, "configurable", 12, scr_dyn_new_bool(true));
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
ScrBytes *scr_array_buffer_view(ScrBytesElem elem, const ScrDyn *buffer,
|
||||
const ScrDyn *offset, const ScrDyn *length) {
|
||||
if (!scr_array_buffer_is(buffer)) {
|
||||
// Non-buffer inputs use the length/iterable/array-like constructor.
|
||||
// Their extra arguments are evaluated by the caller, but not coerced.
|
||||
return scr_bytes_from_dyn(elem, buffer, false);
|
||||
}
|
||||
double off, count = 0;
|
||||
if (!scr_dyn_number_coerce_js(offset, &off)) return NULL;
|
||||
off = isnan(off) ? 0 : trunc(off);
|
||||
if (off < 0 || off > 9007199254740991.0 ||
|
||||
fmod(off, (double)scr_bytes_elem_size(elem)) != 0) {
|
||||
static const char msg[] = "Invalid typed array buffer range";
|
||||
scr_throw_error_msg(SCR_ERR_RANGE, msg, sizeof msg - 1);
|
||||
return NULL;
|
||||
}
|
||||
bool has_len = length->kind != SCR_DYN_UNDEF;
|
||||
if (has_len && !scr_dyn_number_coerce_js(length, &count)) return NULL;
|
||||
return scr_bytes_buffer_view(buffer->v.handle.ptr, elem, off, has_len, count);
|
||||
}
|
||||
|
||||
#define SCR_ARRAY_BUFFER_VIEW(name, elem) \
|
||||
ScrBytes *scr_array_buffer_view_##name(ScrDyn *buffer, ScrDyn *offset, ScrDyn *length) { \
|
||||
return scr_array_buffer_view(elem, buffer, offset, length); \
|
||||
}
|
||||
SCR_ARRAY_BUFFER_VIEW(u8, SCR_BYTES_U8)
|
||||
SCR_ARRAY_BUFFER_VIEW(u32, SCR_BYTES_U32)
|
||||
SCR_ARRAY_BUFFER_VIEW(i32, SCR_BYTES_I32)
|
||||
SCR_ARRAY_BUFFER_VIEW(f32, SCR_BYTES_F32)
|
||||
SCR_ARRAY_BUFFER_VIEW(f64, SCR_BYTES_F64)
|
||||
#undef SCR_ARRAY_BUFFER_VIEW
|
||||
|
||||
ScrBytes *scr_array_buffer_view_dv(ScrDyn *buffer, ScrDyn *offset, ScrDyn *length) {
|
||||
if (!scr_array_buffer_is(buffer)) {
|
||||
static const char msg[] = "First argument to DataView constructor must be an ArrayBuffer";
|
||||
scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1);
|
||||
return NULL;
|
||||
}
|
||||
double off, count = 0;
|
||||
if (!scr_dyn_number_coerce_js(offset, &off)) return NULL;
|
||||
off = isnan(off) ? 0 : trunc(off);
|
||||
if (off < 0 || off > 9007199254740991.0 || off > scr_bytes_byte_len(buffer->v.handle.ptr)) {
|
||||
// DataView rejects an out-of-bounds offset before coercing length.
|
||||
return scr_dataview_new(buffer->v.handle.ptr, off, false, 0);
|
||||
}
|
||||
bool has_len = length->kind != SCR_DYN_UNDEF;
|
||||
if (has_len && !scr_dyn_number_coerce_js(length, &count)) return NULL;
|
||||
return scr_dataview_new(buffer->v.handle.ptr, off, has_len, count);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
/* Native builtin export objects. The compiler supplies the existing static
|
||||
* callable implementations; this unit owns lookup, identity, and mutations. */
|
||||
#include "scr_runtime.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
static SCR_TL ScrDyn *scr_global_known;
|
||||
static SCR_TL bool scr_global_cleanup_registered;
|
||||
|
||||
static void scr_global_cleanup(void) {
|
||||
scr_dyn_release(scr_global_known);
|
||||
scr_global_known = NULL;
|
||||
}
|
||||
|
||||
static void *scr_global_retain(void *handle) { return handle; }
|
||||
static void scr_global_release(void *handle) { (void)handle; }
|
||||
|
||||
static ScrDyn *scr_global_get(void *handle, const char *key, size_t length) {
|
||||
(void)handle;
|
||||
if ((length == 10 && memcmp(key, "globalThis", length) == 0) ||
|
||||
(length == 6 && memcmp(key, "global", length) == 0))
|
||||
return scr_dyn_new_handle(&scr_global_known, SCR_DYNH_GLOBAL);
|
||||
if (length == 9 && memcmp(key, "undefined", length) == 0) return scr_dyn_undefined();
|
||||
if (length == 3 && memcmp(key, "NaN", length) == 0) return scr_dyn_new_num(NAN);
|
||||
if (length == 8 && memcmp(key, "Infinity", length) == 0) return scr_dyn_new_num(INFINITY);
|
||||
if (!scr_dyn_obj_get(scr_global_known, key, length)) return scr_dyn_undefined();
|
||||
ScrJsonBuf text;
|
||||
scr_jb_init(&text);
|
||||
scr_jb_puts(&text, "reading globalThis.");
|
||||
for (size_t i = 0; i < length; i++) scr_jb_putc(&text, key[i]);
|
||||
scr_jb_puts(&text, " through a stored global object is not supported yet [SC2020]");
|
||||
ScrStr *message = scr_jb_finish(&text);
|
||||
scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "SC2020");
|
||||
scr_str_release(message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScrDyn *scr_global_native(ScrArr *known) {
|
||||
static const ScrDynHandleOps ops = {
|
||||
.cls = "Object", .retain = scr_global_retain, .release = scr_global_release,
|
||||
.get = scr_global_get,
|
||||
};
|
||||
scr_dyn_handle_install(SCR_DYNH_GLOBAL, &ops);
|
||||
if (!scr_global_known) scr_global_known = scr_dyn_new_obj();
|
||||
if (!scr_global_cleanup_registered) {
|
||||
atexit(scr_global_cleanup);
|
||||
scr_global_cleanup_registered = true;
|
||||
}
|
||||
for (size_t i = 0; i < known->len; i++) {
|
||||
ScrStr *key = (ScrStr *)scr_arr_get_ref(known, (double)i);
|
||||
if (!scr_dyn_obj_get(scr_global_known, key->data, key->len))
|
||||
scr_dyn_obj_set(scr_global_known, key->data, key->len, scr_dyn_new_bool(true));
|
||||
scr_str_release(key);
|
||||
}
|
||||
return scr_dyn_new_handle(&scr_global_known, SCR_DYNH_GLOBAL);
|
||||
}
|
||||
|
||||
typedef struct ScrBuiltinModule {
|
||||
size_t rc;
|
||||
ScrStr *id;
|
||||
ScrDyn *getter;
|
||||
ScrDyn *exports;
|
||||
struct ScrBuiltinModule *next;
|
||||
} ScrBuiltinModule;
|
||||
|
||||
static SCR_TL ScrBuiltinModule *scr_builtin_modules;
|
||||
static SCR_TL bool scr_builtin_cleanup_registered;
|
||||
|
||||
static void *scr_builtin_retain(void *handle) {
|
||||
ScrBuiltinModule *module = handle;
|
||||
module->rc++;
|
||||
return module;
|
||||
}
|
||||
|
||||
static void scr_builtin_release(void *handle) {
|
||||
ScrBuiltinModule *module = handle;
|
||||
if (--module->rc) return;
|
||||
scr_str_release(module->id);
|
||||
scr_dyn_release(module->getter);
|
||||
scr_dyn_release(module->exports);
|
||||
free(module);
|
||||
}
|
||||
|
||||
static void scr_builtin_cleanup(void) {
|
||||
while (scr_builtin_modules) {
|
||||
ScrBuiltinModule *module = scr_builtin_modules;
|
||||
scr_builtin_modules = module->next;
|
||||
scr_builtin_release(module);
|
||||
}
|
||||
}
|
||||
|
||||
static ScrDyn *scr_builtin_get(void *handle, const char *key, size_t length) {
|
||||
ScrBuiltinModule *module = handle;
|
||||
ScrDyn *cached = scr_dyn_obj_get(module->exports, key, length);
|
||||
if (cached) return scr_dyn_retain(cached);
|
||||
ScrStr *name = scr_str_new(key, length);
|
||||
ScrDyn *arg = scr_dyn_new_str(name);
|
||||
scr_str_release(name);
|
||||
ScrDyn *result = scr_dyn_call(module->getter, &arg, 1, "builtin export");
|
||||
scr_dyn_release(arg);
|
||||
if (!result) return NULL;
|
||||
// Nested path aliases are handles rooted in the registry. Caching them
|
||||
// would add path.posix/path.win32 cycles to the reference-counted graph.
|
||||
if (!(result->kind == SCR_DYN_HANDLE && result->v.handle.tag == SCR_DYNH_BUILTIN_MODULE))
|
||||
scr_dyn_obj_set(module->exports, key, length, scr_dyn_retain(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool scr_builtin_set(void *handle, const char *key, size_t length, const ScrDyn *value) {
|
||||
ScrBuiltinModule *module = handle;
|
||||
scr_dyn_obj_set(module->exports, key, length, scr_dyn_retain((ScrDyn *)value));
|
||||
return true;
|
||||
}
|
||||
|
||||
static ScrDyn *scr_builtin_invoke(void *handle, ScrDyn *self, const char *key,
|
||||
ScrDyn *const *args, size_t argc, const char *what) {
|
||||
ScrDyn *fn = scr_builtin_get(handle, key, strlen(key));
|
||||
if (!fn) return NULL;
|
||||
scr_dyn_this_push_dyn(self);
|
||||
ScrDyn *result = scr_dyn_call(fn, args, argc, what);
|
||||
scr_dyn_this_pop();
|
||||
scr_dyn_release(fn);
|
||||
return result;
|
||||
}
|
||||
|
||||
ScrStr *scr_process_builtin_id(ScrDyn *id, ScrArr *known) {
|
||||
if (id->kind != SCR_DYN_STR) {
|
||||
scr_dyn_arg_type_fail("id", "of type string", id);
|
||||
return NULL;
|
||||
}
|
||||
ScrStr *value = id->v.str;
|
||||
bool prefix = value->len >= 5 && memcmp(value->data, "node:", 5) == 0;
|
||||
for (size_t i = 0; i < known->len; i++) {
|
||||
ScrStr *entry = (ScrStr *)scr_arr_get_ref(known, (double)i);
|
||||
bool exact = entry->len == value->len && memcmp(entry->data, value->data, value->len) == 0;
|
||||
bool prefix_only = entry->len >= 5 && memcmp(entry->data, "node:", 5) == 0;
|
||||
bool bare = prefix && !prefix_only && entry->len == value->len - 5 && memcmp(entry->data, value->data + 5, entry->len) == 0;
|
||||
scr_str_release(entry);
|
||||
if (exact || bare) return scr_str_new(value->data + (prefix ? 5 : 0), value->len - (prefix ? 5 : 0));
|
||||
}
|
||||
return scr_str_new("", 0);
|
||||
}
|
||||
|
||||
ScrDyn *scr_process_builtin_module(ScrStr *id, ScrDyn *getter) {
|
||||
static const ScrDynHandleOps ops = {
|
||||
.cls = "Object", .retain = scr_builtin_retain, .release = scr_builtin_release,
|
||||
.get = scr_builtin_get, .set = scr_builtin_set, .invoke = scr_builtin_invoke,
|
||||
};
|
||||
scr_dyn_handle_install(SCR_DYNH_BUILTIN_MODULE, &ops);
|
||||
for (ScrBuiltinModule *module = scr_builtin_modules; module; module = module->next) {
|
||||
if (module->id->len == id->len && memcmp(module->id->data, id->data, id->len) == 0)
|
||||
return scr_dyn_new_handle(module, SCR_DYNH_BUILTIN_MODULE);
|
||||
}
|
||||
if (!scr_builtin_cleanup_registered) {
|
||||
atexit(scr_builtin_cleanup);
|
||||
scr_builtin_cleanup_registered = true;
|
||||
}
|
||||
ScrBuiltinModule *module = malloc(sizeof(*module));
|
||||
if (!module) scr_trap("scriptc: out of memory\n");
|
||||
*module = (ScrBuiltinModule){ 1, scr_str_retain(id), scr_dyn_retain(getter), scr_dyn_new_obj(), scr_builtin_modules };
|
||||
scr_builtin_modules = module;
|
||||
return scr_dyn_new_handle(module, SCR_DYNH_BUILTIN_MODULE);
|
||||
}
|
||||
|
||||
ScrDyn *scr_process_builtin_unsupported(ScrStr *id, ScrStr *member) {
|
||||
ScrJsonBuf text;
|
||||
scr_jb_init(&text);
|
||||
scr_jb_puts(&text, "native builtin '");
|
||||
for (size_t i = 0; i < id->len; i++) scr_jb_putc(&text, id->data[i]);
|
||||
if (member->len) {
|
||||
scr_jb_putc(&text, '.');
|
||||
for (size_t i = 0; i < member->len; i++) scr_jb_putc(&text, member->data[i]);
|
||||
}
|
||||
scr_jb_puts(&text, "' is not supported through process.getBuiltinModule yet [SC2020]");
|
||||
ScrStr *message = scr_jb_finish(&text);
|
||||
scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "SC2020");
|
||||
scr_str_release(message);
|
||||
return NULL;
|
||||
}
|
||||
@@ -947,11 +947,19 @@ void scr_assert_shape_re(int key, ScrRegex *re) {
|
||||
* "Invalid flags supplied to RegExp constructor 'x'". An empty pattern
|
||||
* stores the spec's "(?:)" source, like Node. Borrows both; +1. */
|
||||
ScrRegex *scr_regex_new(ScrStr *pattern, ScrStr *flags) {
|
||||
unsigned seen_flags = 0;
|
||||
for (size_t i = 0; i < flags->len; i++) {
|
||||
unsigned flag = 0;
|
||||
switch (flags->data[i]) {
|
||||
case 'g': case 'i': case 'm': case 's': case 'u': case 'y':
|
||||
break;
|
||||
default: {
|
||||
case 'g': flag = 1u << 0; break;
|
||||
case 'i': flag = 1u << 1; break;
|
||||
case 'm': flag = 1u << 2; break;
|
||||
case 's': flag = 1u << 3; break;
|
||||
case 'u': flag = 1u << 4; break;
|
||||
case 'y': flag = 1u << 5; break;
|
||||
default: break;
|
||||
}
|
||||
if (!flag || (seen_flags & flag)) {
|
||||
char msg[80];
|
||||
int n = snprintf(msg, sizeof msg,
|
||||
"Invalid flags supplied to RegExp constructor '%.20s'",
|
||||
@@ -959,7 +967,7 @@ ScrRegex *scr_regex_new(ScrStr *pattern, ScrStr *flags) {
|
||||
scr_throw_error_msg(SCR_ERR_SYNTAX, msg, (size_t)n);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
seen_flags |= flag;
|
||||
}
|
||||
ScrRegex *re = calloc(1, sizeof *re);
|
||||
if (!re) {
|
||||
|
||||
@@ -2326,6 +2326,9 @@ ScrStr *scr_process_arch(void);
|
||||
* interned. */
|
||||
ScrStr *scr_process_versions_node(void);
|
||||
ScrStr *scr_process_versions_openssl(void);
|
||||
/* Stable native version dictionary (+1); node/openssl are compatibility
|
||||
* targets, matching the scalar getters above. */
|
||||
ScrDyn *scr_process_versions(void);
|
||||
/* process.kill with Node's exact semantics: int32 pid validation (the
|
||||
* ERR_INVALID_ARG_TYPE TypeError text), Node's signal-name table for the
|
||||
* named form (unknown names throw the ERR_UNKNOWN_SIGNAL TypeError),
|
||||
@@ -3367,6 +3370,11 @@ typedef enum {
|
||||
SCR_DYNH_ABORT_CONTROLLER, /* native static-fetch AbortController */
|
||||
SCR_DYNH_CHILD, /* child_process.ChildProcess */
|
||||
SCR_DYNH_FILE_HANDLE, /* fs/promises.FileHandle */
|
||||
SCR_DYNH_ARRAY_BUFFER, /* fixed-length ArrayBuffer storage */
|
||||
SCR_DYNH_SEGMENTER, /* default Unicode grapheme segmentation */
|
||||
SCR_DYNH_SEGMENTS, /* iterable immutable segmentation result */
|
||||
SCR_DYNH_BUILTIN_MODULE, /* native builtin export object */
|
||||
SCR_DYNH_GLOBAL, /* native global object identity */
|
||||
SCR_DYNH_COUNT,
|
||||
} ScrDynHandleTag;
|
||||
|
||||
@@ -3587,12 +3595,13 @@ ScrDyn *scr_dyn_own_descriptor(const ScrDyn *value, const ScrStr *key);
|
||||
void scr_dyn_proxy_set(ScrDyn *proxy, ScrStr *key, ScrDyn *value);
|
||||
void scr_dyn_proxy_delete(ScrDyn *proxy, const ScrStr *key);
|
||||
void scr_dyn_proxy_unsupported(const char *operation);
|
||||
/* Wraps a fresh COPY of the u8 payload (the static→dyn boundary copies —
|
||||
* DataView-backed sources copy their aliased window). Borrows b. */
|
||||
ScrDyn *scr_dyn_new_bytes_copy(const ScrBytes *b);
|
||||
/* Retains the native view, preserving identity and its shared backing
|
||||
* allocation across the checked-dynamic boundary. Borrows b. */
|
||||
ScrDyn *scr_dyn_new_bytes(const ScrBytes *b);
|
||||
ScrDyn *scr_dyn_bytes_key_get(const ScrDyn *value, const ScrStr *key);
|
||||
/* The Buffer-flavored twin (stream chunks): string coercion/toString
|
||||
* decode utf8 instead of joining elements. */
|
||||
ScrDyn *scr_dyn_new_buffer_copy(const ScrBytes *b);
|
||||
ScrDyn *scr_dyn_new_buffer(const ScrBytes *b);
|
||||
/* Identity-preserving transit capsule used by ReadableStream.from over
|
||||
* typed arrays. The constructor retains `ptr`; matching unbox returns +1.
|
||||
* materialize lazily creates and then retains one detached dyn snapshot.
|
||||
@@ -3615,9 +3624,8 @@ void *scr_dyn_typed_ref_cached_cast(
|
||||
void scr_dyn_typed_ref_cache_cast(
|
||||
ScrDyn *d, const char *type_key, size_t type_key_len, void *ptr,
|
||||
void *(*retain)(void *), void (*release)(void *));
|
||||
/* A fresh u8 COPY of a SCR_DYN_BYTES payload (+1) — the dynCheck
|
||||
* extraction (`u as Uint8Array`). */
|
||||
ScrBytes *scr_dyn_bytes_copy_out(const ScrDyn *d);
|
||||
/* Retains a SCR_DYN_BYTES view (+1) for checked extraction. */
|
||||
ScrBytes *scr_dyn_bytes_unbox(const ScrDyn *d);
|
||||
void scr_dyn_arr_push(ScrDyn *arr, ScrDyn *item);
|
||||
/* Spread completion for a runtime-arity argument list (`f(...xs)` in the
|
||||
* checked-dynamic tier): flattens `src` into `arr` per JS's spread over the
|
||||
@@ -3648,6 +3656,7 @@ ScrDyn *scr_dyn_get_own_property_descriptor(ScrDyn *target, ScrDyn *key);
|
||||
* non-object kinds throw Node's catchable TypeErrors (strict-mode
|
||||
* wording). All three operands BORROWED (the value is retained in). */
|
||||
void scr_dyn_key_set(ScrDyn *recv, ScrStr *key, ScrDyn *value);
|
||||
void scr_dyn_key_set_computed(ScrDyn *recv, ScrDyn *key, ScrDyn *value);
|
||||
void scr_dyn_key_delete(ScrDyn *recv, const ScrStr *key, bool strict);
|
||||
ScrDyn *scr_dyn_global_symbol_get(ScrSym *key); /* borrowed key; +1 value */
|
||||
void scr_dyn_global_symbol_set(ScrSym *key, ScrDyn *value); /* both borrowed */
|
||||
@@ -3815,8 +3824,17 @@ typedef struct ScrDynHandleOps {
|
||||
* answers false for a pairing it does not model (the caller's loud
|
||||
* fence). NULL when the tag accepts no pipes. */
|
||||
bool (*pipe_from)(void *dst, const ScrDyn *src);
|
||||
/* Immutable native iterables may drain into a fresh array. Mutable or
|
||||
* effectful iterators need a separate step/close protocol. NULL = not iterable. */
|
||||
ScrDyn *(*iter_pack)(void *h);
|
||||
} ScrDynHandleOps;
|
||||
|
||||
ScrDyn *scr_intl_segmenter_new(void);
|
||||
ScrStr *scr_process_builtin_id(ScrDyn *id, ScrArr *known);
|
||||
ScrDyn *scr_process_builtin_module(ScrStr *id, ScrDyn *getter);
|
||||
ScrDyn *scr_process_builtin_unsupported(ScrStr *id, ScrStr *member);
|
||||
ScrDyn *scr_global_native(ScrArr *known);
|
||||
|
||||
void scr_dyn_handle_install(ScrDynHandleTag tag, const ScrDynHandleOps *ops);
|
||||
void scr_file_handle_dyn_install(void);
|
||||
/* The tag's class display name ("IncomingMessage") — error texts across
|
||||
@@ -5263,6 +5281,7 @@ typedef struct ScrBytes {
|
||||
* views over views resolve to the owner at construction) and its `data`
|
||||
* points into backing->data — released, never freed. */
|
||||
struct ScrBytes *backing;
|
||||
bool is_buffer; /* Buffer brand belongs to the view, not its backing. */
|
||||
} ScrBytes;
|
||||
|
||||
size_t scr_bytes_elem_size(ScrBytesElem elem); /* 1, 4, or 8 */
|
||||
@@ -5294,6 +5313,25 @@ ScrJsval *scr_jsval_from_bytes(const ScrBytes *b);
|
||||
* THROWS Node's "Invalid typed array length" RangeError catchably and
|
||||
* returns NULL with the exception pending). */
|
||||
ScrBytes *scr_bytes_new(ScrBytesElem elem, double n); /* +1 */
|
||||
ScrBytes *scr_bytes_as_buffer(ScrBytes *bytes); /* borrows; +1, Buffer factory only */
|
||||
/* Views retain the root allocation; offsets are relative to its complete
|
||||
* byte storage, including when src is itself a subarray. */
|
||||
ScrBytes *scr_bytes_buffer_view(ScrBytes *src, ScrBytesElem elem,
|
||||
double offset, bool has_len, double length);
|
||||
ScrDyn *scr_array_buffer_new(ScrDyn *length);
|
||||
ScrDyn *scr_array_buffer_from_bytes(ScrBytes *view);
|
||||
bool scr_array_buffer_is(const ScrDyn *value);
|
||||
bool scr_array_buffer_is_view(const ScrDyn *value);
|
||||
double scr_array_buffer_byte_length_getter(void);
|
||||
ScrDyn *scr_array_buffer_byte_length_descriptor(ScrDyn *getter);
|
||||
ScrBytes *scr_array_buffer_view(ScrBytesElem elem, const ScrDyn *buffer,
|
||||
const ScrDyn *offset, const ScrDyn *length);
|
||||
ScrBytes *scr_array_buffer_view_u8(ScrDyn *, ScrDyn *, ScrDyn *);
|
||||
ScrBytes *scr_array_buffer_view_u32(ScrDyn *, ScrDyn *, ScrDyn *);
|
||||
ScrBytes *scr_array_buffer_view_i32(ScrDyn *, ScrDyn *, ScrDyn *);
|
||||
ScrBytes *scr_array_buffer_view_f32(ScrDyn *, ScrDyn *, ScrDyn *);
|
||||
ScrBytes *scr_array_buffer_view_f64(ScrDyn *, ScrDyn *, ScrDyn *);
|
||||
ScrBytes *scr_array_buffer_view_dv(ScrDyn *, ScrDyn *, ScrDyn *);
|
||||
/* Native callback boundary: exact owned u8 copy. NULL with len == 0 is an
|
||||
* empty span. */
|
||||
ScrBytes *scr_bytes_from_data(const uint8_t *data, size_t len); /* +1 */
|
||||
|
||||
@@ -845,7 +845,7 @@ static void scr_stream_dyn_data(ScrDyn *const *args, size_t argc,
|
||||
*data_str = NULL;
|
||||
if (argc < 2) return;
|
||||
const ScrDyn *a = args[1];
|
||||
if (a->kind == SCR_DYN_BYTES) *data = scr_dyn_bytes_copy_out(a);
|
||||
if (a->kind == SCR_DYN_BYTES) *data = scr_dyn_bytes_unbox(a);
|
||||
else if (a->kind == SCR_DYN_STR) *data_str = scr_str_retain(a->v.str);
|
||||
}
|
||||
|
||||
@@ -877,7 +877,7 @@ ScrDyn *scr_stream_done_dyn_l(ScrClosure *clo, ScrDyn *const *args, size_t argc)
|
||||
bool scr_stream_push_dyn(ScrStream *s, const ScrDyn *d) {
|
||||
switch (d->kind) {
|
||||
case SCR_DYN_BYTES: {
|
||||
ScrBytes *b = scr_dyn_bytes_copy_out(d);
|
||||
ScrBytes *b = scr_dyn_bytes_unbox(d);
|
||||
bool r = scr_stream_push(s, b);
|
||||
scr_bytes_release(b);
|
||||
return r;
|
||||
@@ -897,7 +897,7 @@ bool scr_stream_push_dyn(ScrStream *s, const ScrDyn *d) {
|
||||
bool scr_stream_write_dyn(ScrStream *s, const ScrDyn *d, ScrClosure *cb) {
|
||||
switch (d->kind) {
|
||||
case SCR_DYN_BYTES: {
|
||||
ScrBytes *b = scr_dyn_bytes_copy_out(d);
|
||||
ScrBytes *b = scr_dyn_bytes_unbox(d);
|
||||
bool r = scr_stream_write(s, b, cb);
|
||||
scr_bytes_release(b);
|
||||
return r;
|
||||
@@ -923,7 +923,7 @@ static void scr_stream_next_fulfill(ScrStreamState *st, ScrPromise *w /*moves*/,
|
||||
d = scr_dyn_new_str((ScrStr *)chunk);
|
||||
scr_str_release((ScrStr *)chunk);
|
||||
} else {
|
||||
d = scr_dyn_new_buffer_copy((ScrBytes *)chunk);
|
||||
d = scr_dyn_new_buffer((ScrBytes *)chunk);
|
||||
scr_bytes_release((ScrBytes *)chunk);
|
||||
}
|
||||
scr_promise_fulfill_ref(w, d, scr_dyn_retain_v, scr_dyn_release_v, NULL);
|
||||
@@ -1566,7 +1566,7 @@ static void scr_stream_dynopt_read_inv(ScrClosure *cb, ScrStream *s, double size
|
||||
static void scr_stream_dynopt_chunk3(ScrClosure *cb, ScrStream *s, ScrBytes *chunk,
|
||||
ScrDynThunk glue, const char *what) {
|
||||
ScrDyn *args[3];
|
||||
args[0] = scr_dyn_new_buffer_copy(chunk);
|
||||
args[0] = scr_dyn_new_buffer(chunk);
|
||||
ScrStr *enc = scr_str_new("buffer", 6);
|
||||
args[1] = scr_dyn_new_str(enc);
|
||||
scr_str_release(enc);
|
||||
@@ -1584,7 +1584,7 @@ static void scr_stream_dynopt_write_inv(ScrClosure *cb, ScrStream *s, ScrBytes *
|
||||
|
||||
static void scr_stream_dynopt_transform_inv(ScrClosure *cb, ScrStream *s, ScrBytes *chunk) {
|
||||
ScrDyn *args[3];
|
||||
args[0] = scr_dyn_new_buffer_copy(chunk);
|
||||
args[0] = scr_dyn_new_buffer(chunk);
|
||||
ScrStr *enc = scr_str_new("buffer", 6);
|
||||
args[1] = scr_dyn_new_str(enc);
|
||||
scr_str_release(enc);
|
||||
|
||||
@@ -1105,7 +1105,7 @@ static ScrBytes *scr_tls_pem_dyn(const ScrDyn *v, const char *what, bool concat)
|
||||
memcpy(b->data, v->v.str->data, v->v.str->len);
|
||||
return b;
|
||||
}
|
||||
if (v->kind == SCR_DYN_BYTES) return scr_dyn_bytes_copy_out(v);
|
||||
if (v->kind == SCR_DYN_BYTES) return scr_dyn_bytes_unbox(v);
|
||||
if (v->kind == SCR_DYN_ARR) {
|
||||
if (v->v.arr.len == 0) {
|
||||
ScrJsonBuf b;
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
UNICODE LICENSE V3
|
||||
|
||||
COPYRIGHT AND PERMISSION NOTICE
|
||||
|
||||
Copyright © 1991-2026 Unicode, Inc.
|
||||
|
||||
NOTICE TO USER: Carefully read the following legal agreement. BY
|
||||
DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
|
||||
SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
|
||||
TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
|
||||
DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of data files and any associated documentation (the "Data Files") or
|
||||
software and any associated documentation (the "Software") to deal in the
|
||||
Data Files or Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, and/or sell
|
||||
copies of the Data Files or Software, and to permit persons to whom the
|
||||
Data Files or Software are furnished to do so, provided that either (a)
|
||||
this copyright and permission notice appear with all copies of the Data
|
||||
Files or Software, or (b) this copyright and permission notice appear in
|
||||
associated Documentation.
|
||||
|
||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
THIRD PARTY RIGHTS.
|
||||
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
|
||||
BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
|
||||
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
|
||||
FILES OR SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder shall
|
||||
not be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in these Data Files or Software without prior written
|
||||
authorization of the copyright holder.
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env node
|
||||
// Unicode 17 default extended grapheme clusters (UAX #29), matching the
|
||||
// pinned Node release. Normal builds use the checked-in tables and cases.
|
||||
import { createHash } from "node:crypto";
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { join } from "node:path";
|
||||
|
||||
const root = fileURLToPath(new URL("..", import.meta.url));
|
||||
const inputs = [
|
||||
["auxiliary/GraphemeBreakProperty.txt", "d6b51d1d2ae5c33b451b7ed994b48f1f4dc62b2272a5831e7fd418514a6bae89"],
|
||||
["DerivedCoreProperties.txt", "24c7fed1195c482faaefd5c1e7eb821c5ee1fb6de07ecdbaa64b56a99da22c08"],
|
||||
["emoji/emoji-data.txt", "2cb2bb9455cda83e8481541ecf5b6dfda66a3bb89efa3fa7c5297eccf607b72b"],
|
||||
["auxiliary/GraphemeBreakTest.txt", "e2d134d2c52919bace503ebb6a551c1855fe1a1faec18478c78fff254a1793ec"],
|
||||
];
|
||||
const files = await Promise.all(inputs.map(async ([path, hash]) => {
|
||||
const bytes = process.argv[2]
|
||||
? await readFile(join(process.argv[2], path.split("/").at(-1)))
|
||||
: await (async () => {
|
||||
const response = await fetch(`https://www.unicode.org/Public/17.0.0/ucd/${path}`);
|
||||
if (!response.ok) throw new Error(`${path}: ${response.status}`);
|
||||
return Buffer.from(await response.arrayBuffer());
|
||||
})();
|
||||
if (createHash("sha256").update(bytes).digest("hex") !== hash) throw new Error(`${path}: checksum mismatch`);
|
||||
return bytes.toString("utf8");
|
||||
}));
|
||||
|
||||
const names = ["Other", "CR", "LF", "Control", "Extend", "ZWJ", "Regional_Indicator", "Prepend", "SpacingMark", "L", "V", "T", "LV", "LVT"];
|
||||
const data = new Uint8Array(0x110000);
|
||||
function properties(text, select) {
|
||||
for (const line of text.split("\n")) {
|
||||
const fields = line.split("#")[0].trim().split(";").map((x) => x.trim());
|
||||
if (fields.length < 2) continue;
|
||||
const value = select(fields);
|
||||
if (!value) continue;
|
||||
const [start, end = start] = fields[0].split("..").map((x) => parseInt(x, 16));
|
||||
for (let cp = start; cp <= end; cp++) data[cp] |= value;
|
||||
}
|
||||
}
|
||||
properties(files[0], ([, value]) => names.indexOf(value));
|
||||
properties(files[1], ([, property, value]) => property === "InCB" ? ["None", "Consonant", "Extend", "Linker"].indexOf(value) << 4 : 0);
|
||||
properties(files[2], ([, property]) => property === "Extended_Pictographic" ? 64 : 0);
|
||||
// Hangul syllables have an algorithmic LV/LVT classification.
|
||||
data.fill(0, 0xac00, 0xd7a4);
|
||||
const rows = [];
|
||||
for (let start = 0; start < data.length;) {
|
||||
let end = start + 1;
|
||||
while (end < data.length && data[end] === data[start]) end++;
|
||||
if (data[start]) rows.push(` { 0x${start.toString(16)}, 0x${(end - 1).toString(16)}, ${data[start]} },`);
|
||||
start = end;
|
||||
}
|
||||
const header = [
|
||||
"/* Generated by scripts/gen-grapheme-tables.mjs; Unicode 17.0.0.",
|
||||
" * Unicode data is licensed under vendor/unicode/LICENSE. Do not edit. */",
|
||||
"#ifndef SCR_GRAPHEME_DATA_H",
|
||||
"#define SCR_GRAPHEME_DATA_H",
|
||||
"enum { " + names.map((name, index) => `SCR_GCB_${name.toUpperCase()} = ${index}`).join(", ") + " };",
|
||||
"typedef struct { uint32_t start, end; uint8_t properties; } ScrGraphemeRange;",
|
||||
"static const ScrGraphemeRange scr_grapheme_ranges[] = {",
|
||||
...rows,
|
||||
"};",
|
||||
"#endif",
|
||||
"",
|
||||
].join("\n");
|
||||
await writeFile(join(root, "packages/runtime/src/scr_grapheme_data.h"), header);
|
||||
|
||||
const cases = [];
|
||||
for (const line of files[3].split("\n")) {
|
||||
const content = line.split("#")[0].trim();
|
||||
if (!content) continue;
|
||||
let input = "";
|
||||
const breaks = [];
|
||||
for (const token of content.split(/\s+/)) {
|
||||
if (token === "÷") breaks.push(input.length);
|
||||
else if (token !== "×") input += String.fromCodePoint(parseInt(token, 16));
|
||||
}
|
||||
cases.push([input, breaks.join(",")]);
|
||||
}
|
||||
const corpusDir = join(root, "tests/corpus/intl-grapheme-conformance");
|
||||
await mkdir(corpusDir, { recursive: true });
|
||||
// Escape non-ASCII source so control characters never corrupt the fixture.
|
||||
const quote = (text) => JSON.stringify(text).replace(/[\u007f-\uffff]/g, (ch) => `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
||||
await writeFile(join(corpusDir, "cases.ts"), [
|
||||
"// Generated from Unicode 17.0.0 GraphemeBreakTest.txt by scripts/gen-grapheme-tables.mjs.",
|
||||
"// Unicode data license: packages/runtime/vendor/unicode/LICENSE.",
|
||||
"export const cases: string[][] = [",
|
||||
...cases.map(([input, breaks]) => ` [${quote(input)}, ${quote(breaks)}],`),
|
||||
"];",
|
||||
"",
|
||||
].join("\n"));
|
||||
console.log(`wrote ${rows.length} property ranges and ${cases.length} grapheme conformance cases`);
|
||||
@@ -1,6 +1,6 @@
|
||||
// Uint8Array/Buffer values crossing into `unknown`: the checked-dynamic tree's bytes kind —
|
||||
// conversion on the way in (a copy, the boundary stance), checked-cast
|
||||
// extraction on the way out (another copy), Node-exact String() (elements
|
||||
// retention on the way in, checked-cast extraction sharing the view on
|
||||
// the way out, Node-exact String() (elements
|
||||
// joined) and JSON.stringify (the index-keyed object form). The stdin
|
||||
// toBytes(chunk: unknown) pattern.
|
||||
|
||||
@@ -26,16 +26,11 @@ scratch.buf = new Uint8Array([1, 2, 3]);
|
||||
console.log(String(scratch.buf), (scratch.buf as Uint8Array).length);
|
||||
console.log(JSON.stringify(scratch));
|
||||
|
||||
// Extraction is a fresh value each time (both directions copy — the
|
||||
// documented aliasing divergence is asserted in the dyncheck harness, not
|
||||
// against Node); the BYTES are value-exact.
|
||||
// Repeated extraction preserves the view and its byte contents.
|
||||
const again = scratch.buf as Uint8Array;
|
||||
console.log(again[0] + again[1] + again[2]);
|
||||
|
||||
// Buffer is bytes<u8> too. (String() of an unknown holding a BUFFER joins
|
||||
// the elements like a Uint8Array — Node decodes UTF-8 there; the checked-dynamic tree
|
||||
// cannot tell the two apart. SEMANTICS.md documents it; not asserted here
|
||||
// where Node is the oracle.)
|
||||
// Buffer shares bytes<u8> storage while preserving its runtime brand.
|
||||
const buf = Buffer.from("hi");
|
||||
const ub: unknown = buf;
|
||||
console.log((ub as Uint8Array).length, (ub as Uint8Array)[0]);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
let order = "";
|
||||
function offset(value) {
|
||||
return { valueOf() { order += "o"; return value; } };
|
||||
}
|
||||
function length(value) {
|
||||
return { valueOf() { order += "l"; return value; } };
|
||||
}
|
||||
const buffer = new ArrayBuffer(8);
|
||||
for (const n of [-1, 1, 8, 12, Infinity]) {
|
||||
order = "";
|
||||
try {
|
||||
// @ts-expect-error Numeric inputs use the JavaScript coercion protocol.
|
||||
const view = new Uint32Array(buffer, offset(n), length(0));
|
||||
console.log(view.byteOffset, view.length);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) console.log(error.name);
|
||||
}
|
||||
console.log(order);
|
||||
}
|
||||
for (const n of [-1, 1, 9]) {
|
||||
order = "";
|
||||
try {
|
||||
// @ts-expect-error Numeric inputs use the JavaScript coercion protocol.
|
||||
const view = new DataView(buffer, offset(n), length(0));
|
||||
console.log(view.byteOffset, view.byteLength);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) console.log(error.name);
|
||||
}
|
||||
console.log(order);
|
||||
}
|
||||
order = "";
|
||||
// @ts-expect-error Extra arguments are evaluated but ignored for array inputs.
|
||||
const copied = new Uint32Array([5, 6], offset(-1), length(-1));
|
||||
console.log(copied.length, copied[0], copied[1], order);
|
||||
// @ts-expect-error Extra arguments are evaluated but ignored for length inputs.
|
||||
const allocated = new Uint8Array(3, offset(-1), length(-1));
|
||||
console.log(allocated.length, order);
|
||||
@@ -0,0 +1,32 @@
|
||||
const buffer = new ArrayBuffer(24);
|
||||
const bytes = new Uint8Array(buffer);
|
||||
const words = new Uint32Array(buffer, 4, 2);
|
||||
const view = new DataView(buffer, 4, 8);
|
||||
console.log(buffer.byteLength, buffer.maxByteLength, buffer.resizable, buffer.detached);
|
||||
console.log(bytes.buffer === buffer, words.buffer === buffer, view.buffer === buffer);
|
||||
view.setUint32(0, 0x12345678, true);
|
||||
console.log(words[0], bytes[4], bytes[7], words.byteOffset, words.byteLength);
|
||||
const tail = bytes.subarray(5, 9);
|
||||
console.log(tail.buffer === buffer, tail.byteOffset, tail.length);
|
||||
const shared = Buffer.from(buffer, 5, 3);
|
||||
shared[0] = 99;
|
||||
console.log(bytes[5], view.getUint8(1), shared.buffer === buffer);
|
||||
const copy = buffer.slice(4, 8);
|
||||
const copied = new Uint8Array(copy);
|
||||
copied[0] = 7;
|
||||
console.log(copy.byteLength, copy !== buffer, bytes[4], copied[0]);
|
||||
const held: unknown = buffer;
|
||||
console.log(held === buffer, held instanceof ArrayBuffer, bytes instanceof ArrayBuffer);
|
||||
console.log(ArrayBuffer.isView(buffer), ArrayBuffer.isView(bytes), ArrayBuffer.isView(view));
|
||||
const descriptor = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength")!;
|
||||
const getter: unknown = descriptor.get;
|
||||
console.log(descriptor.enumerable, descriptor.configurable, descriptor.set === undefined);
|
||||
if (typeof getter === "function") {
|
||||
console.log(getter.name, getter.length, getter.call(buffer), getter.call(held));
|
||||
console.log(getter === Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength")!.get);
|
||||
try { getter.call(bytes); } catch (error) { if (error instanceof Error) console.log(error.name); }
|
||||
}
|
||||
try { new Uint32Array(buffer, 1); } catch (error) { if (error instanceof Error) console.log(error.name); }
|
||||
try { new DataView(buffer, 25); } catch (error) { if (error instanceof Error) console.log(error.name); }
|
||||
console.log(new ArrayBuffer(3.9).byteLength, new ArrayBuffer(NaN).byteLength);
|
||||
try { new ArrayBuffer(-1); } catch (error) { if (error instanceof Error) console.log(error.name); }
|
||||
@@ -0,0 +1,32 @@
|
||||
import { alias, metadata, subarray, slice, change, same, clone, describe, coerceWrites } from "./values.js";
|
||||
|
||||
const storage = new ArrayBuffer(12);
|
||||
const bytes = new Uint8Array(storage, 3, 6);
|
||||
bytes[0] = 11;
|
||||
const stored: Uint8Array = alias(bytes);
|
||||
console.log(stored === bytes, same(bytes, bytes), same(bytes, bytes.subarray(0)));
|
||||
metadata(stored, storage);
|
||||
change(stored, 0, 37);
|
||||
console.log(bytes[0], stored[0]);
|
||||
const view: Uint8Array = subarray(stored, 1, 4);
|
||||
console.log(view.byteOffset, view.byteLength, view.buffer === storage);
|
||||
view[0] = 19;
|
||||
console.log(bytes[1]);
|
||||
const independent: Uint8Array = slice(stored, 1, 4);
|
||||
independent[0] = 99;
|
||||
console.log(independent.buffer !== storage, bytes[1], independent[0]);
|
||||
const copied: Uint8Array = clone(stored);
|
||||
copied[0] = 55;
|
||||
console.log(copied !== bytes, copied.buffer !== storage, bytes[0], copied[0]);
|
||||
const buffer = Buffer.alloc(6);
|
||||
buffer[0] = 3;
|
||||
const bufferView: Uint8Array = slice(buffer, 0, 2);
|
||||
bufferView[0] = 17;
|
||||
console.log(buffer[0], bufferView[0]);
|
||||
const retained: Uint8Array = alias(new Uint8Array([4, 5, 6]));
|
||||
console.log(retained[0], retained[1], retained[2]);
|
||||
coerceWrites(retained);
|
||||
describe(Buffer.from("hi"));
|
||||
describe(new Uint8Array([104, 105]));
|
||||
describe(clone(Buffer.from("hi")));
|
||||
describe(slice(Buffer.from("hi"), 0, 1));
|
||||
@@ -0,0 +1,16 @@
|
||||
export function alias(value) { return value; }
|
||||
export function same(a, b) { return a === b; }
|
||||
export function metadata(value, buffer) {
|
||||
console.log(value.length, value.byteLength, value.byteOffset, value.buffer === buffer, value.buffer === value.buffer);
|
||||
}
|
||||
export function subarray(value, start, end) { return value.subarray(start, end); }
|
||||
export function slice(value, start, end) { return value.slice(start, end); }
|
||||
export function change(value, index, number) { value[index] = number; }
|
||||
export function clone(value) { return structuredClone(value); }
|
||||
export function describe(value) { console.log(Buffer.isBuffer(value), String(value)); }
|
||||
export function coerceWrites(value) {
|
||||
let calls = 0;
|
||||
const number = { valueOf() { calls++; return 260; } };
|
||||
for (const key of ["0", "-0", "-1", "1.5", "99", "NaN", "Infinity"]) value[key] = number;
|
||||
console.log(calls, value[0], value[99], value["-0"]);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
const n: number = 3;
|
||||
const t = n > 0 ? "pos" : "neg";
|
||||
const o = { ...{ a: 1 } };
|
||||
const b = "a" in { a: 1 };
|
||||
const m = typeof "ab".indexOf("b"); // a CALL operand — pure computations fold now
|
||||
const u = n === 3 ? 1 : 2;
|
||||
const s: string = "abc";
|
||||
const mixed = n === 3 && s;
|
||||
console.log(t, m, u, b, mixed, o.a);
|
||||
let effects = "";
|
||||
function produce(): number { effects += "called"; return 17; }
|
||||
console.log(typeof produce(), effects);
|
||||
function fail(): number { effects += ":throw"; throw new Error("operand"); }
|
||||
try { console.log(typeof fail()); } catch (error) {
|
||||
if (error instanceof Error) console.log(error.message, effects);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
const bun = globalThis.Bun;
|
||||
const width = bun?.stringWidth ?? ((text) => text.length);
|
||||
const sleep = bun?.sleep ?? (() => "portable");
|
||||
console.log(typeof bun, width("hello"), sleep());
|
||||
console.log(globalThis?.Bun === undefined, globalThis.Deno === undefined);
|
||||
const scope = globalThis;
|
||||
console.log(scope.Bun === undefined, global.Bun === undefined);
|
||||
function shadowed(globalThis) {
|
||||
return globalThis.Bun.stringWidth("abc");
|
||||
}
|
||||
console.log(shadowed({ Bun: { stringWidth: (text) => text.length + 4 } }));
|
||||
@@ -0,0 +1,30 @@
|
||||
before();
|
||||
try { probe(); } catch (error) { console.log(error.name, error.message); }
|
||||
var scope = globalThis;
|
||||
console.log(typeof scope, scope === globalThis, scope === global);
|
||||
console.log(scope.globalThis === scope, scope.global === scope);
|
||||
console.log(scope.NaN !== scope.NaN, scope.Infinity === Infinity, scope.undefined === undefined);
|
||||
console.log(probe(), scope.Worker, scope.close);
|
||||
function probe() { return typeof scope.postMessage; }
|
||||
function before() { console.log(typeof scope, scope?.Bun); }
|
||||
function local() {
|
||||
beforeLocal();
|
||||
var host = globalThis;
|
||||
const copy = host;
|
||||
console.log(copy === host, copy.Bun, host.Deno);
|
||||
host = { postMessage: () => "local" };
|
||||
console.log(host.postMessage(), copy.postMessage);
|
||||
function beforeLocal() { console.log(typeof host, host?.Bun); }
|
||||
}
|
||||
local();
|
||||
scope = { postMessage: () => "replaced" };
|
||||
console.log(probe(), scope.postMessage());
|
||||
function shadowed(globalThis) {
|
||||
var host = globalThis;
|
||||
return host.Bun;
|
||||
}
|
||||
console.log(shadowed({ Bun: "shadow" }));
|
||||
try { readLexical(); } catch (error) { console.log(error.name); }
|
||||
let lexical = globalThis;
|
||||
console.log(readLexical());
|
||||
function readLexical() { return typeof lexical.Bun; }
|
||||
@@ -0,0 +1,32 @@
|
||||
let values;
|
||||
((entry) => {
|
||||
entry[entry["Left"] = 0] = "Left";
|
||||
entry[entry["Right"] = 1] = "Right";
|
||||
})(values ||= {});
|
||||
console.log(values.Left, values[0], values.Right, values[1]);
|
||||
let order = "";
|
||||
let object = {};
|
||||
const original = object;
|
||||
function receiver() { order += "r"; return object; }
|
||||
function key() { order += "k"; return "answer"; }
|
||||
function value() { order += "v"; object = {}; return 42; }
|
||||
console.log(receiver()[key()] = value(), order, original.answer, object.answer);
|
||||
const token = { toString() { order += "c"; return "key"; } };
|
||||
order = "";
|
||||
console.log(original[token] = value(), order);
|
||||
console.log(original["missing"] = undefined, "missing" in original);
|
||||
const setter = {};
|
||||
Object.defineProperty(setter, "x", { set(v) { order += v; }, get() { throw new Error("must not read"); } });
|
||||
order = "";
|
||||
console.log(setter["x"] = 7, order);
|
||||
let bad = null;
|
||||
order = "";
|
||||
try { bad[key()] = value(); } catch (error) { console.log(error.name, order); }
|
||||
order = "";
|
||||
try { console.log(bad[token] = value()); } catch (error) { console.log(error.name, error.message, order); }
|
||||
order = "";
|
||||
const failingKey = { toString() { order += "c"; throw new Error("key"); } };
|
||||
try { console.log(original[failingKey] = value()); } catch (error) { console.log(error.message, order); }
|
||||
order = "";
|
||||
function failValue() { order += "v"; throw new Error("value"); }
|
||||
try { console.log(original[token] = failValue()); } catch (error) { console.log(error.message, order); }
|
||||
@@ -0,0 +1,770 @@
|
||||
// Generated from Unicode 17.0.0 GraphemeBreakTest.txt by scripts/gen-grapheme-tables.mjs.
|
||||
// Unicode data license: packages/runtime/vendor/unicode/LICENSE.
|
||||
export const cases: string[][] = [
|
||||
["\r\r", "0,1,2"],
|
||||
["\r\u0308\r", "0,1,2,3"],
|
||||
["\r\n", "0,2"],
|
||||
["\r\u0308\n", "0,1,2,3"],
|
||||
["\r\u0000", "0,1,2"],
|
||||
["\r\u0308\u0000", "0,1,2,3"],
|
||||
["\r\u094d", "0,1,2"],
|
||||
["\r\u0308\u094d", "0,1,3"],
|
||||
["\r\u0300", "0,1,2"],
|
||||
["\r\u0308\u0300", "0,1,3"],
|
||||
["\r\u200c", "0,1,2"],
|
||||
["\r\u0308\u200c", "0,1,3"],
|
||||
["\r\u200d", "0,1,2"],
|
||||
["\r\u0308\u200d", "0,1,3"],
|
||||
["\r\ud83c\udde6", "0,1,3"],
|
||||
["\r\u0308\ud83c\udde6", "0,1,2,4"],
|
||||
["\r\u06dd", "0,1,2"],
|
||||
["\r\u0308\u06dd", "0,1,2,3"],
|
||||
["\r\u0903", "0,1,2"],
|
||||
["\r\u0308\u0903", "0,1,3"],
|
||||
["\r\u1100", "0,1,2"],
|
||||
["\r\u0308\u1100", "0,1,2,3"],
|
||||
["\r\u1160", "0,1,2"],
|
||||
["\r\u0308\u1160", "0,1,2,3"],
|
||||
["\r\u11a8", "0,1,2"],
|
||||
["\r\u0308\u11a8", "0,1,2,3"],
|
||||
["\r\uac00", "0,1,2"],
|
||||
["\r\u0308\uac00", "0,1,2,3"],
|
||||
["\r\uac01", "0,1,2"],
|
||||
["\r\u0308\uac01", "0,1,2,3"],
|
||||
["\r\u0915", "0,1,2"],
|
||||
["\r\u0308\u0915", "0,1,2,3"],
|
||||
["\r\u00a9", "0,1,2"],
|
||||
["\r\u0308\u00a9", "0,1,2,3"],
|
||||
["\r ", "0,1,2"],
|
||||
["\r\u0308 ", "0,1,2,3"],
|
||||
["\r\u0378", "0,1,2"],
|
||||
["\r\u0308\u0378", "0,1,2,3"],
|
||||
["\n\r", "0,1,2"],
|
||||
["\n\u0308\r", "0,1,2,3"],
|
||||
["\n\n", "0,1,2"],
|
||||
["\n\u0308\n", "0,1,2,3"],
|
||||
["\n\u0000", "0,1,2"],
|
||||
["\n\u0308\u0000", "0,1,2,3"],
|
||||
["\n\u094d", "0,1,2"],
|
||||
["\n\u0308\u094d", "0,1,3"],
|
||||
["\n\u0300", "0,1,2"],
|
||||
["\n\u0308\u0300", "0,1,3"],
|
||||
["\n\u200c", "0,1,2"],
|
||||
["\n\u0308\u200c", "0,1,3"],
|
||||
["\n\u200d", "0,1,2"],
|
||||
["\n\u0308\u200d", "0,1,3"],
|
||||
["\n\ud83c\udde6", "0,1,3"],
|
||||
["\n\u0308\ud83c\udde6", "0,1,2,4"],
|
||||
["\n\u06dd", "0,1,2"],
|
||||
["\n\u0308\u06dd", "0,1,2,3"],
|
||||
["\n\u0903", "0,1,2"],
|
||||
["\n\u0308\u0903", "0,1,3"],
|
||||
["\n\u1100", "0,1,2"],
|
||||
["\n\u0308\u1100", "0,1,2,3"],
|
||||
["\n\u1160", "0,1,2"],
|
||||
["\n\u0308\u1160", "0,1,2,3"],
|
||||
["\n\u11a8", "0,1,2"],
|
||||
["\n\u0308\u11a8", "0,1,2,3"],
|
||||
["\n\uac00", "0,1,2"],
|
||||
["\n\u0308\uac00", "0,1,2,3"],
|
||||
["\n\uac01", "0,1,2"],
|
||||
["\n\u0308\uac01", "0,1,2,3"],
|
||||
["\n\u0915", "0,1,2"],
|
||||
["\n\u0308\u0915", "0,1,2,3"],
|
||||
["\n\u00a9", "0,1,2"],
|
||||
["\n\u0308\u00a9", "0,1,2,3"],
|
||||
["\n ", "0,1,2"],
|
||||
["\n\u0308 ", "0,1,2,3"],
|
||||
["\n\u0378", "0,1,2"],
|
||||
["\n\u0308\u0378", "0,1,2,3"],
|
||||
["\u0000\r", "0,1,2"],
|
||||
["\u0000\u0308\r", "0,1,2,3"],
|
||||
["\u0000\n", "0,1,2"],
|
||||
["\u0000\u0308\n", "0,1,2,3"],
|
||||
["\u0000\u0000", "0,1,2"],
|
||||
["\u0000\u0308\u0000", "0,1,2,3"],
|
||||
["\u0000\u094d", "0,1,2"],
|
||||
["\u0000\u0308\u094d", "0,1,3"],
|
||||
["\u0000\u0300", "0,1,2"],
|
||||
["\u0000\u0308\u0300", "0,1,3"],
|
||||
["\u0000\u200c", "0,1,2"],
|
||||
["\u0000\u0308\u200c", "0,1,3"],
|
||||
["\u0000\u200d", "0,1,2"],
|
||||
["\u0000\u0308\u200d", "0,1,3"],
|
||||
["\u0000\ud83c\udde6", "0,1,3"],
|
||||
["\u0000\u0308\ud83c\udde6", "0,1,2,4"],
|
||||
["\u0000\u06dd", "0,1,2"],
|
||||
["\u0000\u0308\u06dd", "0,1,2,3"],
|
||||
["\u0000\u0903", "0,1,2"],
|
||||
["\u0000\u0308\u0903", "0,1,3"],
|
||||
["\u0000\u1100", "0,1,2"],
|
||||
["\u0000\u0308\u1100", "0,1,2,3"],
|
||||
["\u0000\u1160", "0,1,2"],
|
||||
["\u0000\u0308\u1160", "0,1,2,3"],
|
||||
["\u0000\u11a8", "0,1,2"],
|
||||
["\u0000\u0308\u11a8", "0,1,2,3"],
|
||||
["\u0000\uac00", "0,1,2"],
|
||||
["\u0000\u0308\uac00", "0,1,2,3"],
|
||||
["\u0000\uac01", "0,1,2"],
|
||||
["\u0000\u0308\uac01", "0,1,2,3"],
|
||||
["\u0000\u0915", "0,1,2"],
|
||||
["\u0000\u0308\u0915", "0,1,2,3"],
|
||||
["\u0000\u00a9", "0,1,2"],
|
||||
["\u0000\u0308\u00a9", "0,1,2,3"],
|
||||
["\u0000 ", "0,1,2"],
|
||||
["\u0000\u0308 ", "0,1,2,3"],
|
||||
["\u0000\u0378", "0,1,2"],
|
||||
["\u0000\u0308\u0378", "0,1,2,3"],
|
||||
["\u094d\r", "0,1,2"],
|
||||
["\u094d\u0308\r", "0,2,3"],
|
||||
["\u094d\n", "0,1,2"],
|
||||
["\u094d\u0308\n", "0,2,3"],
|
||||
["\u094d\u0000", "0,1,2"],
|
||||
["\u094d\u0308\u0000", "0,2,3"],
|
||||
["\u094d\u094d", "0,2"],
|
||||
["\u094d\u0308\u094d", "0,3"],
|
||||
["\u094d\u0300", "0,2"],
|
||||
["\u094d\u0308\u0300", "0,3"],
|
||||
["\u094d\u200c", "0,2"],
|
||||
["\u094d\u0308\u200c", "0,3"],
|
||||
["\u094d\u200d", "0,2"],
|
||||
["\u094d\u0308\u200d", "0,3"],
|
||||
["\u094d\ud83c\udde6", "0,1,3"],
|
||||
["\u094d\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u094d\u06dd", "0,1,2"],
|
||||
["\u094d\u0308\u06dd", "0,2,3"],
|
||||
["\u094d\u0903", "0,2"],
|
||||
["\u094d\u0308\u0903", "0,3"],
|
||||
["\u094d\u1100", "0,1,2"],
|
||||
["\u094d\u0308\u1100", "0,2,3"],
|
||||
["\u094d\u1160", "0,1,2"],
|
||||
["\u094d\u0308\u1160", "0,2,3"],
|
||||
["\u094d\u11a8", "0,1,2"],
|
||||
["\u094d\u0308\u11a8", "0,2,3"],
|
||||
["\u094d\uac00", "0,1,2"],
|
||||
["\u094d\u0308\uac00", "0,2,3"],
|
||||
["\u094d\uac01", "0,1,2"],
|
||||
["\u094d\u0308\uac01", "0,2,3"],
|
||||
["\u094d\u0915", "0,1,2"],
|
||||
["\u094d\u0308\u0915", "0,2,3"],
|
||||
["\u094d\u00a9", "0,1,2"],
|
||||
["\u094d\u0308\u00a9", "0,2,3"],
|
||||
["\u094d ", "0,1,2"],
|
||||
["\u094d\u0308 ", "0,2,3"],
|
||||
["\u094d\u0378", "0,1,2"],
|
||||
["\u094d\u0308\u0378", "0,2,3"],
|
||||
["\u0300\r", "0,1,2"],
|
||||
["\u0300\u0308\r", "0,2,3"],
|
||||
["\u0300\n", "0,1,2"],
|
||||
["\u0300\u0308\n", "0,2,3"],
|
||||
["\u0300\u0000", "0,1,2"],
|
||||
["\u0300\u0308\u0000", "0,2,3"],
|
||||
["\u0300\u094d", "0,2"],
|
||||
["\u0300\u0308\u094d", "0,3"],
|
||||
["\u0300\u0300", "0,2"],
|
||||
["\u0300\u0308\u0300", "0,3"],
|
||||
["\u0300\u200c", "0,2"],
|
||||
["\u0300\u0308\u200c", "0,3"],
|
||||
["\u0300\u200d", "0,2"],
|
||||
["\u0300\u0308\u200d", "0,3"],
|
||||
["\u0300\ud83c\udde6", "0,1,3"],
|
||||
["\u0300\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u0300\u06dd", "0,1,2"],
|
||||
["\u0300\u0308\u06dd", "0,2,3"],
|
||||
["\u0300\u0903", "0,2"],
|
||||
["\u0300\u0308\u0903", "0,3"],
|
||||
["\u0300\u1100", "0,1,2"],
|
||||
["\u0300\u0308\u1100", "0,2,3"],
|
||||
["\u0300\u1160", "0,1,2"],
|
||||
["\u0300\u0308\u1160", "0,2,3"],
|
||||
["\u0300\u11a8", "0,1,2"],
|
||||
["\u0300\u0308\u11a8", "0,2,3"],
|
||||
["\u0300\uac00", "0,1,2"],
|
||||
["\u0300\u0308\uac00", "0,2,3"],
|
||||
["\u0300\uac01", "0,1,2"],
|
||||
["\u0300\u0308\uac01", "0,2,3"],
|
||||
["\u0300\u0915", "0,1,2"],
|
||||
["\u0300\u0308\u0915", "0,2,3"],
|
||||
["\u0300\u00a9", "0,1,2"],
|
||||
["\u0300\u0308\u00a9", "0,2,3"],
|
||||
["\u0300 ", "0,1,2"],
|
||||
["\u0300\u0308 ", "0,2,3"],
|
||||
["\u0300\u0378", "0,1,2"],
|
||||
["\u0300\u0308\u0378", "0,2,3"],
|
||||
["\u200c\r", "0,1,2"],
|
||||
["\u200c\u0308\r", "0,2,3"],
|
||||
["\u200c\n", "0,1,2"],
|
||||
["\u200c\u0308\n", "0,2,3"],
|
||||
["\u200c\u0000", "0,1,2"],
|
||||
["\u200c\u0308\u0000", "0,2,3"],
|
||||
["\u200c\u094d", "0,2"],
|
||||
["\u200c\u0308\u094d", "0,3"],
|
||||
["\u200c\u0300", "0,2"],
|
||||
["\u200c\u0308\u0300", "0,3"],
|
||||
["\u200c\u200c", "0,2"],
|
||||
["\u200c\u0308\u200c", "0,3"],
|
||||
["\u200c\u200d", "0,2"],
|
||||
["\u200c\u0308\u200d", "0,3"],
|
||||
["\u200c\ud83c\udde6", "0,1,3"],
|
||||
["\u200c\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u200c\u06dd", "0,1,2"],
|
||||
["\u200c\u0308\u06dd", "0,2,3"],
|
||||
["\u200c\u0903", "0,2"],
|
||||
["\u200c\u0308\u0903", "0,3"],
|
||||
["\u200c\u1100", "0,1,2"],
|
||||
["\u200c\u0308\u1100", "0,2,3"],
|
||||
["\u200c\u1160", "0,1,2"],
|
||||
["\u200c\u0308\u1160", "0,2,3"],
|
||||
["\u200c\u11a8", "0,1,2"],
|
||||
["\u200c\u0308\u11a8", "0,2,3"],
|
||||
["\u200c\uac00", "0,1,2"],
|
||||
["\u200c\u0308\uac00", "0,2,3"],
|
||||
["\u200c\uac01", "0,1,2"],
|
||||
["\u200c\u0308\uac01", "0,2,3"],
|
||||
["\u200c\u0915", "0,1,2"],
|
||||
["\u200c\u0308\u0915", "0,2,3"],
|
||||
["\u200c\u00a9", "0,1,2"],
|
||||
["\u200c\u0308\u00a9", "0,2,3"],
|
||||
["\u200c ", "0,1,2"],
|
||||
["\u200c\u0308 ", "0,2,3"],
|
||||
["\u200c\u0378", "0,1,2"],
|
||||
["\u200c\u0308\u0378", "0,2,3"],
|
||||
["\u200d\r", "0,1,2"],
|
||||
["\u200d\u0308\r", "0,2,3"],
|
||||
["\u200d\n", "0,1,2"],
|
||||
["\u200d\u0308\n", "0,2,3"],
|
||||
["\u200d\u0000", "0,1,2"],
|
||||
["\u200d\u0308\u0000", "0,2,3"],
|
||||
["\u200d\u094d", "0,2"],
|
||||
["\u200d\u0308\u094d", "0,3"],
|
||||
["\u200d\u0300", "0,2"],
|
||||
["\u200d\u0308\u0300", "0,3"],
|
||||
["\u200d\u200c", "0,2"],
|
||||
["\u200d\u0308\u200c", "0,3"],
|
||||
["\u200d\u200d", "0,2"],
|
||||
["\u200d\u0308\u200d", "0,3"],
|
||||
["\u200d\ud83c\udde6", "0,1,3"],
|
||||
["\u200d\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u200d\u06dd", "0,1,2"],
|
||||
["\u200d\u0308\u06dd", "0,2,3"],
|
||||
["\u200d\u0903", "0,2"],
|
||||
["\u200d\u0308\u0903", "0,3"],
|
||||
["\u200d\u1100", "0,1,2"],
|
||||
["\u200d\u0308\u1100", "0,2,3"],
|
||||
["\u200d\u1160", "0,1,2"],
|
||||
["\u200d\u0308\u1160", "0,2,3"],
|
||||
["\u200d\u11a8", "0,1,2"],
|
||||
["\u200d\u0308\u11a8", "0,2,3"],
|
||||
["\u200d\uac00", "0,1,2"],
|
||||
["\u200d\u0308\uac00", "0,2,3"],
|
||||
["\u200d\uac01", "0,1,2"],
|
||||
["\u200d\u0308\uac01", "0,2,3"],
|
||||
["\u200d\u0915", "0,1,2"],
|
||||
["\u200d\u0308\u0915", "0,2,3"],
|
||||
["\u200d\u00a9", "0,1,2"],
|
||||
["\u200d\u0308\u00a9", "0,2,3"],
|
||||
["\u200d ", "0,1,2"],
|
||||
["\u200d\u0308 ", "0,2,3"],
|
||||
["\u200d\u0378", "0,1,2"],
|
||||
["\u200d\u0308\u0378", "0,2,3"],
|
||||
["\ud83c\udde6\r", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\r", "0,3,4"],
|
||||
["\ud83c\udde6\n", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\n", "0,3,4"],
|
||||
["\ud83c\udde6\u0000", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\u0000", "0,3,4"],
|
||||
["\ud83c\udde6\u094d", "0,3"],
|
||||
["\ud83c\udde6\u0308\u094d", "0,4"],
|
||||
["\ud83c\udde6\u0300", "0,3"],
|
||||
["\ud83c\udde6\u0308\u0300", "0,4"],
|
||||
["\ud83c\udde6\u200c", "0,3"],
|
||||
["\ud83c\udde6\u0308\u200c", "0,4"],
|
||||
["\ud83c\udde6\u200d", "0,3"],
|
||||
["\ud83c\udde6\u0308\u200d", "0,4"],
|
||||
["\ud83c\udde6\ud83c\udde6", "0,4"],
|
||||
["\ud83c\udde6\u0308\ud83c\udde6", "0,3,5"],
|
||||
["\ud83c\udde6\u06dd", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\u06dd", "0,3,4"],
|
||||
["\ud83c\udde6\u0903", "0,3"],
|
||||
["\ud83c\udde6\u0308\u0903", "0,4"],
|
||||
["\ud83c\udde6\u1100", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\u1100", "0,3,4"],
|
||||
["\ud83c\udde6\u1160", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\u1160", "0,3,4"],
|
||||
["\ud83c\udde6\u11a8", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\u11a8", "0,3,4"],
|
||||
["\ud83c\udde6\uac00", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\uac00", "0,3,4"],
|
||||
["\ud83c\udde6\uac01", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\uac01", "0,3,4"],
|
||||
["\ud83c\udde6\u0915", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\u0915", "0,3,4"],
|
||||
["\ud83c\udde6\u00a9", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\u00a9", "0,3,4"],
|
||||
["\ud83c\udde6 ", "0,2,3"],
|
||||
["\ud83c\udde6\u0308 ", "0,3,4"],
|
||||
["\ud83c\udde6\u0378", "0,2,3"],
|
||||
["\ud83c\udde6\u0308\u0378", "0,3,4"],
|
||||
["\u06dd\r", "0,1,2"],
|
||||
["\u06dd\u0308\r", "0,2,3"],
|
||||
["\u06dd\n", "0,1,2"],
|
||||
["\u06dd\u0308\n", "0,2,3"],
|
||||
["\u06dd\u0000", "0,1,2"],
|
||||
["\u06dd\u0308\u0000", "0,2,3"],
|
||||
["\u06dd\u094d", "0,2"],
|
||||
["\u06dd\u0308\u094d", "0,3"],
|
||||
["\u06dd\u0300", "0,2"],
|
||||
["\u06dd\u0308\u0300", "0,3"],
|
||||
["\u06dd\u200c", "0,2"],
|
||||
["\u06dd\u0308\u200c", "0,3"],
|
||||
["\u06dd\u200d", "0,2"],
|
||||
["\u06dd\u0308\u200d", "0,3"],
|
||||
["\u06dd\ud83c\udde6", "0,3"],
|
||||
["\u06dd\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u06dd\u06dd", "0,2"],
|
||||
["\u06dd\u0308\u06dd", "0,2,3"],
|
||||
["\u06dd\u0903", "0,2"],
|
||||
["\u06dd\u0308\u0903", "0,3"],
|
||||
["\u06dd\u1100", "0,2"],
|
||||
["\u06dd\u0308\u1100", "0,2,3"],
|
||||
["\u06dd\u1160", "0,2"],
|
||||
["\u06dd\u0308\u1160", "0,2,3"],
|
||||
["\u06dd\u11a8", "0,2"],
|
||||
["\u06dd\u0308\u11a8", "0,2,3"],
|
||||
["\u06dd\uac00", "0,2"],
|
||||
["\u06dd\u0308\uac00", "0,2,3"],
|
||||
["\u06dd\uac01", "0,2"],
|
||||
["\u06dd\u0308\uac01", "0,2,3"],
|
||||
["\u06dd\u0915", "0,2"],
|
||||
["\u06dd\u0308\u0915", "0,2,3"],
|
||||
["\u06dd\u00a9", "0,2"],
|
||||
["\u06dd\u0308\u00a9", "0,2,3"],
|
||||
["\u06dd ", "0,2"],
|
||||
["\u06dd\u0308 ", "0,2,3"],
|
||||
["\u06dd\u0378", "0,2"],
|
||||
["\u06dd\u0308\u0378", "0,2,3"],
|
||||
["\u0903\r", "0,1,2"],
|
||||
["\u0903\u0308\r", "0,2,3"],
|
||||
["\u0903\n", "0,1,2"],
|
||||
["\u0903\u0308\n", "0,2,3"],
|
||||
["\u0903\u0000", "0,1,2"],
|
||||
["\u0903\u0308\u0000", "0,2,3"],
|
||||
["\u0903\u094d", "0,2"],
|
||||
["\u0903\u0308\u094d", "0,3"],
|
||||
["\u0903\u0300", "0,2"],
|
||||
["\u0903\u0308\u0300", "0,3"],
|
||||
["\u0903\u200c", "0,2"],
|
||||
["\u0903\u0308\u200c", "0,3"],
|
||||
["\u0903\u200d", "0,2"],
|
||||
["\u0903\u0308\u200d", "0,3"],
|
||||
["\u0903\ud83c\udde6", "0,1,3"],
|
||||
["\u0903\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u0903\u06dd", "0,1,2"],
|
||||
["\u0903\u0308\u06dd", "0,2,3"],
|
||||
["\u0903\u0903", "0,2"],
|
||||
["\u0903\u0308\u0903", "0,3"],
|
||||
["\u0903\u1100", "0,1,2"],
|
||||
["\u0903\u0308\u1100", "0,2,3"],
|
||||
["\u0903\u1160", "0,1,2"],
|
||||
["\u0903\u0308\u1160", "0,2,3"],
|
||||
["\u0903\u11a8", "0,1,2"],
|
||||
["\u0903\u0308\u11a8", "0,2,3"],
|
||||
["\u0903\uac00", "0,1,2"],
|
||||
["\u0903\u0308\uac00", "0,2,3"],
|
||||
["\u0903\uac01", "0,1,2"],
|
||||
["\u0903\u0308\uac01", "0,2,3"],
|
||||
["\u0903\u0915", "0,1,2"],
|
||||
["\u0903\u0308\u0915", "0,2,3"],
|
||||
["\u0903\u00a9", "0,1,2"],
|
||||
["\u0903\u0308\u00a9", "0,2,3"],
|
||||
["\u0903 ", "0,1,2"],
|
||||
["\u0903\u0308 ", "0,2,3"],
|
||||
["\u0903\u0378", "0,1,2"],
|
||||
["\u0903\u0308\u0378", "0,2,3"],
|
||||
["\u1100\r", "0,1,2"],
|
||||
["\u1100\u0308\r", "0,2,3"],
|
||||
["\u1100\n", "0,1,2"],
|
||||
["\u1100\u0308\n", "0,2,3"],
|
||||
["\u1100\u0000", "0,1,2"],
|
||||
["\u1100\u0308\u0000", "0,2,3"],
|
||||
["\u1100\u094d", "0,2"],
|
||||
["\u1100\u0308\u094d", "0,3"],
|
||||
["\u1100\u0300", "0,2"],
|
||||
["\u1100\u0308\u0300", "0,3"],
|
||||
["\u1100\u200c", "0,2"],
|
||||
["\u1100\u0308\u200c", "0,3"],
|
||||
["\u1100\u200d", "0,2"],
|
||||
["\u1100\u0308\u200d", "0,3"],
|
||||
["\u1100\ud83c\udde6", "0,1,3"],
|
||||
["\u1100\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u1100\u06dd", "0,1,2"],
|
||||
["\u1100\u0308\u06dd", "0,2,3"],
|
||||
["\u1100\u0903", "0,2"],
|
||||
["\u1100\u0308\u0903", "0,3"],
|
||||
["\u1100\u1100", "0,2"],
|
||||
["\u1100\u0308\u1100", "0,2,3"],
|
||||
["\u1100\u1160", "0,2"],
|
||||
["\u1100\u0308\u1160", "0,2,3"],
|
||||
["\u1100\u11a8", "0,1,2"],
|
||||
["\u1100\u0308\u11a8", "0,2,3"],
|
||||
["\u1100\uac00", "0,2"],
|
||||
["\u1100\u0308\uac00", "0,2,3"],
|
||||
["\u1100\uac01", "0,2"],
|
||||
["\u1100\u0308\uac01", "0,2,3"],
|
||||
["\u1100\u0915", "0,1,2"],
|
||||
["\u1100\u0308\u0915", "0,2,3"],
|
||||
["\u1100\u00a9", "0,1,2"],
|
||||
["\u1100\u0308\u00a9", "0,2,3"],
|
||||
["\u1100 ", "0,1,2"],
|
||||
["\u1100\u0308 ", "0,2,3"],
|
||||
["\u1100\u0378", "0,1,2"],
|
||||
["\u1100\u0308\u0378", "0,2,3"],
|
||||
["\u1160\r", "0,1,2"],
|
||||
["\u1160\u0308\r", "0,2,3"],
|
||||
["\u1160\n", "0,1,2"],
|
||||
["\u1160\u0308\n", "0,2,3"],
|
||||
["\u1160\u0000", "0,1,2"],
|
||||
["\u1160\u0308\u0000", "0,2,3"],
|
||||
["\u1160\u094d", "0,2"],
|
||||
["\u1160\u0308\u094d", "0,3"],
|
||||
["\u1160\u0300", "0,2"],
|
||||
["\u1160\u0308\u0300", "0,3"],
|
||||
["\u1160\u200c", "0,2"],
|
||||
["\u1160\u0308\u200c", "0,3"],
|
||||
["\u1160\u200d", "0,2"],
|
||||
["\u1160\u0308\u200d", "0,3"],
|
||||
["\u1160\ud83c\udde6", "0,1,3"],
|
||||
["\u1160\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u1160\u06dd", "0,1,2"],
|
||||
["\u1160\u0308\u06dd", "0,2,3"],
|
||||
["\u1160\u0903", "0,2"],
|
||||
["\u1160\u0308\u0903", "0,3"],
|
||||
["\u1160\u1100", "0,1,2"],
|
||||
["\u1160\u0308\u1100", "0,2,3"],
|
||||
["\u1160\u1160", "0,2"],
|
||||
["\u1160\u0308\u1160", "0,2,3"],
|
||||
["\u1160\u11a8", "0,2"],
|
||||
["\u1160\u0308\u11a8", "0,2,3"],
|
||||
["\u1160\uac00", "0,1,2"],
|
||||
["\u1160\u0308\uac00", "0,2,3"],
|
||||
["\u1160\uac01", "0,1,2"],
|
||||
["\u1160\u0308\uac01", "0,2,3"],
|
||||
["\u1160\u0915", "0,1,2"],
|
||||
["\u1160\u0308\u0915", "0,2,3"],
|
||||
["\u1160\u00a9", "0,1,2"],
|
||||
["\u1160\u0308\u00a9", "0,2,3"],
|
||||
["\u1160 ", "0,1,2"],
|
||||
["\u1160\u0308 ", "0,2,3"],
|
||||
["\u1160\u0378", "0,1,2"],
|
||||
["\u1160\u0308\u0378", "0,2,3"],
|
||||
["\u11a8\r", "0,1,2"],
|
||||
["\u11a8\u0308\r", "0,2,3"],
|
||||
["\u11a8\n", "0,1,2"],
|
||||
["\u11a8\u0308\n", "0,2,3"],
|
||||
["\u11a8\u0000", "0,1,2"],
|
||||
["\u11a8\u0308\u0000", "0,2,3"],
|
||||
["\u11a8\u094d", "0,2"],
|
||||
["\u11a8\u0308\u094d", "0,3"],
|
||||
["\u11a8\u0300", "0,2"],
|
||||
["\u11a8\u0308\u0300", "0,3"],
|
||||
["\u11a8\u200c", "0,2"],
|
||||
["\u11a8\u0308\u200c", "0,3"],
|
||||
["\u11a8\u200d", "0,2"],
|
||||
["\u11a8\u0308\u200d", "0,3"],
|
||||
["\u11a8\ud83c\udde6", "0,1,3"],
|
||||
["\u11a8\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u11a8\u06dd", "0,1,2"],
|
||||
["\u11a8\u0308\u06dd", "0,2,3"],
|
||||
["\u11a8\u0903", "0,2"],
|
||||
["\u11a8\u0308\u0903", "0,3"],
|
||||
["\u11a8\u1100", "0,1,2"],
|
||||
["\u11a8\u0308\u1100", "0,2,3"],
|
||||
["\u11a8\u1160", "0,1,2"],
|
||||
["\u11a8\u0308\u1160", "0,2,3"],
|
||||
["\u11a8\u11a8", "0,2"],
|
||||
["\u11a8\u0308\u11a8", "0,2,3"],
|
||||
["\u11a8\uac00", "0,1,2"],
|
||||
["\u11a8\u0308\uac00", "0,2,3"],
|
||||
["\u11a8\uac01", "0,1,2"],
|
||||
["\u11a8\u0308\uac01", "0,2,3"],
|
||||
["\u11a8\u0915", "0,1,2"],
|
||||
["\u11a8\u0308\u0915", "0,2,3"],
|
||||
["\u11a8\u00a9", "0,1,2"],
|
||||
["\u11a8\u0308\u00a9", "0,2,3"],
|
||||
["\u11a8 ", "0,1,2"],
|
||||
["\u11a8\u0308 ", "0,2,3"],
|
||||
["\u11a8\u0378", "0,1,2"],
|
||||
["\u11a8\u0308\u0378", "0,2,3"],
|
||||
["\uac00\r", "0,1,2"],
|
||||
["\uac00\u0308\r", "0,2,3"],
|
||||
["\uac00\n", "0,1,2"],
|
||||
["\uac00\u0308\n", "0,2,3"],
|
||||
["\uac00\u0000", "0,1,2"],
|
||||
["\uac00\u0308\u0000", "0,2,3"],
|
||||
["\uac00\u094d", "0,2"],
|
||||
["\uac00\u0308\u094d", "0,3"],
|
||||
["\uac00\u0300", "0,2"],
|
||||
["\uac00\u0308\u0300", "0,3"],
|
||||
["\uac00\u200c", "0,2"],
|
||||
["\uac00\u0308\u200c", "0,3"],
|
||||
["\uac00\u200d", "0,2"],
|
||||
["\uac00\u0308\u200d", "0,3"],
|
||||
["\uac00\ud83c\udde6", "0,1,3"],
|
||||
["\uac00\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\uac00\u06dd", "0,1,2"],
|
||||
["\uac00\u0308\u06dd", "0,2,3"],
|
||||
["\uac00\u0903", "0,2"],
|
||||
["\uac00\u0308\u0903", "0,3"],
|
||||
["\uac00\u1100", "0,1,2"],
|
||||
["\uac00\u0308\u1100", "0,2,3"],
|
||||
["\uac00\u1160", "0,2"],
|
||||
["\uac00\u0308\u1160", "0,2,3"],
|
||||
["\uac00\u11a8", "0,2"],
|
||||
["\uac00\u0308\u11a8", "0,2,3"],
|
||||
["\uac00\uac00", "0,1,2"],
|
||||
["\uac00\u0308\uac00", "0,2,3"],
|
||||
["\uac00\uac01", "0,1,2"],
|
||||
["\uac00\u0308\uac01", "0,2,3"],
|
||||
["\uac00\u0915", "0,1,2"],
|
||||
["\uac00\u0308\u0915", "0,2,3"],
|
||||
["\uac00\u00a9", "0,1,2"],
|
||||
["\uac00\u0308\u00a9", "0,2,3"],
|
||||
["\uac00 ", "0,1,2"],
|
||||
["\uac00\u0308 ", "0,2,3"],
|
||||
["\uac00\u0378", "0,1,2"],
|
||||
["\uac00\u0308\u0378", "0,2,3"],
|
||||
["\uac01\r", "0,1,2"],
|
||||
["\uac01\u0308\r", "0,2,3"],
|
||||
["\uac01\n", "0,1,2"],
|
||||
["\uac01\u0308\n", "0,2,3"],
|
||||
["\uac01\u0000", "0,1,2"],
|
||||
["\uac01\u0308\u0000", "0,2,3"],
|
||||
["\uac01\u094d", "0,2"],
|
||||
["\uac01\u0308\u094d", "0,3"],
|
||||
["\uac01\u0300", "0,2"],
|
||||
["\uac01\u0308\u0300", "0,3"],
|
||||
["\uac01\u200c", "0,2"],
|
||||
["\uac01\u0308\u200c", "0,3"],
|
||||
["\uac01\u200d", "0,2"],
|
||||
["\uac01\u0308\u200d", "0,3"],
|
||||
["\uac01\ud83c\udde6", "0,1,3"],
|
||||
["\uac01\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\uac01\u06dd", "0,1,2"],
|
||||
["\uac01\u0308\u06dd", "0,2,3"],
|
||||
["\uac01\u0903", "0,2"],
|
||||
["\uac01\u0308\u0903", "0,3"],
|
||||
["\uac01\u1100", "0,1,2"],
|
||||
["\uac01\u0308\u1100", "0,2,3"],
|
||||
["\uac01\u1160", "0,1,2"],
|
||||
["\uac01\u0308\u1160", "0,2,3"],
|
||||
["\uac01\u11a8", "0,2"],
|
||||
["\uac01\u0308\u11a8", "0,2,3"],
|
||||
["\uac01\uac00", "0,1,2"],
|
||||
["\uac01\u0308\uac00", "0,2,3"],
|
||||
["\uac01\uac01", "0,1,2"],
|
||||
["\uac01\u0308\uac01", "0,2,3"],
|
||||
["\uac01\u0915", "0,1,2"],
|
||||
["\uac01\u0308\u0915", "0,2,3"],
|
||||
["\uac01\u00a9", "0,1,2"],
|
||||
["\uac01\u0308\u00a9", "0,2,3"],
|
||||
["\uac01 ", "0,1,2"],
|
||||
["\uac01\u0308 ", "0,2,3"],
|
||||
["\uac01\u0378", "0,1,2"],
|
||||
["\uac01\u0308\u0378", "0,2,3"],
|
||||
["\u0915\r", "0,1,2"],
|
||||
["\u0915\u0308\r", "0,2,3"],
|
||||
["\u0915\n", "0,1,2"],
|
||||
["\u0915\u0308\n", "0,2,3"],
|
||||
["\u0915\u0000", "0,1,2"],
|
||||
["\u0915\u0308\u0000", "0,2,3"],
|
||||
["\u0915\u094d", "0,2"],
|
||||
["\u0915\u0308\u094d", "0,3"],
|
||||
["\u0915\u0300", "0,2"],
|
||||
["\u0915\u0308\u0300", "0,3"],
|
||||
["\u0915\u200c", "0,2"],
|
||||
["\u0915\u0308\u200c", "0,3"],
|
||||
["\u0915\u200d", "0,2"],
|
||||
["\u0915\u0308\u200d", "0,3"],
|
||||
["\u0915\ud83c\udde6", "0,1,3"],
|
||||
["\u0915\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u0915\u06dd", "0,1,2"],
|
||||
["\u0915\u0308\u06dd", "0,2,3"],
|
||||
["\u0915\u0903", "0,2"],
|
||||
["\u0915\u0308\u0903", "0,3"],
|
||||
["\u0915\u1100", "0,1,2"],
|
||||
["\u0915\u0308\u1100", "0,2,3"],
|
||||
["\u0915\u1160", "0,1,2"],
|
||||
["\u0915\u0308\u1160", "0,2,3"],
|
||||
["\u0915\u11a8", "0,1,2"],
|
||||
["\u0915\u0308\u11a8", "0,2,3"],
|
||||
["\u0915\uac00", "0,1,2"],
|
||||
["\u0915\u0308\uac00", "0,2,3"],
|
||||
["\u0915\uac01", "0,1,2"],
|
||||
["\u0915\u0308\uac01", "0,2,3"],
|
||||
["\u0915\u0915", "0,1,2"],
|
||||
["\u0915\u0308\u0915", "0,2,3"],
|
||||
["\u0915\u00a9", "0,1,2"],
|
||||
["\u0915\u0308\u00a9", "0,2,3"],
|
||||
["\u0915 ", "0,1,2"],
|
||||
["\u0915\u0308 ", "0,2,3"],
|
||||
["\u0915\u0378", "0,1,2"],
|
||||
["\u0915\u0308\u0378", "0,2,3"],
|
||||
["\u00a9\r", "0,1,2"],
|
||||
["\u00a9\u0308\r", "0,2,3"],
|
||||
["\u00a9\n", "0,1,2"],
|
||||
["\u00a9\u0308\n", "0,2,3"],
|
||||
["\u00a9\u0000", "0,1,2"],
|
||||
["\u00a9\u0308\u0000", "0,2,3"],
|
||||
["\u00a9\u094d", "0,2"],
|
||||
["\u00a9\u0308\u094d", "0,3"],
|
||||
["\u00a9\u0300", "0,2"],
|
||||
["\u00a9\u0308\u0300", "0,3"],
|
||||
["\u00a9\u200c", "0,2"],
|
||||
["\u00a9\u0308\u200c", "0,3"],
|
||||
["\u00a9\u200d", "0,2"],
|
||||
["\u00a9\u0308\u200d", "0,3"],
|
||||
["\u00a9\ud83c\udde6", "0,1,3"],
|
||||
["\u00a9\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u00a9\u06dd", "0,1,2"],
|
||||
["\u00a9\u0308\u06dd", "0,2,3"],
|
||||
["\u00a9\u0903", "0,2"],
|
||||
["\u00a9\u0308\u0903", "0,3"],
|
||||
["\u00a9\u1100", "0,1,2"],
|
||||
["\u00a9\u0308\u1100", "0,2,3"],
|
||||
["\u00a9\u1160", "0,1,2"],
|
||||
["\u00a9\u0308\u1160", "0,2,3"],
|
||||
["\u00a9\u11a8", "0,1,2"],
|
||||
["\u00a9\u0308\u11a8", "0,2,3"],
|
||||
["\u00a9\uac00", "0,1,2"],
|
||||
["\u00a9\u0308\uac00", "0,2,3"],
|
||||
["\u00a9\uac01", "0,1,2"],
|
||||
["\u00a9\u0308\uac01", "0,2,3"],
|
||||
["\u00a9\u0915", "0,1,2"],
|
||||
["\u00a9\u0308\u0915", "0,2,3"],
|
||||
["\u00a9\u00a9", "0,1,2"],
|
||||
["\u00a9\u0308\u00a9", "0,2,3"],
|
||||
["\u00a9 ", "0,1,2"],
|
||||
["\u00a9\u0308 ", "0,2,3"],
|
||||
["\u00a9\u0378", "0,1,2"],
|
||||
["\u00a9\u0308\u0378", "0,2,3"],
|
||||
[" \r", "0,1,2"],
|
||||
[" \u0308\r", "0,2,3"],
|
||||
[" \n", "0,1,2"],
|
||||
[" \u0308\n", "0,2,3"],
|
||||
[" \u0000", "0,1,2"],
|
||||
[" \u0308\u0000", "0,2,3"],
|
||||
[" \u094d", "0,2"],
|
||||
[" \u0308\u094d", "0,3"],
|
||||
[" \u0300", "0,2"],
|
||||
[" \u0308\u0300", "0,3"],
|
||||
[" \u200c", "0,2"],
|
||||
[" \u0308\u200c", "0,3"],
|
||||
[" \u200d", "0,2"],
|
||||
[" \u0308\u200d", "0,3"],
|
||||
[" \ud83c\udde6", "0,1,3"],
|
||||
[" \u0308\ud83c\udde6", "0,2,4"],
|
||||
[" \u06dd", "0,1,2"],
|
||||
[" \u0308\u06dd", "0,2,3"],
|
||||
[" \u0903", "0,2"],
|
||||
[" \u0308\u0903", "0,3"],
|
||||
[" \u1100", "0,1,2"],
|
||||
[" \u0308\u1100", "0,2,3"],
|
||||
[" \u1160", "0,1,2"],
|
||||
[" \u0308\u1160", "0,2,3"],
|
||||
[" \u11a8", "0,1,2"],
|
||||
[" \u0308\u11a8", "0,2,3"],
|
||||
[" \uac00", "0,1,2"],
|
||||
[" \u0308\uac00", "0,2,3"],
|
||||
[" \uac01", "0,1,2"],
|
||||
[" \u0308\uac01", "0,2,3"],
|
||||
[" \u0915", "0,1,2"],
|
||||
[" \u0308\u0915", "0,2,3"],
|
||||
[" \u00a9", "0,1,2"],
|
||||
[" \u0308\u00a9", "0,2,3"],
|
||||
[" ", "0,1,2"],
|
||||
[" \u0308 ", "0,2,3"],
|
||||
[" \u0378", "0,1,2"],
|
||||
[" \u0308\u0378", "0,2,3"],
|
||||
["\u0378\r", "0,1,2"],
|
||||
["\u0378\u0308\r", "0,2,3"],
|
||||
["\u0378\n", "0,1,2"],
|
||||
["\u0378\u0308\n", "0,2,3"],
|
||||
["\u0378\u0000", "0,1,2"],
|
||||
["\u0378\u0308\u0000", "0,2,3"],
|
||||
["\u0378\u094d", "0,2"],
|
||||
["\u0378\u0308\u094d", "0,3"],
|
||||
["\u0378\u0300", "0,2"],
|
||||
["\u0378\u0308\u0300", "0,3"],
|
||||
["\u0378\u200c", "0,2"],
|
||||
["\u0378\u0308\u200c", "0,3"],
|
||||
["\u0378\u200d", "0,2"],
|
||||
["\u0378\u0308\u200d", "0,3"],
|
||||
["\u0378\ud83c\udde6", "0,1,3"],
|
||||
["\u0378\u0308\ud83c\udde6", "0,2,4"],
|
||||
["\u0378\u06dd", "0,1,2"],
|
||||
["\u0378\u0308\u06dd", "0,2,3"],
|
||||
["\u0378\u0903", "0,2"],
|
||||
["\u0378\u0308\u0903", "0,3"],
|
||||
["\u0378\u1100", "0,1,2"],
|
||||
["\u0378\u0308\u1100", "0,2,3"],
|
||||
["\u0378\u1160", "0,1,2"],
|
||||
["\u0378\u0308\u1160", "0,2,3"],
|
||||
["\u0378\u11a8", "0,1,2"],
|
||||
["\u0378\u0308\u11a8", "0,2,3"],
|
||||
["\u0378\uac00", "0,1,2"],
|
||||
["\u0378\u0308\uac00", "0,2,3"],
|
||||
["\u0378\uac01", "0,1,2"],
|
||||
["\u0378\u0308\uac01", "0,2,3"],
|
||||
["\u0378\u0915", "0,1,2"],
|
||||
["\u0378\u0308\u0915", "0,2,3"],
|
||||
["\u0378\u00a9", "0,1,2"],
|
||||
["\u0378\u0308\u00a9", "0,2,3"],
|
||||
["\u0378 ", "0,1,2"],
|
||||
["\u0378\u0308 ", "0,2,3"],
|
||||
["\u0378\u0378", "0,1,2"],
|
||||
["\u0378\u0308\u0378", "0,2,3"],
|
||||
["\r\na\n\u0308", "0,2,3,4,5"],
|
||||
["a\u0308", "0,2"],
|
||||
[" \u200d\u0646", "0,2,3"],
|
||||
["\u0646\u200d ", "0,2,3"],
|
||||
["\u1100\u1100", "0,2"],
|
||||
["\uac00\u11a8\u1100", "0,2,3"],
|
||||
["\uac01\u11a8\u1100", "0,2,3"],
|
||||
["\ud83c\udde6\ud83c\udde7\ud83c\udde8b", "0,4,6,7"],
|
||||
["a\ud83c\udde6\ud83c\udde7\ud83c\udde8b", "0,1,5,7,8"],
|
||||
["a\ud83c\udde6\ud83c\udde7\u200d\ud83c\udde8b", "0,1,6,8,9"],
|
||||
["a\ud83c\udde6\u200d\ud83c\udde7\ud83c\udde8b", "0,1,4,8,9"],
|
||||
["a\ud83c\udde6\ud83c\udde7\ud83c\udde8\ud83c\udde9b", "0,1,5,9,10"],
|
||||
["a\u200d", "0,2"],
|
||||
["a\u0308b", "0,2,3"],
|
||||
["a\u0903b", "0,2,3"],
|
||||
["a\u0600b", "0,1,3"],
|
||||
["\ud83d\udc76\ud83c\udfff\ud83d\udc76", "0,4,6"],
|
||||
["a\ud83c\udfff\ud83d\udc76", "0,3,5"],
|
||||
["a\ud83c\udfff\ud83d\udc76\u200d\ud83d\uded1", "0,3,8"],
|
||||
["\ud83d\udc76\ud83c\udfff\u0308\u200d\ud83d\udc76\ud83c\udfff", "0,10"],
|
||||
["\ud83d\uded1\u200d\ud83d\uded1", "0,5"],
|
||||
["a\u200d\ud83d\uded1", "0,2,4"],
|
||||
["\u2701\u200d\u2701", "0,2,3"],
|
||||
["a\u200d\u2701", "0,2,3"],
|
||||
["\u0915\u0924", "0,1,2"],
|
||||
["\u0915\u094d\u0924", "0,3"],
|
||||
["\u0915\u094d\u094d\u0924", "0,4"],
|
||||
["\u0915\u094d\u200d\u0924", "0,4"],
|
||||
["\u0915\u093c\u200d\u094d\u0924", "0,5"],
|
||||
["\u0915\u093c\u094d\u200d\u0924", "0,5"],
|
||||
["\u0915\u094d\u0924\u094d\u092f", "0,5"],
|
||||
["\u0915\u094da", "0,2,3"],
|
||||
["a\u094d\u0924", "0,2,3"],
|
||||
["?\u094d\u0924", "0,2,3"],
|
||||
["\u0915\u094d\u094d\u0924", "0,4"],
|
||||
["\u0ab8\u0afb\u0acd\u0ab8\u0afb", "0,5"],
|
||||
["\u1019\u1039\u1018\u102c\u1037", "0,3,5"],
|
||||
["\u1004\u103a\u1039\u1011\u1039\u1011", "0,6"],
|
||||
["\u1b12\u1b01\u1b32\u1b44\u1b2f\u1b32\u1b44\u1b22\u1b44\u1b2c\u1b32\u1b44\u1b22\u1b38", "0,2,5,10,14"],
|
||||
["\u179f\u17d2\u178f\u17d2\u179a\u17b8", "0,6"],
|
||||
["\u1b26\u1b17\u1b44\u1b13", "0,1,4"],
|
||||
["\u1b27\u1b13\u1b44\u1b0b\u1b0b\u1b04", "0,1,4,6"],
|
||||
["\u1795\u17d2\u17af\u1798", "0,3,4"],
|
||||
["\u17a0\u17d2\u17ab\u1791\u17d0\u1799", "0,3,5,6"],
|
||||
];
|
||||
@@ -0,0 +1,13 @@
|
||||
import { cases } from "./cases.ts";
|
||||
|
||||
const segmenter = new Intl.Segmenter();
|
||||
let count = 0;
|
||||
for (const entry of cases) {
|
||||
const input = entry[0];
|
||||
let boundaries = "";
|
||||
for (const part of segmenter.segment(input)) boundaries += `${part.index},`;
|
||||
boundaries += input.length;
|
||||
if (boundaries !== entry[1]) throw new Error(`grapheme case ${count}: ${boundaries} != ${entry[1]}`);
|
||||
count++;
|
||||
}
|
||||
console.log("Unicode 17 grapheme cases", count);
|
||||
@@ -0,0 +1,24 @@
|
||||
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
||||
const input = "Ae\u0301👩🏽💻🇺🇸🇨🇦\r\nक्\u200dष각Z";
|
||||
const segments = segmenter.segment(input);
|
||||
for (const { segment, index, input: original } of segments) {
|
||||
console.log(JSON.stringify(segment), index, original === input);
|
||||
}
|
||||
let text = "";
|
||||
for (const part of segments) text += part.segment;
|
||||
console.log(text === input, Array.isArray(segments), segments === segments);
|
||||
console.log(segmenter.segment("") === segmenter.segment(""));
|
||||
for (const position of [-1, 0, 1, 2, 3, 4, 8, 9, 10, 11, input.length - 1, input.length, NaN, Infinity]) {
|
||||
const result = segments.containing(position);
|
||||
console.log(position, result === undefined ? "none" : `${result.index}:${result.segment}`);
|
||||
}
|
||||
let empty = 0;
|
||||
for (const part of segmenter.segment("")) empty += part.segment.length;
|
||||
console.log("empty", empty);
|
||||
let order = "";
|
||||
function undef(value: string): undefined {
|
||||
order += value;
|
||||
return undefined;
|
||||
}
|
||||
const another = new Intl.Segmenter(undef("a"), undef("b"));
|
||||
for (const part of another.segment("x")) console.log(part.segment, order);
|
||||
@@ -0,0 +1,59 @@
|
||||
let calls = 0;
|
||||
const source = { x: 1, y: 2 };
|
||||
function readSource() {
|
||||
calls++;
|
||||
return source;
|
||||
}
|
||||
function mutateSource() {
|
||||
source.x = 9;
|
||||
source.y = 10;
|
||||
return { z: 3 };
|
||||
}
|
||||
const copied = { ...readSource(), ...mutateSource() };
|
||||
console.log(calls, copied.x, copied.y, copied.z, source.x);
|
||||
|
||||
let order = "";
|
||||
function value(label: string, n: number) {
|
||||
order += label;
|
||||
return n;
|
||||
}
|
||||
function pair() {
|
||||
order += "B";
|
||||
return { x: 20, y: 30 };
|
||||
}
|
||||
// @ts-expect-error The overwrite is intentional; its earlier initializer must still run.
|
||||
const overwritten = { x: value("A", 1), ...pair(), y: value("C", 40) };
|
||||
console.log(order, overwritten.x, overwritten.y);
|
||||
|
||||
function empty() {
|
||||
order += "D";
|
||||
return {};
|
||||
}
|
||||
const discarded = { ...pair(), ...empty(), x: value("E", 50), y: value("F", 60) };
|
||||
console.log(order, discarded.x, discarded.y);
|
||||
|
||||
function optional(present: boolean): { x: number; y: number } | undefined {
|
||||
calls++;
|
||||
return present ? { x: 7, y: 8 } : undefined;
|
||||
}
|
||||
const absent = { ...source, ...optional(false) };
|
||||
const present = { ...source, ...optional(true) };
|
||||
console.log(calls, absent.x, absent.y, present.x, present.y);
|
||||
|
||||
function fail(): { x: number; y: number } {
|
||||
order += "G";
|
||||
throw new Error("spread failed");
|
||||
}
|
||||
try {
|
||||
const failed = { before: value("H", 0), ...fail(), after: value("I", 0) };
|
||||
console.log(failed.x);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) console.log(error.message, order);
|
||||
}
|
||||
|
||||
const dropped: PromiseRejectedResult = {
|
||||
...{ status: "rejected" as const },
|
||||
reason: console.log("reason evaluated"),
|
||||
status: "rejected",
|
||||
};
|
||||
console.log(dropped.status);
|
||||
@@ -0,0 +1,6 @@
|
||||
const getLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength")?.get;
|
||||
const buffer = new ArrayBuffer(12);
|
||||
if (getLength) console.log(typeof getLength, getLength.call(buffer));
|
||||
const empty = /** @type {unknown} */ ({});
|
||||
const none = Object.getOwnPropertyDescriptor(empty, "missing")?.get;
|
||||
console.log(none === undefined);
|
||||
@@ -0,0 +1,46 @@
|
||||
import { join, basename } from "node:path";
|
||||
import { platform } from "node:os";
|
||||
|
||||
const load = process.getBuiltinModule;
|
||||
console.log(typeof load, load === process.getBuiltinModule);
|
||||
const copy = load;
|
||||
console.log(copy === load, copy === process.getBuiltinModule);
|
||||
try { copy(null); } catch (error) { console.log(error.code, error.message); }
|
||||
function localLoader() {
|
||||
const local = process.getBuiltinModule;
|
||||
console.log(local === process.getBuiltinModule, local("missing"));
|
||||
try { local(42); } catch (error) { console.log(error.code, error.message); }
|
||||
var mutable = process.getBuiltinModule;
|
||||
console.log(mutable === local);
|
||||
try { mutable(); } catch (error) { console.log(error.code, error.message); }
|
||||
mutable = (id) => "custom:" + id;
|
||||
console.log(mutable("path"));
|
||||
}
|
||||
localLoader();
|
||||
const path = load("path");
|
||||
console.log(path === load("node:path"), path === load("path/posix"), path.win32 === load("path/win32"));
|
||||
console.log(path.posix === path, path.win32.posix === path, path.win32.win32 === path.win32);
|
||||
console.log(path.join("a", "b", "..", "c"), path.basename("/a/file.ts", ".ts"));
|
||||
console.log(path.normalize("/a/../b"), path.dirname("/a/file.ts"), path.extname("a.ts"));
|
||||
console.log(path.isAbsolute("/a"), path.relative("/a", "/a/b"));
|
||||
console.log(path.win32.join("a", "b"), path.win32.isAbsolute("C:\\a"));
|
||||
console.log(path.sep, path.delimiter, path.win32.sep, path.win32.delimiter);
|
||||
const stored = path.join;
|
||||
console.log(stored === path.join, stored === join, path.basename === basename, stored("a", "b"));
|
||||
const original = path.basename;
|
||||
path.basename = (name) => "changed:" + name;
|
||||
console.log(load("path").basename("x"), original("/a/x"));
|
||||
path.basename = original;
|
||||
const os = load("os");
|
||||
console.log(os.platform() === platform(), os === load("node:os"), typeof os.homedir(), typeof os.totalmem());
|
||||
const worker = load("node:worker_threads");
|
||||
console.log(worker === load("worker_threads"), worker.isMainThread, worker.isInternalThread, worker.threadId, worker.parentPort, worker.workerData);
|
||||
console.log(load("missing"), load("node:missing"), load("node:node:path"), load("node:node:test"), load("./path"), load("test"));
|
||||
for (const id of [undefined, null, 42, {}, [], true]) {
|
||||
try { load(id); } catch (error) { console.log(error.name, error.code, error.message); }
|
||||
}
|
||||
let effects = "";
|
||||
function extra() { effects += "e"; return 1; }
|
||||
try { process.getBuiltinModule(null, extra()); } catch (error) { console.log(error.code, effects); }
|
||||
function local(process) { return process.getBuiltinModule("custom"); }
|
||||
console.log(local({ getBuiltinModule(name) { return name + "!"; } }));
|
||||
@@ -0,0 +1,14 @@
|
||||
const stored = process.versions;
|
||||
console.log(typeof stored, stored !== null, stored === process.versions);
|
||||
console.log(typeof stored.node, typeof stored.openssl);
|
||||
console.log(stored.node === process.versions.node, stored.openssl === process.versions.openssl);
|
||||
console.log(stored.bun === undefined, stored.electron === undefined, stored.deno === undefined);
|
||||
console.log(typeof process.versions === "object" &&
|
||||
process.versions !== null && typeof process.versions.bun === "string");
|
||||
const descriptor = Object.getOwnPropertyDescriptor(stored, "node")!;
|
||||
console.log(descriptor.enumerable, descriptor.configurable, descriptor.writable);
|
||||
Object.defineProperty(stored, "node", { value: "native-probe" });
|
||||
console.log(stored.node, process.versions.node);
|
||||
Object.defineProperty(stored, "bun", { value: "probe", configurable: true });
|
||||
Object.defineProperty(stored, "electron", { value: "probe", configurable: true });
|
||||
console.log(stored.bun, process.versions.bun, process.versions?.electron);
|
||||
@@ -0,0 +1,29 @@
|
||||
let order = "";
|
||||
function pattern(value: string | undefined): string | undefined {
|
||||
order += "p";
|
||||
return value;
|
||||
}
|
||||
function flags(value: string | undefined): string | undefined {
|
||||
order += "f";
|
||||
return value;
|
||||
}
|
||||
// @ts-expect-error JavaScript permits an undefined pattern.
|
||||
const insensitive = new RegExp(pattern("a"), flags("i"));
|
||||
console.log(insensitive.test("A"), order);
|
||||
order = "";
|
||||
// @ts-expect-error JavaScript permits an undefined pattern.
|
||||
const empty = new RegExp(pattern(undefined), flags(undefined));
|
||||
console.log(empty.test("anything"), order);
|
||||
// @ts-expect-error JavaScript permits an undefined pattern.
|
||||
console.log(new RegExp(undefined, undefined).test(""));
|
||||
for (const onlyFirst of [true, false]) {
|
||||
const regex = new RegExp("a", onlyFirst ? undefined : "g");
|
||||
console.log("aba".replace(regex, "x"));
|
||||
}
|
||||
order = "";
|
||||
try {
|
||||
// @ts-expect-error JavaScript permits an undefined pattern.
|
||||
new RegExp(pattern("a"), flags("gg"));
|
||||
} catch (error) {
|
||||
if (error instanceof Error) console.log(error.name, order);
|
||||
}
|
||||
@@ -1,14 +1,6 @@
|
||||
// The DataView fences: `.buffer` escaping the one composed position that
|
||||
// consumes it and a constructor
|
||||
// over something that isn't a typed array's `.buffer`.
|
||||
|
||||
const buf = new Uint8Array(8);
|
||||
const view = new DataView(buf.buffer);
|
||||
|
||||
// '.buffer' only compiles inside new DataView(x.buffer, ...).
|
||||
const escaped = buf.buffer;
|
||||
|
||||
// The constructor wants a typed array's own '.buffer'.
|
||||
const ab = new ArrayBuffer(8);
|
||||
const direct = new DataView(ab);
|
||||
void view;
|
||||
// Stored ArrayBuffers and DataViews lower; Float16 accessors remain unsupported.
|
||||
const buffer = new ArrayBuffer(16);
|
||||
const view = new DataView(buffer);
|
||||
view.setFloat16(0, 1.5);
|
||||
console.log(view.getFloat16(0));
|
||||
// End of the diagnostic fixture.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
const n: number = 3;
|
||||
const t = n > 0 ? "pos" : "neg";
|
||||
const o = { ...{ a: 1 } };
|
||||
const b = "a" in { a: 1 };
|
||||
const m = typeof "ab".indexOf("b"); // a CALL operand — pure computations fold now
|
||||
const u = n === 3 ? 1 : 2;
|
||||
const s: string = "abc";
|
||||
const mixed = n === 3 && s;
|
||||
console.log(t, m, u, b, mixed);
|
||||
@@ -0,0 +1,5 @@
|
||||
// The native implementation covers default Unicode grapheme segmentation.
|
||||
new Intl.Segmenter("en-US");
|
||||
new Intl.Segmenter(undefined, { granularity: "word" });
|
||||
new Intl.Segmenter(undefined, { granularity: "sentence" });
|
||||
// End of the diagnostic fixture.
|
||||
@@ -1,42 +1,17 @@
|
||||
dataview.ts:9:7 - error SC2020: 'ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
dataview.ts:4:1 - error SC2020: 'DataView<ArrayBuffer>.setFloat16' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
8 | // '.buffer' only compiles inside new DataView(x.buffer, ...).
|
||||
9 | const escaped = buf.buffer;
|
||||
| ^~~~~~~
|
||||
10 |
|
||||
3 | const view = new DataView(buffer);
|
||||
4 | view.setFloat16(0, 1.5);
|
||||
| ^~~~~~~~~~~~~~~
|
||||
5 | console.log(view.getFloat16(0));
|
||||
|
||||
hint: no free-standing ArrayBuffer value exists — typed arrays own their storage (new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)
|
||||
hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations)
|
||||
|
||||
dataview.ts:9:17 - error SC1090: '.buffer' outside new DataView(x.buffer, ...) / Buffer.from(x.buffer, ...) (no free-standing ArrayBuffer value exists; subarray() answers an aliasing view directly) is not supported yet
|
||||
dataview.ts:5:13 - error SC2020: 'DataView<ArrayBuffer>.getFloat16' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
8 | // '.buffer' only compiles inside new DataView(x.buffer, ...).
|
||||
9 | const escaped = buf.buffer;
|
||||
| ^~~~~~~~~~
|
||||
10 |
|
||||
4 | view.setFloat16(0, 1.5);
|
||||
5 | console.log(view.getFloat16(0));
|
||||
| ^~~~~~~~~~~~~~~
|
||||
6 | // End of the diagnostic fixture.
|
||||
|
||||
dataview.ts:12:7 - error SC2020: 'ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
11 | // The constructor wants a typed array's own '.buffer'.
|
||||
12 | const ab = new ArrayBuffer(8);
|
||||
| ^~
|
||||
13 | const direct = new DataView(ab);
|
||||
|
||||
hint: no free-standing ArrayBuffer value exists — typed arrays own their storage (new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)
|
||||
|
||||
dataview.ts:12:12 - error SC2020: 'new ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
11 | // The constructor wants a typed array's own '.buffer'.
|
||||
12 | const ab = new ArrayBuffer(8);
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
13 | const direct = new DataView(ab);
|
||||
|
||||
hint: no free-standing ArrayBuffer value exists — typed arrays own their storage: allocate the view directly (new Uint8Array(n)), or erase a fresh buffer into one (new Uint8Array(new ArrayBuffer(n)), new DataView(new ArrayBuffer(n), ...))
|
||||
|
||||
dataview.ts:13:29 - error SC2020: 'new DataView over this buffer expression' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
12 | const ab = new ArrayBuffer(8);
|
||||
13 | const direct = new DataView(ab);
|
||||
| ^~
|
||||
14 | void view;
|
||||
|
||||
hint: views compile over a typed array's own storage — new DataView(x.buffer, byteOffset?, byteLength?) where x is a Uint8Array/Uint32Array/Float32Array/Float64Array/Buffer value — or a fresh buffer erased into the view: new DataView(new ArrayBuffer(n), ...); free-standing ArrayBuffers have no representation
|
||||
hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations)
|
||||
@@ -1,56 +1,20 @@
|
||||
es2025-fences.ts:9:7 - error SC2020: 'ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
8 | // Resizable ArrayBuffer + transfer (ES2024).
|
||||
9 | const ab = new ArrayBuffer(8, { maxByteLength: 16 });
|
||||
| ^~
|
||||
10 | ab.resize(16);
|
||||
|
||||
hint: no free-standing ArrayBuffer value exists — typed arrays own their storage (new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)
|
||||
|
||||
es2025-fences.ts:9:12 - error SC2020: 'new ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
es2025-fences.ts:9:12 - error SC2020: 'resizable ArrayBuffer construction' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
8 | // Resizable ArrayBuffer + transfer (ES2024).
|
||||
9 | const ab = new ArrayBuffer(8, { maxByteLength: 16 });
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
10 | ab.resize(16);
|
||||
|
||||
hint: no free-standing ArrayBuffer value exists — typed arrays own their storage: allocate the view directly (new Uint8Array(n)), or erase a fresh buffer into one (new Uint8Array(new ArrayBuffer(n)), new DataView(new ArrayBuffer(n), ...))
|
||||
hint: fixed-length ArrayBuffers accept a byte length; resizable storage is not supported yet
|
||||
|
||||
es2025-fences.ts:10:1 - error SC2020: 'ArrayBuffer.resize' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
9 | const ab = new ArrayBuffer(8, { maxByteLength: 16 });
|
||||
10 | ab.resize(16);
|
||||
| ^~~~~~~~~
|
||||
11 | const moved = ab.transfer();
|
||||
|
||||
hint: resize/transfer/maxByteLength need the buffer to exist as a runtime value, and no free-standing ArrayBuffer value does — typed arrays own fixed-length storage (new Uint8Array(n)); allocate a new view and copy instead
|
||||
|
||||
es2025-fences.ts:11:7 - error SC2020: 'ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
10 | ab.resize(16);
|
||||
11 | const moved = ab.transfer();
|
||||
| ^~~~~
|
||||
12 |
|
||||
|
||||
hint: no free-standing ArrayBuffer value exists — typed arrays own their storage (new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)
|
||||
|
||||
es2025-fences.ts:11:15 - error SC2020: 'ArrayBuffer.transfer' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
10 | ab.resize(16);
|
||||
11 | const moved = ab.transfer();
|
||||
| ^~~~~~~~~~~
|
||||
12 |
|
||||
|
||||
hint: resize/transfer/maxByteLength need the buffer to exist as a runtime value, and no free-standing ArrayBuffer value does — typed arrays own fixed-length storage (new Uint8Array(n)); allocate a new view and copy instead
|
||||
|
||||
es2025-fences.ts:15:27 - error SC2020: 'new Uint8Array over a resizable ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
es2025-fences.ts:15:27 - error SC2020: 'resizable ArrayBuffer construction' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
14 | // fixed-length new Uint8Array(new ArrayBuffer(8)) lowers).
|
||||
15 | const rz = new Uint8Array(new ArrayBuffer(8, { maxByteLength: 16 }));
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
16 |
|
||||
|
||||
hint: a maxByteLength options bag makes the buffer resizable, and resizing needs the buffer to exist as a runtime value — no free-standing ArrayBuffer value exists (the buffer here erases into the view): drop the options bag
|
||||
hint: fixed-length ArrayBuffers accept a byte length; resizable storage is not supported yet
|
||||
|
||||
es2025-fences.ts:18:7 - error SC2020: 'SharedArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
expressions.ts:3:13 - error SC1090: object spread of computed sources (the field copies re-read the source — bind it to a const first) are not supported yet
|
||||
|
||||
2 | const t = n > 0 ? "pos" : "neg";
|
||||
3 | const o = { ...{ a: 1 } };
|
||||
| ^~~~~~~~~~~
|
||||
4 | const b = "a" in { a: 1 };
|
||||
|
||||
expressions.ts:5:11 - error SC1090: typeof expressions on statically-typed values are not supported yet
|
||||
|
||||
4 | const b = "a" in { a: 1 };
|
||||
5 | const m = typeof "ab".indexOf("b"); // a CALL operand — pure computations fold now
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
6 | const u = n === 3 ? 1 : 2;
|
||||
@@ -0,0 +1,26 @@
|
||||
intl-segmenter.ts:2:1 - error SC2020: 'Intl.Segmenter locale negotiation' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
1 | // The native implementation covers default Unicode grapheme segmentation.
|
||||
2 | new Intl.Segmenter("en-US");
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
3 | new Intl.Segmenter(undefined, { granularity: "word" });
|
||||
|
||||
hint: omit the locale or pass undefined for default Unicode grapheme segmentation
|
||||
|
||||
intl-segmenter.ts:3:31 - error SC2020: 'Intl.Segmenter options' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
2 | new Intl.Segmenter("en-US");
|
||||
3 | new Intl.Segmenter(undefined, { granularity: "word" });
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~
|
||||
4 | new Intl.Segmenter(undefined, { granularity: "sentence" });
|
||||
|
||||
hint: the native segmenter supports default options and { granularity: "grapheme" }; word and sentence segmentation remain unsupported
|
||||
|
||||
intl-segmenter.ts:4:31 - error SC2020: 'Intl.Segmenter options' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
3 | new Intl.Segmenter(undefined, { granularity: "word" });
|
||||
4 | new Intl.Segmenter(undefined, { granularity: "sentence" });
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
5 | // End of the diagnostic fixture.
|
||||
|
||||
hint: the native segmenter supports default options and { granularity: "grapheme" }; word and sentence segmentation remain unsupported
|
||||
@@ -48,7 +48,7 @@ intl.ts:14:18 - error SC2020: 'NumberFormat.format' is part of the standard libr
|
||||
| ^~~~~~~~~~~~~~
|
||||
15 |
|
||||
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options; format with template literals, toFixed, and toString otherwise
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options, plus default Unicode grapheme segmentation with Intl.Segmenter; locale negotiation, word/sentence segmentation, and resolvedOptions remain unsupported
|
||||
|
||||
intl.ts:17:20 - error SC2020: 'Number.prototype.toLocaleString without a locale' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
@@ -84,7 +84,7 @@ intl.ts:22:14 - error SC2020: 'DateTimeFormat.format' is part of the standard li
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
23 | const dur = new Intl.DurationFormat("en-US").format({ hours: 1, minutes: 23 });
|
||||
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options; format with template literals, toFixed, and toString otherwise
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options, plus default Unicode grapheme segmentation with Intl.Segmenter; locale negotiation, word/sentence segmentation, and resolvedOptions remain unsupported
|
||||
|
||||
intl.ts:23:13 - error SC2020: 'DurationFormat.format' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
@@ -93,7 +93,7 @@ intl.ts:23:13 - error SC2020: 'DurationFormat.format' is part of the standard li
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
24 | const rule = new Intl.PluralRules("en-US").select(1);
|
||||
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options; format with template literals, toFixed, and toString otherwise
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options, plus default Unicode grapheme segmentation with Intl.Segmenter; locale negotiation, word/sentence segmentation, and resolvedOptions remain unsupported
|
||||
|
||||
intl.ts:24:14 - error SC2020: 'PluralRules.select' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
@@ -102,7 +102,7 @@ intl.ts:24:14 - error SC2020: 'PluralRules.select' is part of the standard libra
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
25 | const canon = Intl.getCanonicalLocales("en-us");
|
||||
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options; format with template literals, toFixed, and toString otherwise
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options, plus default Unicode grapheme segmentation with Intl.Segmenter; locale negotiation, word/sentence segmentation, and resolvedOptions remain unsupported
|
||||
|
||||
intl.ts:25:15 - error SC2020: 'Intl.getCanonicalLocales' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
@@ -111,4 +111,4 @@ intl.ts:25:15 - error SC2020: 'Intl.getCanonicalLocales' is part of the standard
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
26 |
|
||||
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options; format with template literals, toFixed, and toString otherwise
|
||||
hint: locale- and ICU-backed behavior lives outside the static runtime (the localeCompare stance: code-unit order, no collation/locale data) — what lowers: the composed new Intl.NumberFormat("en-US").format(x) and x.toLocaleString("en-US") with default options, plus default Unicode grapheme segmentation with Intl.Segmenter; locale negotiation, word/sentence segmentation, and resolvedOptions remain unsupported
|
||||
@@ -3,11 +3,4 @@ spread-fences.ts:14:21 - error SC1090: conditional spreads beyond `...(c ? { fie
|
||||
13 | const cond = true;
|
||||
14 | const s1: Shape = { ...(cond ? { x: 1, y: 2 } : { x: 3, y: 4 }) };
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
15 | interface YOnly {
|
||||
|
||||
spread-fences.ts:19:27 - error SC1090: object spread after explicit properties (spreads must come first — a later spread would overwrite them with JS semantics the desugar does not model) are not supported yet
|
||||
|
||||
18 | const yPart: YOnly = { y: 0 };
|
||||
19 | const s2: Shape = { x: 5, ...yPart };
|
||||
| ^~~~~~~~
|
||||
20 | // A spread field the target keeps (no later override) must match exactly —
|
||||
15 | interface YOnly {
|
||||
@@ -100,33 +100,6 @@ stdlib-fence.ts:27:12 - error SC2020: 'new WeakMap' is part of the standard libr
|
||||
|
||||
hint: weak collections observe garbage collection, which reference counting never exposes — a strong Map behaves identically in-language: use Map
|
||||
|
||||
stdlib-fence.ts:29:7 - error SC2020: 'ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
28 | const px = new Proxy({ a: 1 }, {});
|
||||
29 | const buf = new ArrayBuffer(8);
|
||||
| ^~~
|
||||
30 | const st = new Set(new Set([1, 2])); // string and array seeds lower; Set-valued seeds stay fenced
|
||||
|
||||
hint: no free-standing ArrayBuffer value exists — typed arrays own their storage (new Uint8Array(n) allocates; new Uint8Array(new ArrayBuffer(n)) erases the buffer into the view)
|
||||
|
||||
stdlib-fence.ts:29:13 - error SC2020: 'new ArrayBuffer' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
28 | const px = new Proxy({ a: 1 }, {});
|
||||
29 | const buf = new ArrayBuffer(8);
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
30 | const st = new Set(new Set([1, 2])); // string and array seeds lower; Set-valued seeds stay fenced
|
||||
|
||||
hint: no free-standing ArrayBuffer value exists — typed arrays own their storage: allocate the view directly (new Uint8Array(n)), or erase a fresh buffer into one (new Uint8Array(new ArrayBuffer(n)), new DataView(new ArrayBuffer(n), ...))
|
||||
|
||||
stdlib-fence.ts:30:12 - error SC2020: 'new Set(values)' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
29 | const buf = new ArrayBuffer(8);
|
||||
30 | const st = new Set(new Set([1, 2])); // string and array seeds lower; Set-valued seeds stay fenced
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
31 | // (new Error / TypeError / RangeError / SyntaxError now LOWER — the error
|
||||
|
||||
hint: construct the Set empty and add() each value — only a string, array, or fixed tuple of already-legal elements (numbers, strings, or identity references) seeds a Set
|
||||
|
||||
stdlib-fence.ts:34:7 - error SC2020: 'AggregateError' is part of the standard library types but has no scriptc lowering yet
|
||||
|
||||
33 | // and the unlowered members of lowered error objects.)
|
||||
|
||||
Reference in New Issue
Block a user