visaljs 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -4
- package/THIRD_PARTY_LICENSES +1216 -0
- package/cli.js +4461 -321
- package/node/include/js_node.h +57 -1
- package/node/include/js_uv.h +8 -1
- package/node/prelude/_http_agent.js +5 -0
- package/node/prelude/_http_server.js +7 -0
- package/node/prelude/_stream_duplex.js +4 -0
- package/node/prelude/_stream_passthrough.js +4 -0
- package/node/prelude/_stream_readable.js +4 -0
- package/node/prelude/_stream_transform.js +4 -0
- package/node/prelude/_stream_writable.js +4 -0
- package/node/prelude/assert.js +1334 -0
- package/node/prelude/assert_strict.js +12 -0
- package/node/prelude/async_hooks.js +1 -1
- package/node/prelude/buffer.js +43 -3
- package/node/prelude/child_process.js +1098 -0
- package/node/prelude/cluster.js +52 -0
- package/node/prelude/console.js +328 -0
- package/node/prelude/constants.js +10 -0
- package/node/prelude/crypto.js +1 -1
- package/node/prelude/diagnostics_channel.js +1 -1
- package/node/prelude/dns.js +8 -2
- package/node/prelude/domain.js +115 -0
- package/node/prelude/events.js +148 -16
- package/node/prelude/fs.js +1138 -151
- package/node/prelude/fs_promises.js +117 -11
- package/node/prelude/http.js +784 -301
- package/node/prelude/http2.js +1 -1
- package/node/prelude/https.js +159 -0
- package/node/prelude/inspector.js +27 -0
- package/node/prelude/inspector_promises.js +4 -0
- package/node/prelude/internal/async_context.js +1 -1
- package/node/prelude/internal/buffer_transcode.js +44 -0
- package/node/prelude/internal/comparisons.js +916 -0
- package/node/prelude/internal/compression_streams.js +153 -0
- package/node/prelude/internal/crypto/asym.js +27 -14
- package/node/prelude/internal/crypto/cipher.js +16 -5
- package/node/prelude/internal/crypto/diffiehellman.js +3 -2
- package/node/prelude/internal/crypto/hash.js +2 -1
- package/node/prelude/internal/crypto/kdf.js +14 -9
- package/node/prelude/internal/crypto/keys.js +63 -50
- package/node/prelude/internal/crypto/random.js +2 -1
- package/node/prelude/internal/crypto/util.js +4 -4
- package/node/prelude/internal/dotenv.js +98 -0
- package/node/prelude/internal/errors.js +21 -5
- package/node/prelude/internal/events_extras.js +113 -0
- package/node/prelude/internal/events_on.js +100 -0
- package/node/prelude/internal/features.js +72 -0
- package/node/prelude/internal/fetch.js +364 -0
- package/node/prelude/internal/form_data.js +376 -0
- package/node/prelude/internal/fs_bigint_stats.js +41 -0
- package/node/prelude/internal/fs_blob.js +19 -0
- package/node/prelude/internal/fs_cp.js +709 -0
- package/node/prelude/internal/fs_dir.js +166 -0
- package/node/prelude/internal/fs_filehandle.js +287 -0
- package/node/prelude/internal/fs_glob.js +296 -0
- package/node/prelude/internal/fs_statfs.js +42 -0
- package/node/prelude/internal/fs_stats.js +89 -0
- package/node/prelude/internal/fs_streams.js +541 -0
- package/node/prelude/internal/fs_utils.js +286 -0
- package/node/prelude/internal/fs_watch.js +580 -0
- package/node/prelude/internal/http_agent.js +114 -2
- package/node/prelude/internal/http_symbols.js +3 -0
- package/node/prelude/internal/mime.js +249 -0
- package/node/prelude/internal/net.js +1 -0
- package/node/prelude/internal/net_bound.js +123 -0
- package/node/prelude/internal/net_onread.js +73 -0
- package/node/prelude/internal/net_tos.js +54 -0
- package/node/prelude/internal/parse_args.js +288 -0
- package/node/prelude/internal/perf_histogram.js +435 -0
- package/node/prelude/internal/perf_observe.js +125 -0
- package/node/prelude/internal/performance_global.js +19 -0
- package/node/prelude/internal/process_events.js +49 -1
- package/node/prelude/internal/process_memory.js +14 -0
- package/node/prelude/internal/process_more.js +414 -0
- package/node/prelude/internal/process_signals.js +2 -1
- package/node/prelude/internal/process_stdin.js +52 -0
- package/node/prelude/internal/process_stdio.js +36 -0
- package/node/prelude/internal/querystring.js +0 -0
- package/node/prelude/internal/readline.js +338 -0
- package/node/prelude/internal/socketaddress.js +8 -4
- package/node/prelude/internal/source_map.js +122 -0
- package/node/prelude/internal/stream_compose.js +74 -0
- package/node/prelude/internal/stream_from.js +6 -0
- package/node/prelude/internal/stream_operators.js +23 -0
- package/node/prelude/internal/stream_pipeline.js +7 -0
- package/node/prelude/internal/stream_transform.js +10 -0
- package/node/prelude/internal/stream_web_adapters.js +143 -0
- package/node/prelude/internal/streams/add_abort_signal.js +58 -0
- package/node/prelude/internal/streams/compose.js +244 -0
- package/node/prelude/internal/streams/destroy.js +358 -0
- package/node/prelude/internal/streams/duplex.js +199 -0
- package/node/prelude/internal/streams/duplexify.js +378 -0
- package/node/prelude/internal/streams/end_of_stream.js +387 -0
- package/node/prelude/internal/streams/errors.js +216 -0
- package/node/prelude/internal/streams/from.js +211 -0
- package/node/prelude/internal/streams/legacy.js +120 -0
- package/node/prelude/internal/streams/operators.js +375 -0
- package/node/prelude/internal/streams/passthrough.js +45 -0
- package/node/prelude/internal/streams/pipeline.js +468 -0
- package/node/prelude/internal/streams/readable.js +1835 -0
- package/node/prelude/internal/streams/state.js +48 -0
- package/node/prelude/internal/streams/transform.js +203 -0
- package/node/prelude/internal/streams/utils.js +355 -0
- package/node/prelude/internal/streams/validators.js +108 -0
- package/node/prelude/internal/streams/writable.js +1160 -0
- package/node/prelude/internal/structured_clone.js +238 -0
- package/node/prelude/internal/system_errors.js +37 -0
- package/node/prelude/internal/test_runner/mock.js +431 -0
- package/node/prelude/internal/test_runner/reporters.js +404 -0
- package/node/prelude/internal/test_runner/test.js +1571 -0
- package/node/prelude/internal/timers.js +38 -7
- package/node/prelude/internal/timers_global.js +1 -1
- package/node/prelude/internal/tls/common.js +8 -2
- package/node/prelude/internal/tls/wrap.js +5 -16
- package/node/prelude/internal/tls/x509.js +1 -1
- package/node/prelude/internal/tty_read_stream.js +39 -0
- package/node/prelude/internal/tty_streams.js +3 -0
- package/node/prelude/internal/util_debuglog.js +68 -0
- package/node/prelude/internal/util_diff.js +63 -0
- package/node/prelude/internal/util_more.js +111 -0
- package/node/prelude/internal/util_styles.js +76 -0
- package/node/prelude/internal/zlib_engines.js +1 -1
- package/node/prelude/module.js +219 -8
- package/node/prelude/net.js +197 -49
- package/node/prelude/os.js +88 -11
- package/node/prelude/path.js +11 -7
- package/node/prelude/path_posix.js +1 -1
- package/node/prelude/path_win32.js +1 -1
- package/node/prelude/perf_hooks.js +151 -0
- package/node/prelude/process.js +36 -1
- package/node/prelude/punycode.js +188 -0
- package/node/prelude/querystring.js +1 -1
- package/node/prelude/readline.js +8 -0
- package/node/prelude/readline_promises.js +88 -0
- package/node/prelude/repl.js +38 -0
- package/node/prelude/sea.js +23 -0
- package/node/prelude/stream.js +70 -1332
- package/node/prelude/stream_consumers.js +34 -0
- package/node/prelude/stream_promises.js +1 -1
- package/node/prelude/stream_web.js +15 -2
- package/node/prelude/string_decoder.js +1 -1
- package/node/prelude/sys.js +7 -0
- package/node/prelude/test.js +56 -0
- package/node/prelude/test_reporters.js +269 -0
- package/node/prelude/timers.js +7 -84
- package/node/prelude/timers_promises.js +1 -1
- package/node/prelude/tls.js +2 -1
- package/node/prelude/trace_events.js +52 -0
- package/node/prelude/tty.js +10 -4
- package/node/prelude/url.js +88 -27
- package/node/prelude/util.js +121 -5
- package/node/prelude/util_types.js +4 -3
- package/node/prelude/v8.js +814 -0
- package/node/prelude/vm.js +86 -0
- package/node/prelude/wasi.js +10 -0
- package/node/prelude/worker_threads.js +56 -0
- package/node/prelude/zlib.js +58 -25
- package/node/src/host_brotli.c +59 -11
- package/node/src/host_fs.c +342 -11
- package/node/src/host_fswatch.c +170 -0
- package/node/src/host_http.c +292 -39
- package/node/src/host_loop.c +25 -2
- package/node/src/host_net.c +130 -16
- package/node/src/host_os.c +55 -1
- package/node/src/host_proc.c +291 -0
- package/node/src/host_process.c +488 -0
- package/node/src/host_sys.c +64 -2
- package/node/src/host_zlib.c +27 -7
- package/node/src/host_zstd.c +41 -6
- package/node/third_party/hdrhistogram/LICENSE +42 -0
- package/node/third_party/hdrhistogram/README.md +5 -0
- package/node/third_party/libuv/LICENSE +0 -0
- package/node/third_party/libuv/LICENSE-extra +36 -0
- package/node/third_party/libuv/include/uv/aix.h +0 -0
- package/node/third_party/libuv/include/uv/bsd.h +0 -0
- package/node/third_party/libuv/include/uv/darwin.h +0 -0
- package/node/third_party/libuv/include/uv/errno.h +0 -0
- package/node/third_party/libuv/include/uv/linux.h +0 -0
- package/node/third_party/libuv/include/uv/os390.h +0 -0
- package/node/third_party/libuv/include/uv/posix.h +0 -0
- package/node/third_party/libuv/include/uv/sunos.h +0 -0
- package/node/third_party/libuv/include/uv/threadpool.h +0 -0
- package/node/third_party/libuv/include/uv/tree.h +0 -0
- package/node/third_party/libuv/include/uv/unix.h +0 -0
- package/node/third_party/libuv/include/uv/version.h +0 -0
- package/node/third_party/libuv/include/uv/win.h +0 -0
- package/node/third_party/libuv/include/uv.h +0 -0
- package/node/third_party/libuv/src/fs-poll.c +0 -0
- package/node/third_party/libuv/src/heap-inl.h +0 -0
- package/node/third_party/libuv/src/idna.c +0 -0
- package/node/third_party/libuv/src/idna.h +0 -0
- package/node/third_party/libuv/src/inet.c +0 -0
- package/node/third_party/libuv/src/queue.h +0 -0
- package/node/third_party/libuv/src/random.c +0 -0
- package/node/third_party/libuv/src/strscpy.c +0 -0
- package/node/third_party/libuv/src/strscpy.h +0 -0
- package/node/third_party/libuv/src/strtok.c +0 -0
- package/node/third_party/libuv/src/strtok.h +0 -0
- package/node/third_party/libuv/src/thread-common.c +0 -0
- package/node/third_party/libuv/src/threadpool.c +0 -0
- package/node/third_party/libuv/src/timer.c +0 -0
- package/node/third_party/libuv/src/unix/async.c +0 -0
- package/node/third_party/libuv/src/unix/bsd-ifaddrs.c +0 -0
- package/node/third_party/libuv/src/unix/core.c +0 -0
- package/node/third_party/libuv/src/unix/darwin-proctitle.c +0 -0
- package/node/third_party/libuv/src/unix/darwin-stub.h +0 -0
- package/node/third_party/libuv/src/unix/darwin-syscalls.h +0 -0
- package/node/third_party/libuv/src/unix/darwin.c +0 -0
- package/node/third_party/libuv/src/unix/dl.c +0 -0
- package/node/third_party/libuv/src/unix/fs.c +0 -0
- package/node/third_party/libuv/src/unix/fsevents.c +0 -0
- package/node/third_party/libuv/src/unix/getaddrinfo.c +0 -0
- package/node/third_party/libuv/src/unix/getnameinfo.c +0 -0
- package/node/third_party/libuv/src/unix/internal.h +0 -0
- package/node/third_party/libuv/src/unix/kqueue.c +0 -0
- package/node/third_party/libuv/src/unix/linux.c +0 -0
- package/node/third_party/libuv/src/unix/loop-watcher.c +0 -0
- package/node/third_party/libuv/src/unix/loop.c +0 -0
- package/node/third_party/libuv/src/unix/pipe.c +0 -0
- package/node/third_party/libuv/src/unix/poll.c +0 -0
- package/node/third_party/libuv/src/unix/process.c +0 -0
- package/node/third_party/libuv/src/unix/procfs-exepath.c +0 -0
- package/node/third_party/libuv/src/unix/proctitle.c +0 -0
- package/node/third_party/libuv/src/unix/random-devurandom.c +0 -0
- package/node/third_party/libuv/src/unix/random-getentropy.c +0 -0
- package/node/third_party/libuv/src/unix/random-getrandom.c +0 -0
- package/node/third_party/libuv/src/unix/random-sysctl-linux.c +0 -0
- package/node/third_party/libuv/src/unix/signal.c +0 -0
- package/node/third_party/libuv/src/unix/stream.c +0 -0
- package/node/third_party/libuv/src/unix/tcp.c +0 -0
- package/node/third_party/libuv/src/unix/thread.c +0 -0
- package/node/third_party/libuv/src/unix/tty.c +0 -0
- package/node/third_party/libuv/src/unix/udp.c +0 -0
- package/node/third_party/libuv/src/uv-common.c +0 -0
- package/node/third_party/libuv/src/uv-common.h +0 -0
- package/node/third_party/libuv/src/uv-data-getter-setters.c +0 -0
- package/node/third_party/libuv/src/version.c +0 -0
- package/node/third_party/llhttp/LICENSE +0 -0
- package/node/third_party/llhttp/api.c +0 -0
- package/node/third_party/llhttp/http.c +0 -0
- package/node/third_party/llhttp/llhttp.c +0 -0
- package/node/third_party/llhttp/llhttp.h +0 -0
- package/node/third_party/nodejs/LICENSE +47 -0
- package/node/third_party/nodejs/README.md +5 -0
- package/node/third_party/parseargs/LICENSE +21 -0
- package/node/third_party/parseargs/README.md +5 -0
- package/node/third_party/punycode/LICENSE +20 -0
- package/node/third_party/punycode/README.md +5 -0
- package/node/third_party/zlib/LICENSE.chromium +27 -0
- package/package.json +1 -1
- package/prebuilt/darwin-arm64/boringssl-4a47438eaf7e73ba.a +0 -0
- package/prebuilt/darwin-arm64/brotli-7995bbdacc52e51c.a +0 -0
- package/prebuilt/darwin-arm64/uv-72ab666eae197cd8.a +0 -0
- package/prebuilt/darwin-arm64/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/darwin-arm64/zstd-015315ac7c784c73.a +0 -0
- package/prebuilt/darwin-x64/boringssl-4a47438eaf7e73ba.a +0 -0
- package/prebuilt/darwin-x64/brotli-7995bbdacc52e51c.a +0 -0
- package/prebuilt/darwin-x64/uv-72ab666eae197cd8.a +0 -0
- package/prebuilt/darwin-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/darwin-x64/zstd-015315ac7c784c73.a +0 -0
- package/prebuilt/linux-arm64/boringssl-4a47438eaf7e73ba.a +0 -0
- package/prebuilt/linux-arm64/brotli-65481ff838ce9def.a +0 -0
- package/prebuilt/linux-arm64/uv-f1353f50ff983f3c.a +0 -0
- package/prebuilt/linux-arm64/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/linux-arm64/zstd-015315ac7c784c73.a +0 -0
- package/prebuilt/linux-arm64-musl/boringssl-4a47438eaf7e73ba.a +0 -0
- package/prebuilt/linux-arm64-musl/brotli-65481ff838ce9def.a +0 -0
- package/prebuilt/linux-arm64-musl/uv-f1353f50ff983f3c.a +0 -0
- package/prebuilt/linux-arm64-musl/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/linux-arm64-musl/zstd-015315ac7c784c73.a +0 -0
- package/prebuilt/linux-x64/boringssl-4a47438eaf7e73ba.a +0 -0
- package/prebuilt/linux-x64/brotli-65481ff838ce9def.a +0 -0
- package/prebuilt/linux-x64/uv-f1353f50ff983f3c.a +0 -0
- package/prebuilt/linux-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/linux-x64/zstd-015315ac7c784c73.a +0 -0
- package/prebuilt/linux-x64-musl/boringssl-4a47438eaf7e73ba.a +0 -0
- package/prebuilt/linux-x64-musl/brotli-65481ff838ce9def.a +0 -0
- package/prebuilt/linux-x64-musl/uv-f1353f50ff983f3c.a +0 -0
- package/prebuilt/linux-x64-musl/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/linux-x64-musl/zstd-015315ac7c784c73.a +0 -0
- package/prebuilt/win32-x64/boringssl-ce573858472b7fc9.a +0 -0
- package/prebuilt/win32-x64/brotli-20d86a61f30baeb3.a +0 -0
- package/prebuilt/win32-x64/uv-b11bae65d7fced82.a +0 -0
- package/prebuilt/win32-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/win32-x64/zstd-015315ac7c784c73.a +0 -0
- package/runtime/include/js_atoms.gen.h +0 -0
- package/runtime/include/js_atoms.h +5 -1
- package/runtime/include/js_bigint.h +1 -1
- package/runtime/include/js_buffer.h +4 -4
- package/runtime/include/js_builtins.h +41 -3
- package/runtime/include/js_console.h +9 -4
- package/runtime/include/js_convert.h +1 -1
- package/runtime/include/js_core.def +5 -4
- package/runtime/include/js_crypto.h +1 -1
- package/runtime/include/js_error.h +1 -1
- package/runtime/include/js_exception.h +21 -1
- package/runtime/include/js_function.h +33 -9
- package/runtime/include/js_gc.h +172 -30
- package/runtime/include/js_generator.h +2 -2
- package/runtime/include/js_host.h +19 -1
- package/runtime/include/js_jobs.h +5 -5
- package/runtime/include/js_module.h +1 -1
- package/runtime/include/js_object.h +142 -15
- package/runtime/include/js_ops.h +107 -5
- package/runtime/include/js_promise.h +3 -3
- package/runtime/include/js_regexp.h +1 -1
- package/runtime/include/js_runtime.h +0 -0
- package/runtime/include/js_symbol.h +1 -1
- package/runtime/include/js_web.h +5 -1
- package/runtime/include/jscell.h +22 -15
- package/runtime/include/jscontext.h +82 -39
- package/runtime/include/jsnum.h +1 -1
- package/runtime/include/jsstring.h +19 -6
- package/runtime/include/jsvalue.h +7 -3
- package/runtime/src/arguments.c +2 -2
- package/runtime/src/array.c +4 -1
- package/runtime/src/arraybuffer.c +19 -7
- package/runtime/src/async_iter.c +4 -3
- package/runtime/src/atoms.c +38 -4
- package/runtime/src/base64.c +2 -2
- package/runtime/src/bigint.c +1 -1
- package/runtime/src/blob.c +22 -9
- package/runtime/src/boringssl_support.cc +1 -1
- package/runtime/src/buffer.c +299 -91
- package/runtime/src/builtin_table.c +1 -1
- package/runtime/src/builtins.c +30 -4
- package/runtime/src/builtins_util.h +0 -0
- package/runtime/src/collections.c +18 -3
- package/runtime/src/components.c +1 -1
- package/runtime/src/console.c +14 -7
- package/runtime/src/convert.c +0 -0
- package/runtime/src/core_all.c +1 -1
- package/runtime/src/crypto.c +1 -1
- package/runtime/src/crypto_asym.c +1 -1
- package/runtime/src/crypto_bn.c +1 -1
- package/runtime/src/crypto_cipher.c +10 -3
- package/runtime/src/crypto_hash.c +1 -1
- package/runtime/src/crypto_host.c +1 -1
- package/runtime/src/crypto_internal.h +1 -1
- package/runtime/src/crypto_kdf.c +1 -1
- package/runtime/src/crypto_key.c +14 -1
- package/runtime/src/crypto_pkey.c +1 -1
- package/runtime/src/crypto_subtle.c +142 -58
- package/runtime/src/crypto_tls.c +1 -1
- package/runtime/src/date.c +5 -2
- package/runtime/src/domexception.c +2 -2
- package/runtime/src/elements.c +56 -17
- package/runtime/src/elements.h +7 -2
- package/runtime/src/encoding.c +1 -1
- package/runtime/src/error.c +4 -4
- package/runtime/src/events.c +42 -14
- package/runtime/src/exception.c +1 -1
- package/runtime/src/fetch.c +241 -17
- package/runtime/src/function.c +31 -19
- package/runtime/src/gc.c +1720 -211
- package/runtime/src/gc_visit.h +87 -0
- package/runtime/src/generator.c +5 -3
- package/runtime/src/global.c +14 -6
- package/runtime/src/headers.c +10 -10
- package/runtime/src/inspect.c +76 -17
- package/runtime/src/internal.h +9 -6
- package/runtime/src/iterate.c +94 -2
- package/runtime/src/iterator.c +1 -1
- package/runtime/src/jobs.c +11 -5
- package/runtime/src/jsnum.c +2 -2
- package/runtime/src/json.c +1 -1
- package/runtime/src/math.c +9 -1
- package/runtime/src/module.c +3 -3
- package/runtime/src/number.c +0 -0
- package/runtime/src/object.c +107 -74
- package/runtime/src/ops.c +21 -3
- package/runtime/src/os.c +192 -1
- package/runtime/src/os.h +33 -2
- package/runtime/src/process.c +73 -8
- package/runtime/src/promise.c +4 -4
- package/runtime/src/proxy.c +1 -1
- package/runtime/src/reflect.c +1 -1
- package/runtime/src/regexp.c +700 -11
- package/runtime/src/regexp_anchor.h +1 -1
- package/runtime/src/regexp_message.h +1 -1
- package/runtime/src/shape.c +78 -20
- package/runtime/src/shape.h +0 -0
- package/runtime/src/streams.c +22 -8
- package/runtime/src/streams.h +0 -0
- package/runtime/src/string.c +64 -25
- package/runtime/src/string_builtins.c +7 -7
- package/runtime/src/symbol.c +2 -7
- package/runtime/src/test_host.c +3 -3
- package/runtime/src/tls_roots.gen.h +102 -620
- package/runtime/src/typedarray.c +8 -3
- package/runtime/src/tznames.gen.h +2 -1
- package/runtime/src/uri.c +1 -1
- package/runtime/src/url.c +42 -39
- package/runtime/src/weak.c +110 -36
- package/runtime/src/web.c +21 -3
- package/runtime/src/wrapper.c +0 -0
- package/runtime/src/writable.c +7 -6
- package/runtime/third_party/ada-idna/LICENSE-MIT +0 -0
- package/runtime/third_party/ada-idna/README.md +7 -7
- package/runtime/third_party/ada-idna/convert.mjs +89 -27
- package/runtime/third_party/ada-idna/idna.c +30 -31
- package/runtime/third_party/ada-idna/idna.h +0 -0
- package/runtime/third_party/ada-idna/idna_tables.h +2272 -1952
- package/runtime/third_party/boringssl/third_party/fiat/LICENSE +15 -0
- package/runtime/third_party/mozilla-ca/LICENSE +373 -0
- package/runtime/third_party/mozilla-ca/README.md +9 -0
- package/runtime/third_party/nodejs/LICENSE +47 -0
- package/runtime/third_party/nodejs/README.md +7 -0
- package/runtime/third_party/quickjs-dtoa/LICENSE +0 -0
- package/runtime/third_party/quickjs-dtoa/README.md +1 -1
- package/runtime/third_party/quickjs-dtoa/dtoa.c +0 -0
- package/runtime/third_party/quickjs-dtoa/dtoa.h +0 -0
- package/runtime/third_party/quickjs-dtoa/dtoa_compat.h +0 -0
- package/runtime/third_party/quickjs-regexp/LICENSE +0 -0
- package/runtime/third_party/quickjs-regexp/README.md +2 -2
- package/runtime/third_party/quickjs-regexp/cutils.c +0 -0
- package/runtime/third_party/quickjs-regexp/cutils.h +0 -0
- package/runtime/third_party/quickjs-regexp/libregexp-opcode.h +0 -0
- package/runtime/third_party/quickjs-regexp/libregexp.c +0 -0
- package/runtime/third_party/quickjs-regexp/libregexp.h +0 -0
- package/runtime/third_party/quickjs-regexp/libunicode-table.h +0 -0
- package/runtime/third_party/quickjs-regexp/libunicode.c +0 -0
- package/runtime/third_party/quickjs-regexp/libunicode.h +0 -0
- package/runtime/third_party/unicode/LICENSE +39 -0
- package/runtime/third_party/unicode/README.md +9 -0
- package/runtime/third_party/v8-ieee754/LICENSE +0 -0
- package/runtime/third_party/v8-ieee754/LICENSE.fdlibm +10 -0
- package/runtime/third_party/v8-ieee754/README.md +3 -2
- package/runtime/third_party/v8-ieee754/convert.py +0 -0
- package/runtime/third_party/v8-ieee754/ieee754.c +0 -0
- package/runtime/third_party/v8-ieee754/ieee754.h +0 -0
- package/runtime/tools/regexp_compile.c +2 -2
package/runtime/src/regexp.c
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* RegExp (ECMAScript §22.2), the regexp component
|
|
1
|
+
/* RegExp (ECMAScript §22.2), the regexp component.
|
|
2
2
|
*
|
|
3
3
|
* The engine is QuickJS's libregexp (third_party/quickjs-regexp): a pattern compiles to bytecode,
|
|
4
4
|
* and lre_exec runs it straight on a string's Latin-1 or UTF-16 characters. Literals arrive
|
|
@@ -33,14 +33,22 @@ typedef struct RegExpObject {
|
|
|
33
33
|
JSValue source; /* [[OriginalSource]]: a string */
|
|
34
34
|
const uint8_t *bytecode; /* [[RegExpMatcher]]; its flags are [[OriginalFlags]] */
|
|
35
35
|
bool owned; /* malloc'd (compiled at run time): the finalizer frees it */
|
|
36
|
+
bool one_class; /* the pattern is one character class: `units` (see find_class) */
|
|
37
|
+
bool negated; /* ...that matches every unit from U+0100 up */
|
|
38
|
+
uint32_t units[8]; /* its units below U+0100, a bit each */
|
|
39
|
+
bool analyzed; /* `prefilter` is set (see analyze) */
|
|
40
|
+
struct Prefilter *prefilter; /* where a match can start, or NULL: malloc'd */
|
|
36
41
|
} RegExpObject;
|
|
37
42
|
|
|
43
|
+
static void free_prefilter(RegExpObject *re);
|
|
44
|
+
|
|
38
45
|
static void regexp_visit(JSCell *c, JSTracer *trc) { js_trace_value(trc, ((RegExpObject *)c)->source); }
|
|
39
46
|
|
|
40
47
|
static void regexp_finalize(JSRuntime *rt, JSCell *c) {
|
|
41
48
|
(void)rt;
|
|
42
49
|
RegExpObject *re = (RegExpObject *)c;
|
|
43
50
|
if (re->owned) free((void *)re->bytecode);
|
|
51
|
+
free_prefilter(re);
|
|
44
52
|
}
|
|
45
53
|
|
|
46
54
|
static const JSClass regexp_class = { "RegExp", sizeof(RegExpObject), NULL, NULL, NULL, NULL, regexp_visit, regexp_finalize, NULL };
|
|
@@ -232,6 +240,9 @@ static JSValue regexp_new(JSContext *ctx, JSValue proto) {
|
|
|
232
240
|
re->source = js_empty_string();
|
|
233
241
|
re->bytecode = NULL;
|
|
234
242
|
re->owned = false;
|
|
243
|
+
re->one_class = false;
|
|
244
|
+
re->analyzed = false;
|
|
245
|
+
re->prefilter = NULL;
|
|
235
246
|
js_define_data(ctx, &re->obj, JS_ATOM(lastIndex), JS_UNDEFINED, JS_PROP_WRITABLE);
|
|
236
247
|
return js_object_value(&re->obj);
|
|
237
248
|
}
|
|
@@ -242,11 +253,398 @@ static JSValue regexp_alloc(JSContext *ctx, JSValue new_target) {
|
|
|
242
253
|
return js_is_exception(proto) ? proto : regexp_new(ctx, proto);
|
|
243
254
|
}
|
|
244
255
|
|
|
256
|
+
/* ---- One character class, matched without the engine ---------------------------------------
|
|
257
|
+
*
|
|
258
|
+
* A pattern that is a single character, or a single class of characters below U+0100, matches
|
|
259
|
+
* one code unit: builtin_exec scans for it in place of lre_exec (React's and escape-html's
|
|
260
|
+
* /["'&<>]/, a split on /[,;]/). Without i, u or v only: case folding and code points change what
|
|
261
|
+
* a character matches. The source is parsed conservatively: anything else keeps the engine. */
|
|
262
|
+
|
|
263
|
+
typedef struct {
|
|
264
|
+
JSStrView v;
|
|
265
|
+
uint32_t at;
|
|
266
|
+
} Source;
|
|
267
|
+
|
|
268
|
+
static int peek(const Source *s) { return s->at < s->v.length ? (int)js_view_at(s->v, s->at) : -1; }
|
|
269
|
+
|
|
270
|
+
static void add_range(uint32_t units[8], int lo, int hi) {
|
|
271
|
+
for (int c = lo; c <= hi; c++) units[c >> 5] |= 1u << (c & 31);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
enum { NOT_ONE = -1, DIGITS = -2, WORD = -3 };
|
|
275
|
+
|
|
276
|
+
static int hex_digit(int c) {
|
|
277
|
+
return c >= '0' && c <= '9' ? c - '0' : c >= 'a' && c <= 'f' ? c - 'a' + 10 : c >= 'A' && c <= 'F' ? c - 'A' + 10 : -1;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* The unit an escape stands for (after its backslash), DIGITS or WORD for \d and \w, or NOT_ONE. */
|
|
281
|
+
static int escape_unit(Source *s, bool in_class) {
|
|
282
|
+
int c = peek(s);
|
|
283
|
+
if (c < 0) return NOT_ONE;
|
|
284
|
+
s->at++;
|
|
285
|
+
switch (c) {
|
|
286
|
+
case 'n': return '\n';
|
|
287
|
+
case 'r': return '\r';
|
|
288
|
+
case 't': return '\t';
|
|
289
|
+
case 'f': return '\f';
|
|
290
|
+
case 'v': return '\v';
|
|
291
|
+
case 'd': return DIGITS;
|
|
292
|
+
case 'w': return WORD;
|
|
293
|
+
case 'b': return in_class ? '\b' : NOT_ONE;
|
|
294
|
+
case '0': {
|
|
295
|
+
int d = peek(s);
|
|
296
|
+
return d >= '0' && d <= '9' ? NOT_ONE : 0;
|
|
297
|
+
}
|
|
298
|
+
case 'x': {
|
|
299
|
+
int h = s->at + 1 < s->v.length ? hex_digit(peek(s)) : -1;
|
|
300
|
+
int l = h >= 0 ? hex_digit((int)js_view_at(s->v, s->at + 1)) : -1;
|
|
301
|
+
if (l < 0) return NOT_ONE;
|
|
302
|
+
s->at += 2;
|
|
303
|
+
return h * 16 + l;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return c < 0x80 && strchr("^$\\.*+?()[]{}|/-", c) ? c : NOT_ONE; /* a syntax character, escaped */
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* A class's unit (after reading it), or DIGITS / WORD (added to `units`), or NOT_ONE. */
|
|
310
|
+
static int class_unit(Source *s, uint32_t units[8]) {
|
|
311
|
+
int c = peek(s);
|
|
312
|
+
s->at++;
|
|
313
|
+
if (c != '\\') return c;
|
|
314
|
+
c = escape_unit(s, true);
|
|
315
|
+
if (c == DIGITS) add_range(units, '0', '9');
|
|
316
|
+
if (c == WORD) add_range(units, '0', '9'), add_range(units, 'A', 'Z'), add_range(units, 'a', 'z'), add_range(units, '_', '_');
|
|
317
|
+
return c;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
static void find_class(JSContext *ctx, RegExpObject *re) {
|
|
321
|
+
re->one_class = false;
|
|
322
|
+
if (lre_get_flags(re->bytecode) & (LRE_FLAG_IGNORECASE | LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS | LRE_FLAG_NAMED_GROUPS)) return;
|
|
323
|
+
Source s = { js_string_view(ctx, re->source), 0 };
|
|
324
|
+
uint32_t units[8] = { 0 };
|
|
325
|
+
bool negated = false;
|
|
326
|
+
int c = peek(&s);
|
|
327
|
+
if (c < 0) return;
|
|
328
|
+
s.at++;
|
|
329
|
+
if (c == '[') {
|
|
330
|
+
negated = peek(&s) == '^';
|
|
331
|
+
if (negated) s.at++;
|
|
332
|
+
for (;;) {
|
|
333
|
+
c = peek(&s);
|
|
334
|
+
if (c < 0) return;
|
|
335
|
+
if (c == ']') break;
|
|
336
|
+
int lo = class_unit(&s, units);
|
|
337
|
+
if (lo == NOT_ONE || lo >= 0x100) return;
|
|
338
|
+
if (peek(&s) == '-' && s.at + 1 < s.v.length && js_view_at(s.v, s.at + 1) != ']') {
|
|
339
|
+
s.at++;
|
|
340
|
+
int hi = class_unit(&s, units);
|
|
341
|
+
if (lo < 0 || hi < lo || hi >= 0x100) return; /* a class escape in a range: Annex B's */
|
|
342
|
+
add_range(units, lo, hi);
|
|
343
|
+
} else if (lo >= 0) {
|
|
344
|
+
add_range(units, lo, lo);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
s.at++;
|
|
348
|
+
if (negated)
|
|
349
|
+
for (int i = 0; i < 8; i++) units[i] = ~units[i];
|
|
350
|
+
} else if (c == '\\') {
|
|
351
|
+
Source t = { s.v, s.at - 1 }; /* from the backslash */
|
|
352
|
+
c = class_unit(&t, units);
|
|
353
|
+
s.at = t.at;
|
|
354
|
+
if (c == NOT_ONE || c == '\b' || c >= 0x100) return; /* \b outside a class: a word boundary */
|
|
355
|
+
if (c >= 0) add_range(units, c, c);
|
|
356
|
+
} else {
|
|
357
|
+
if (c >= 0x100 || (c < 0x80 && strchr("^$.*+?()[]{}|/", c))) return;
|
|
358
|
+
add_range(units, c, c);
|
|
359
|
+
}
|
|
360
|
+
if (s.at != s.v.length) return; /* more than the one class */
|
|
361
|
+
memcpy(re->units, units, sizeof units);
|
|
362
|
+
re->negated = negated;
|
|
363
|
+
re->one_class = true;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/* The first unit from `from` (only there, sticky) in the class: 1 with capture 0 set, as lre_exec. */
|
|
367
|
+
static int scan_class(const RegExpObject *re, const uint8_t *buf, int shift, uint32_t from, uint32_t length, bool sticky,
|
|
368
|
+
uint8_t **capture) {
|
|
369
|
+
uint32_t end = sticky && from < length ? from + 1 : length;
|
|
370
|
+
for (uint32_t i = from; i < end; i++) {
|
|
371
|
+
uint32_t c = shift ? ((const uint16_t *)buf)[i] : buf[i];
|
|
372
|
+
if (c < 0x100 ? (re->units[c >> 5] >> (c & 31)) & 1 : re->negated) {
|
|
373
|
+
capture[0] = (uint8_t *)buf + ((size_t)i << shift);
|
|
374
|
+
capture[1] = capture[0] + ((size_t)1 << shift);
|
|
375
|
+
return 1;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return 0;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/* ---- Where a match can start ----------------------------------------------------------------
|
|
382
|
+
*
|
|
383
|
+
* A pattern that isn't anchored or sticky compiles to a loop that tries every position in turn
|
|
384
|
+
* (split_goto_first +6; any; goto -11; save_start 0; ...): each failed attempt costs a trip
|
|
385
|
+
* through the interpreter. When the first units of a match can only be a few (a literal,
|
|
386
|
+
* /foo|bar/, /[cgt]gggtaaa/i, /\s+/), analyze reads them off the bytecode: the units each of
|
|
387
|
+
* the first PREFIX positions can hold, over every alternative. The search then looks for a
|
|
388
|
+
* position where they all fit (memchr for one first unit) and runs a copy of the bytecode whose
|
|
389
|
+
* loop is a goto there: one attempt each. The sets may hold more than can match, never less. */
|
|
390
|
+
|
|
391
|
+
#define PREFIX 4
|
|
392
|
+
|
|
393
|
+
typedef struct {
|
|
394
|
+
uint32_t units[8]; /* below U+0100, a bit each */
|
|
395
|
+
bool high; /* and any unit from U+0100 up */
|
|
396
|
+
} UnitSet;
|
|
397
|
+
|
|
398
|
+
typedef struct Prefilter {
|
|
399
|
+
int depth; /* the positions known: 1..PREFIX */
|
|
400
|
+
int single; /* at[0]'s one unit below U+0100, without high, else -1 */
|
|
401
|
+
UnitSet at[PREFIX];
|
|
402
|
+
uint8_t *once; /* the bytecode without its loop: an attempt at the start index only */
|
|
403
|
+
} Prefilter;
|
|
404
|
+
|
|
405
|
+
/* lre_canonicalize of the units below U+0100, without and with u/v: char_i and range_i compare
|
|
406
|
+
* the canonical unit. */
|
|
407
|
+
static uint32_t canonical[2][256];
|
|
408
|
+
|
|
409
|
+
static void free_prefilter(RegExpObject *re) {
|
|
410
|
+
if (re->prefilter) free(re->prefilter->once);
|
|
411
|
+
free(re->prefilter);
|
|
412
|
+
re->prefilter = NULL;
|
|
413
|
+
re->analyzed = false;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* The bytecode's size: header, code, then the group names (NUL-terminated, each with a trailer). */
|
|
417
|
+
static size_t bytecode_size(const uint8_t *bc) {
|
|
418
|
+
size_t size = 8 + (size_t)(bc[4] | bc[5] << 8 | bc[6] << 16 | (uint32_t)bc[7] << 24);
|
|
419
|
+
const char *names = lre_get_groupnames(bc);
|
|
420
|
+
if (names) {
|
|
421
|
+
for (int i = 1; i < lre_get_capture_count(bc); i++) names += strlen(names) + LRE_GROUP_NAME_TRAILER_LEN;
|
|
422
|
+
size = (size_t)((const uint8_t *)names - bc);
|
|
423
|
+
}
|
|
424
|
+
return size;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
static void add_unit(UnitSet *u, uint32_t c) {
|
|
428
|
+
if (c < 0x100) u->units[c >> 5] |= 1u << (c & 31);
|
|
429
|
+
else u->high = true;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
static bool has_unit_in(const UnitSet *u, uint32_t c) {
|
|
433
|
+
return c < 0x100 ? (u->units[c >> 5] >> (c & 31)) & 1 : u->high;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
static uint32_t get_u16_le(const uint8_t *p) { return p[0] | (uint32_t)p[1] << 8; }
|
|
437
|
+
static uint32_t get_u32_le(const uint8_t *p) { return p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24; }
|
|
438
|
+
|
|
439
|
+
typedef struct {
|
|
440
|
+
const uint8_t *code;
|
|
441
|
+
uint32_t length;
|
|
442
|
+
bool unicode;
|
|
443
|
+
int limit; /* every path consumes at least this many units first (PREFIX at most) */
|
|
444
|
+
int steps;
|
|
445
|
+
UnitSet at[PREFIX];
|
|
446
|
+
} Walk;
|
|
447
|
+
|
|
448
|
+
/* A class op (range, range32 and their _i forms) at p: the units below U+0100 it takes. */
|
|
449
|
+
static void add_ranges(Walk *w, UnitSet *u, const uint8_t *p, bool wide, bool fold) {
|
|
450
|
+
uint32_t n = get_u16_le(p + 1), size = wide ? 8 : 4;
|
|
451
|
+
for (uint32_t c = 0; c < 0x100; c++) {
|
|
452
|
+
uint32_t k = fold ? canonical[w->unicode][c] : c;
|
|
453
|
+
for (uint32_t i = 0; i < n; i++) {
|
|
454
|
+
const uint8_t *r = p + 3 + i * size;
|
|
455
|
+
uint32_t lo = wide ? get_u32_le(r) : get_u16_le(r), hi = wide ? get_u32_le(r + 4) : get_u16_le(r + 2);
|
|
456
|
+
if (k >= lo && k <= hi) {
|
|
457
|
+
add_unit(u, c);
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
const uint8_t *last = p + 3 + (n - 1) * size;
|
|
463
|
+
if (fold || wide || get_u16_le(last + 2) >= 0x100) u->high = true;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/* The units the paths from pc can take at positions d.. (until w->limit). */
|
|
467
|
+
static void walk(Walk *w, uint32_t pc, int d) {
|
|
468
|
+
while (d < w->limit) {
|
|
469
|
+
if (++w->steps > 1000 || pc >= w->length) {
|
|
470
|
+
w->limit = 0;
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const uint8_t *p = w->code + pc;
|
|
474
|
+
UnitSet *u = &w->at[d];
|
|
475
|
+
switch (p[0]) {
|
|
476
|
+
case JS_REOP_char:
|
|
477
|
+
case JS_REOP_char32: {
|
|
478
|
+
uint32_t c = p[0] == JS_REOP_char ? get_u16_le(p + 1) : get_u32_le(p + 1);
|
|
479
|
+
add_unit(u, c); /* from U+10000 up: a high surrogate first */
|
|
480
|
+
pc += p[0] == JS_REOP_char ? 3 : 5;
|
|
481
|
+
d++;
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
case JS_REOP_char_i:
|
|
485
|
+
case JS_REOP_char32_i: {
|
|
486
|
+
uint32_t c = p[0] == JS_REOP_char_i ? get_u16_le(p + 1) : get_u32_le(p + 1);
|
|
487
|
+
for (uint32_t k = 0; k < 0x100; k++)
|
|
488
|
+
if (canonical[w->unicode][k] == c) add_unit(u, k);
|
|
489
|
+
u->high = true; /* units from U+0100 up may fold to it too */
|
|
490
|
+
pc += p[0] == JS_REOP_char_i ? 3 : 5;
|
|
491
|
+
d++;
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
case JS_REOP_range:
|
|
495
|
+
case JS_REOP_range_i:
|
|
496
|
+
add_ranges(w, u, p, false, p[0] == JS_REOP_range_i);
|
|
497
|
+
pc += 3 + get_u16_le(p + 1) * 4;
|
|
498
|
+
d++;
|
|
499
|
+
break;
|
|
500
|
+
case JS_REOP_range32:
|
|
501
|
+
case JS_REOP_range32_i:
|
|
502
|
+
add_ranges(w, u, p, true, p[0] == JS_REOP_range32_i);
|
|
503
|
+
pc += 3 + get_u16_le(p + 1) * 8;
|
|
504
|
+
d++;
|
|
505
|
+
break;
|
|
506
|
+
case JS_REOP_space:
|
|
507
|
+
case JS_REOP_not_space:
|
|
508
|
+
for (uint32_t k = 0; k < 0x100; k++)
|
|
509
|
+
if (lre_is_space(k) == (p[0] == JS_REOP_space)) add_unit(u, k);
|
|
510
|
+
u->high = true;
|
|
511
|
+
pc++;
|
|
512
|
+
d++;
|
|
513
|
+
break;
|
|
514
|
+
case JS_REOP_dot:
|
|
515
|
+
for (uint32_t k = 0; k < 0x100; k++)
|
|
516
|
+
if (k != '\n' && k != '\r') add_unit(u, k);
|
|
517
|
+
u->high = true;
|
|
518
|
+
pc++;
|
|
519
|
+
d++;
|
|
520
|
+
break;
|
|
521
|
+
case JS_REOP_goto:
|
|
522
|
+
pc += 5 + get_u32_le(p + 1);
|
|
523
|
+
break;
|
|
524
|
+
case JS_REOP_split_goto_first:
|
|
525
|
+
case JS_REOP_split_next_first:
|
|
526
|
+
walk(w, pc + 5, d);
|
|
527
|
+
walk(w, pc + 5 + get_u32_le(p + 1), d);
|
|
528
|
+
return;
|
|
529
|
+
case JS_REOP_save_start:
|
|
530
|
+
case JS_REOP_save_end:
|
|
531
|
+
pc += 2;
|
|
532
|
+
break;
|
|
533
|
+
case JS_REOP_save_reset:
|
|
534
|
+
pc += 3;
|
|
535
|
+
break;
|
|
536
|
+
case JS_REOP_line_start:
|
|
537
|
+
case JS_REOP_line_start_m:
|
|
538
|
+
case JS_REOP_line_end:
|
|
539
|
+
case JS_REOP_line_end_m:
|
|
540
|
+
case JS_REOP_word_boundary:
|
|
541
|
+
case JS_REOP_word_boundary_i:
|
|
542
|
+
case JS_REOP_not_word_boundary:
|
|
543
|
+
case JS_REOP_not_word_boundary_i:
|
|
544
|
+
pc++; /* zero-width: the next op's unit is at the same position */
|
|
545
|
+
break;
|
|
546
|
+
default: /* any, match, loops, lookarounds, back references: anything from here on */
|
|
547
|
+
w->limit = d;
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/* The share of printable ASCII the sets let through, roughly: a filter that lets most
|
|
554
|
+
* positions through only adds a call per position. */
|
|
555
|
+
static double selectivity(const Prefilter *f) {
|
|
556
|
+
double share = 1;
|
|
557
|
+
for (int k = 0; k < f->depth; k++) {
|
|
558
|
+
int n = 0;
|
|
559
|
+
for (uint32_t c = 0x20; c < 0x7F; c++) n += has_unit_in(&f->at[k], c);
|
|
560
|
+
share *= n / 95.0;
|
|
561
|
+
}
|
|
562
|
+
return share;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/* The prefilter of re's bytecode, made at its first long search; NULL when it has none. */
|
|
566
|
+
static Prefilter *analyze(RegExpObject *re) {
|
|
567
|
+
re->analyzed = true;
|
|
568
|
+
const uint8_t *bc = re->bytecode;
|
|
569
|
+
uint32_t code_length = (uint32_t)(bytecode_size(bc) - JS_RE_HEADER_LEN);
|
|
570
|
+
const uint8_t *p = bc + JS_RE_HEADER_LEN;
|
|
571
|
+
/* the search loop, as js_regexp_anchor reads it (an anchored pattern has a goto instead) */
|
|
572
|
+
if (code_length < 13 || p[0] != JS_REOP_split_goto_first || p[5] != JS_REOP_any || p[6] != JS_REOP_goto || p[11] != JS_REOP_save_start)
|
|
573
|
+
return NULL;
|
|
574
|
+
Walk w = { .code = p, .length = code_length, .unicode = (lre_get_flags(bc) & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0,
|
|
575
|
+
.limit = PREFIX };
|
|
576
|
+
walk(&w, 11, 0);
|
|
577
|
+
if (w.limit == 0) return NULL;
|
|
578
|
+
Prefilter *f = calloc(1, sizeof *f);
|
|
579
|
+
if (!f) js_fatal("out of memory analyzing a regular expression");
|
|
580
|
+
f->depth = w.limit;
|
|
581
|
+
memcpy(f->at, w.at, sizeof f->at);
|
|
582
|
+
if (selectivity(f) > 0.2) {
|
|
583
|
+
free(f);
|
|
584
|
+
return NULL;
|
|
585
|
+
}
|
|
586
|
+
f->single = -1;
|
|
587
|
+
if (!f->at[0].high) {
|
|
588
|
+
int n = 0;
|
|
589
|
+
for (int c = 0; c < 0x100; c++)
|
|
590
|
+
if (has_unit_in(&f->at[0], (uint32_t)c)) f->single = n++ ? -1 : c;
|
|
591
|
+
if (n != 1) f->single = -1;
|
|
592
|
+
}
|
|
593
|
+
size_t size = bytecode_size(bc);
|
|
594
|
+
f->once = malloc(size);
|
|
595
|
+
if (!f->once) js_fatal("out of memory analyzing a regular expression");
|
|
596
|
+
memcpy(f->once, bc, size);
|
|
597
|
+
f->once[JS_RE_HEADER_LEN] = JS_REOP_goto; /* same offset: straight to save_start */
|
|
598
|
+
return f;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/* The first position from `from` where the prefilter's units all fit, or UINT32_MAX. */
|
|
602
|
+
static uint32_t next_start(const Prefilter *f, const uint8_t *buf, int shift, uint32_t from, uint32_t length) {
|
|
603
|
+
if (length < (uint32_t)f->depth) return UINT32_MAX;
|
|
604
|
+
uint32_t last = length - (uint32_t)f->depth; /* a match starts no later */
|
|
605
|
+
for (uint32_t i = from; i <= last; i++) {
|
|
606
|
+
if (!shift && f->single >= 0) {
|
|
607
|
+
const uint8_t *hit = memchr(buf + i, f->single, last - i + 1);
|
|
608
|
+
if (!hit) return UINT32_MAX;
|
|
609
|
+
i = (uint32_t)(hit - buf);
|
|
610
|
+
}
|
|
611
|
+
int k = 0;
|
|
612
|
+
for (; k < f->depth; k++) {
|
|
613
|
+
uint32_t c = shift ? ((const uint16_t *)buf)[i + k] : buf[i + k];
|
|
614
|
+
if (!has_unit_in(&f->at[k], c)) break;
|
|
615
|
+
}
|
|
616
|
+
if (k == f->depth) return i;
|
|
617
|
+
}
|
|
618
|
+
return UINT32_MAX;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/* Runs re's matcher on the string from `from` (at most its length): 1 with capture[] set (from
|
|
622
|
+
* lre_exec's alloc count), 0 for no match, or LRE_RET_* < 0. */
|
|
623
|
+
static int run(JSContext *ctx, RegExpObject *re, JSStrView v, uint32_t from, uint8_t **capture) {
|
|
624
|
+
const uint8_t *buf = v.chars;
|
|
625
|
+
int shift = v.latin1 ? 0 : 1;
|
|
626
|
+
int flags = lre_get_flags(re->bytecode);
|
|
627
|
+
if (re->one_class) return scan_class(re, buf, shift, from, v.length, (flags & LRE_FLAG_STICKY) != 0, capture);
|
|
628
|
+
/* surrogate pairs: lre_exec steps over them as code points, the scan doesn't */
|
|
629
|
+
bool pairs = !v.latin1 && (flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS));
|
|
630
|
+
if (!re->analyzed && v.length - from >= 64 && !pairs) re->prefilter = analyze(re);
|
|
631
|
+
const Prefilter *f = re->prefilter;
|
|
632
|
+
if (!f || pairs) return lre_exec(capture, re->bytecode, buf, (int)from, (int)v.length, shift, ctx);
|
|
633
|
+
for (uint32_t i = from;; i++) {
|
|
634
|
+
i = next_start(f, buf, shift, i, v.length);
|
|
635
|
+
if (i == UINT32_MAX) return 0;
|
|
636
|
+
int rc = lre_exec(capture, f->once, buf, (int)i, (int)v.length, shift, ctx);
|
|
637
|
+
if (rc != 0) return rc;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
245
641
|
static void set_matcher(JSContext *ctx, RegExpObject *re, JSValue source, const uint8_t *bytecode, bool owned) {
|
|
246
642
|
if (re->owned) free((void *)re->bytecode);
|
|
643
|
+
free_prefilter(re);
|
|
247
644
|
js_store(ctx, &re->obj.cell, &re->source, source);
|
|
248
645
|
re->bytecode = bytecode;
|
|
249
646
|
re->owned = owned;
|
|
647
|
+
find_class(ctx, re);
|
|
250
648
|
}
|
|
251
649
|
|
|
252
650
|
/* RegExpInitialize (§22.2.3.3) */
|
|
@@ -277,13 +675,7 @@ static void copy_matcher(JSContext *ctx, RegExpObject *to, const RegExpObject *f
|
|
|
277
675
|
return;
|
|
278
676
|
}
|
|
279
677
|
const uint8_t *bc = from->bytecode;
|
|
280
|
-
|
|
281
|
-
size_t size = 8 + (size_t)(bc[4] | bc[5] << 8 | bc[6] << 16 | (uint32_t)bc[7] << 24);
|
|
282
|
-
const char *names = lre_get_groupnames(bc);
|
|
283
|
-
if (names) {
|
|
284
|
-
for (int i = 1; i < lre_get_capture_count(bc); i++) names += strlen(names) + LRE_GROUP_NAME_TRAILER_LEN;
|
|
285
|
-
size = (size_t)((const uint8_t *)names - bc);
|
|
286
|
-
}
|
|
678
|
+
size_t size = bytecode_size(bc);
|
|
287
679
|
uint8_t *copy = malloc(size);
|
|
288
680
|
if (!copy) js_fatal("out of memory copying a regular expression");
|
|
289
681
|
memcpy(copy, bc, size);
|
|
@@ -440,6 +832,8 @@ FLAG_GETTER(regexp_unicode, LRE_FLAG_UNICODE, "unicode")
|
|
|
440
832
|
FLAG_GETTER(regexp_unicode_sets, LRE_FLAG_UNICODE_SETS, "unicodeSets")
|
|
441
833
|
FLAG_GETTER(regexp_sticky, LRE_FLAG_STICKY, "sticky")
|
|
442
834
|
|
|
835
|
+
static const char *const flag_names[] = { "hasIndices", "global", "ignoreCase", "multiline", "dotAll", "unicode", "unicodeSets", "sticky" };
|
|
836
|
+
|
|
443
837
|
/* get RegExp.prototype.flags (§22.2.6.4): from the flag getters, observably. */
|
|
444
838
|
BUILTIN(regexp_flags) {
|
|
445
839
|
UNUSED_ARGS;
|
|
@@ -448,11 +842,10 @@ BUILTIN(regexp_flags) {
|
|
|
448
842
|
js_describe_value(ctx, this_val, what, sizeof what);
|
|
449
843
|
return js_throw_type_error(ctx, "RegExp.prototype.flags getter called on non-object %s", what);
|
|
450
844
|
}
|
|
451
|
-
static const char *const names[] = { "hasIndices", "global", "ignoreCase", "multiline", "dotAll", "unicode", "unicodeSets", "sticky" };
|
|
452
845
|
char out[9];
|
|
453
846
|
size_t n = 0;
|
|
454
847
|
for (int i = 0; i < 8; i++) {
|
|
455
|
-
JSValue v = js_get_value(ctx, this_val, js_atom_from_cstr(ctx,
|
|
848
|
+
JSValue v = js_get_value(ctx, this_val, js_atom_from_cstr(ctx, flag_names[i]));
|
|
456
849
|
if (js_is_exception(v)) return v;
|
|
457
850
|
if (js_truthy(v)) out[n++] = flag_chars[i];
|
|
458
851
|
}
|
|
@@ -544,7 +937,7 @@ static JSValue builtin_exec(JSContext *ctx, JSValue rx, JSValue s) {
|
|
|
544
937
|
if (!capture) js_fatal("out of memory matching a regular expression");
|
|
545
938
|
int shift = v.latin1 ? 0 : 1;
|
|
546
939
|
const uint8_t *buf = v.chars;
|
|
547
|
-
int rc = last_index > v.length ? 2 :
|
|
940
|
+
int rc = last_index > v.length ? 2 : run(ctx, re, v, (uint32_t)last_index, capture);
|
|
548
941
|
JSValue result = JS_NULL;
|
|
549
942
|
if (rc < 0) {
|
|
550
943
|
result = throw_exec_failure(ctx, rc);
|
|
@@ -644,11 +1037,139 @@ BUILTIN(regexp_proto_exec) {
|
|
|
644
1037
|
return js_is_exception(s) ? s : builtin_exec(ctx, this_val, s);
|
|
645
1038
|
}
|
|
646
1039
|
|
|
1040
|
+
/* ---- Unmodified RegExps --------------------------------------------------------------------
|
|
1041
|
+
*
|
|
1042
|
+
* The methods below follow the spec step by step: Get(rx, "flags") through the flag getters,
|
|
1043
|
+
* RegExpExec through `exec`, lastIndex read and written as a property, a match array for every
|
|
1044
|
+
* match. For a RegExp as created, on a RegExp.prototype whose methods are the originals, none of
|
|
1045
|
+
* that is observable: test, @@match, @@replace, @@search and @@split then run the matcher
|
|
1046
|
+
* directly and make only what they return (V8 does the same). Checked at every call, after the
|
|
1047
|
+
* steps that can run code (ToString of the arguments). */
|
|
1048
|
+
|
|
1049
|
+
static const JSNativeFn flag_fns[] = { regexp_has_indices, regexp_global, regexp_ignore_case, regexp_multiline,
|
|
1050
|
+
regexp_dot_all, regexp_unicode, regexp_unicode_sets, regexp_sticky };
|
|
1051
|
+
|
|
1052
|
+
static bool is_builtin(JSValue f, JSNativeFn fn) { return js_is_function(f) && js_as_function(f)->entry == fn; }
|
|
1053
|
+
|
|
1054
|
+
/* o's own `key` is a data property holding the built-in fn, or (getter) an accessor whose getter is. */
|
|
1055
|
+
static bool own_builtin(JSObject *o, JSValue key, JSNativeFn fn, bool getter) {
|
|
1056
|
+
uint8_t attrs;
|
|
1057
|
+
int32_t slot = js_shape_find(o->shape, key, &attrs);
|
|
1058
|
+
if (slot < 0 || ((attrs & JS_PROP_ACCESSOR) != 0) != getter) return false;
|
|
1059
|
+
JSValue v = *js_object_slot(o, (uint32_t)slot);
|
|
1060
|
+
return is_builtin(getter ? ((JSAccessorPair *)js_as_cell(v))->get : v, fn);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/* rx, when it's a RegExp whose one own property is lastIndex, writable and a number, on the
|
|
1064
|
+
* realm's RegExp.prototype with the original exec: RegExpExec is then RegExpBuiltinExec, and
|
|
1065
|
+
* lastIndex reads and writes as its slot. Else NULL. */
|
|
1066
|
+
static RegExpObject *unmodified(JSContext *ctx, JSValue rx) {
|
|
1067
|
+
RegExpObject *re = as_regexp(rx);
|
|
1068
|
+
if (!re) return NULL;
|
|
1069
|
+
JSShape *s = re->obj.shape;
|
|
1070
|
+
JSValue proto = ctx->intrinsics[JS_INTRINSIC_REGEXP_PROTOTYPE];
|
|
1071
|
+
if (s->prop_count != 1 || (s->flags & JS_SHAPE_DICTIONARY) || !js_same_bits(s->proto, proto) ||
|
|
1072
|
+
!js_same_bits(s->key, JS_ATOM(lastIndex)) || s->attrs != JS_PROP_WRITABLE || !js_is_number(*js_object_slot(&re->obj, 0)))
|
|
1073
|
+
return NULL;
|
|
1074
|
+
return own_builtin(js_as_object(proto), JS_ATOM(exec), regexp_proto_exec, false) ? re : NULL;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/* Get(rx, "flags") on an unmodified RegExp runs the original getters only: its flags are its
|
|
1078
|
+
* bytecode's. */
|
|
1079
|
+
static bool flags_unmodified(JSContext *ctx) {
|
|
1080
|
+
JSObject *p = js_as_object(ctx->intrinsics[JS_INTRINSIC_REGEXP_PROTOTYPE]);
|
|
1081
|
+
if (!own_builtin(p, JS_ATOM(flags), regexp_flags, true)) return false;
|
|
1082
|
+
for (int i = 0; i < 8; i++)
|
|
1083
|
+
if (!own_builtin(p, js_atom_from_cstr(ctx, flag_names[i]), flag_fns[i], true)) return false;
|
|
1084
|
+
return true;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
static double slot_last_index(JSContext *ctx, RegExpObject *re) {
|
|
1088
|
+
double d;
|
|
1089
|
+
if (to_length(ctx, *js_object_slot(&re->obj, 0), &d) < 0) js_fatal("ToLength of a number");
|
|
1090
|
+
return d;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
static void store_last_index(JSContext *ctx, RegExpObject *re, double index) {
|
|
1094
|
+
js_store(ctx, &re->obj.cell, js_object_slot(&re->obj, 0), js_number(index));
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/* The index in v of a position lre_exec gave. */
|
|
1098
|
+
static uint32_t index_of(JSStrView v, const uint8_t *p) {
|
|
1099
|
+
return (uint32_t)((p - (const uint8_t *)v.chars) >> (v.latin1 ? 0 : 1));
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
/* lre_exec's capture[] for bc: `small`, or malloc'd (free it when it isn't `small`). */
|
|
1103
|
+
static uint8_t **capture_buffer(const uint8_t *bc, uint8_t **small) {
|
|
1104
|
+
int n = lre_get_alloc_count(bc);
|
|
1105
|
+
if (n <= 32) return small;
|
|
1106
|
+
uint8_t **capture = malloc(sizeof *capture * (size_t)n);
|
|
1107
|
+
if (!capture) js_fatal("out of memory matching a regular expression");
|
|
1108
|
+
return capture;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/* test(s) (§22.2.6.16) on an unmodified RegExp: RegExpBuiltinExec without the match array. */
|
|
1112
|
+
static JSValue test_unmodified(JSContext *ctx, RegExpObject *re, JSValue s) {
|
|
1113
|
+
int flags = lre_get_flags(re->bytecode);
|
|
1114
|
+
bool global_or_sticky = (flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) != 0;
|
|
1115
|
+
double from = global_or_sticky ? slot_last_index(ctx, re) : 0;
|
|
1116
|
+
JSStrView v = js_string_view(ctx, s);
|
|
1117
|
+
uint8_t *small[32], **capture = capture_buffer(re->bytecode, small);
|
|
1118
|
+
int rc = from > v.length ? 0 : run(ctx, re, v, (uint32_t)from, capture);
|
|
1119
|
+
if (rc > 0 && global_or_sticky) store_last_index(ctx, re, index_of(v, capture[1]));
|
|
1120
|
+
if (rc == 0 && global_or_sticky) store_last_index(ctx, re, 0);
|
|
1121
|
+
if (capture != small) free(capture);
|
|
1122
|
+
return rc < 0 ? throw_exec_failure(ctx, rc) : js_bool(rc > 0);
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/* @@match with the g flag on an unmodified RegExp: the matched strings, or null. */
|
|
1126
|
+
static JSValue match_global_unmodified(JSContext *ctx, RegExpObject *re, JSValue s) {
|
|
1127
|
+
bool unicode = (lre_get_flags(re->bytecode) & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
1128
|
+
uint8_t *small[32], **capture = capture_buffer(re->bytecode, small);
|
|
1129
|
+
JSValue a = js_new_array(ctx, 0), result;
|
|
1130
|
+
double i = 0;
|
|
1131
|
+
for (;;) {
|
|
1132
|
+
JSStrView v = js_string_view(ctx, s);
|
|
1133
|
+
int rc = i > v.length ? 0 : run(ctx, re, v, (uint32_t)i, capture);
|
|
1134
|
+
if (rc < 0) {
|
|
1135
|
+
store_last_index(ctx, re, i);
|
|
1136
|
+
result = throw_exec_failure(ctx, rc);
|
|
1137
|
+
break;
|
|
1138
|
+
}
|
|
1139
|
+
if (rc == 0) {
|
|
1140
|
+
store_last_index(ctx, re, 0);
|
|
1141
|
+
result = js_array_length(js_as_object(a)) ? a : JS_NULL;
|
|
1142
|
+
break;
|
|
1143
|
+
}
|
|
1144
|
+
uint32_t start = index_of(v, capture[0]), end = index_of(v, capture[1]);
|
|
1145
|
+
JSValue m = js_substring(ctx, s, start, end);
|
|
1146
|
+
if (js_is_exception(m) || js_array_push(ctx, js_as_object(a), m) < 0) {
|
|
1147
|
+
result = JS_EXCEPTION;
|
|
1148
|
+
break;
|
|
1149
|
+
}
|
|
1150
|
+
i = end == start ? advance_index(ctx, s, end, unicode) : end;
|
|
1151
|
+
}
|
|
1152
|
+
if (capture != small) free(capture);
|
|
1153
|
+
return result;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/* @@search on an unmodified RegExp: lastIndex ends as it was, so it's left alone. */
|
|
1157
|
+
static JSValue search_unmodified(JSContext *ctx, RegExpObject *re, JSValue s) {
|
|
1158
|
+
JSStrView v = js_string_view(ctx, s);
|
|
1159
|
+
uint8_t *small[32], **capture = capture_buffer(re->bytecode, small);
|
|
1160
|
+
int rc = run(ctx, re, v, 0, capture);
|
|
1161
|
+
double index = rc > 0 ? (double)index_of(v, capture[0]) : -1;
|
|
1162
|
+
if (capture != small) free(capture);
|
|
1163
|
+
return rc < 0 ? throw_exec_failure(ctx, rc) : js_number(index);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
647
1166
|
BUILTIN(regexp_test) {
|
|
648
1167
|
UNUSED_ARGS;
|
|
649
1168
|
if (!js_is_object(this_val)) return throw_incompatible(ctx, "test", this_val);
|
|
650
1169
|
JSValue s = js_to_string(ctx, ARG(0));
|
|
651
1170
|
if (js_is_exception(s)) return s;
|
|
1171
|
+
RegExpObject *re = unmodified(ctx, this_val);
|
|
1172
|
+
if (re) return test_unmodified(ctx, re, s);
|
|
652
1173
|
JSValue r = regexp_exec(ctx, this_val, s);
|
|
653
1174
|
return js_is_exception(r) ? r : js_bool(!js_is_null(r));
|
|
654
1175
|
}
|
|
@@ -673,6 +1194,9 @@ BUILTIN(regexp_symbol_match) {
|
|
|
673
1194
|
if (!js_is_object(rx)) return throw_incompatible(ctx, "@@match", rx);
|
|
674
1195
|
JSValue s = js_to_string(ctx, ARG(0));
|
|
675
1196
|
if (js_is_exception(s)) return s;
|
|
1197
|
+
RegExpObject *re = unmodified(ctx, rx);
|
|
1198
|
+
if (re && flags_unmodified(ctx))
|
|
1199
|
+
return lre_get_flags(re->bytecode) & LRE_FLAG_GLOBAL ? match_global_unmodified(ctx, re, s) : builtin_exec(ctx, rx, s);
|
|
676
1200
|
JSValue flags = js_get_value(ctx, rx, JS_ATOM(flags));
|
|
677
1201
|
JSValue f = js_is_exception(flags) ? flags : js_to_string(ctx, flags);
|
|
678
1202
|
if (js_is_exception(f)) return f;
|
|
@@ -874,6 +1398,83 @@ static int get_substitution(JSContext *ctx, Builder *b, JSValue matched, JSValue
|
|
|
874
1398
|
return 0;
|
|
875
1399
|
}
|
|
876
1400
|
|
|
1401
|
+
/* @@replace on an unmodified RegExp without named groups, of at most 32 captures. Every match is
|
|
1402
|
+
* found before a replacement function first runs, as in the spec, which collects the match
|
|
1403
|
+
* arrays first: positions only here, the strings made as each replacement needs them. */
|
|
1404
|
+
static JSValue replace_unmodified(JSContext *ctx, RegExpObject *re, JSValue s, JSValue replace_value, bool functional) {
|
|
1405
|
+
const uint8_t *bc = re->bytecode;
|
|
1406
|
+
int flags = lre_get_flags(bc);
|
|
1407
|
+
uint32_t ncap = (uint32_t)lre_get_capture_count(bc);
|
|
1408
|
+
bool global = (flags & LRE_FLAG_GLOBAL) != 0, sticky = (flags & LRE_FLAG_STICKY) != 0;
|
|
1409
|
+
bool unicode = (flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
1410
|
+
uint32_t *pos = NULL; /* each match's captures: start and end, UINT32_MAX when unset */
|
|
1411
|
+
size_t count = 0, cap = 0;
|
|
1412
|
+
uint8_t *small[32], **capture = capture_buffer(bc, small);
|
|
1413
|
+
double i = global || !sticky ? 0 : slot_last_index(ctx, re);
|
|
1414
|
+
int rc;
|
|
1415
|
+
for (;;) {
|
|
1416
|
+
JSStrView v = js_string_view(ctx, s);
|
|
1417
|
+
rc = i > v.length ? 0 : run(ctx, re, v, (uint32_t)i, capture);
|
|
1418
|
+
if (rc <= 0) break;
|
|
1419
|
+
if (count == cap) {
|
|
1420
|
+
cap = cap ? cap * 2 : 8;
|
|
1421
|
+
uint32_t *grown = realloc(pos, cap * 2 * ncap * sizeof *pos);
|
|
1422
|
+
if (!grown) js_fatal("out of memory replacing");
|
|
1423
|
+
pos = grown;
|
|
1424
|
+
}
|
|
1425
|
+
uint32_t *m = pos + count++ * 2 * ncap;
|
|
1426
|
+
for (uint32_t k = 0; k < ncap; k++) {
|
|
1427
|
+
bool set = capture[2 * k] && capture[2 * k + 1];
|
|
1428
|
+
m[2 * k] = set ? index_of(v, capture[2 * k]) : UINT32_MAX;
|
|
1429
|
+
m[2 * k + 1] = set ? index_of(v, capture[2 * k + 1]) : UINT32_MAX;
|
|
1430
|
+
}
|
|
1431
|
+
if (!global) break;
|
|
1432
|
+
i = m[1] == m[0] ? advance_index(ctx, s, m[1], unicode) : m[1];
|
|
1433
|
+
}
|
|
1434
|
+
if (capture != small) free(capture);
|
|
1435
|
+
if (global) store_last_index(ctx, re, rc < 0 ? i : 0);
|
|
1436
|
+
else if (sticky && rc >= 0) store_last_index(ctx, re, rc ? pos[1] : 0);
|
|
1437
|
+
if (rc < 0) {
|
|
1438
|
+
free(pos);
|
|
1439
|
+
return throw_exec_failure(ctx, rc);
|
|
1440
|
+
}
|
|
1441
|
+
bool dollar = !functional && has_unit(ctx, replace_value, '$');
|
|
1442
|
+
Builder b = { 0 };
|
|
1443
|
+
uint32_t next = 0;
|
|
1444
|
+
for (size_t j = 0; j < count; j++) {
|
|
1445
|
+
const uint32_t *m = pos + j * 2 * ncap;
|
|
1446
|
+
if (m[0] > next) put_view(&b, js_string_view(ctx, s), next, m[0]);
|
|
1447
|
+
if (!functional && !dollar) {
|
|
1448
|
+
put_string(&b, ctx, replace_value);
|
|
1449
|
+
} else {
|
|
1450
|
+
JSValue args[34]; /* the match, its captures, the position, the string */
|
|
1451
|
+
for (uint32_t k = 0; k < ncap; k++) {
|
|
1452
|
+
args[k] = m[2 * k] == UINT32_MAX ? JS_UNDEFINED : js_substring(ctx, s, m[2 * k], m[2 * k + 1]);
|
|
1453
|
+
if (js_is_exception(args[k])) goto fail;
|
|
1454
|
+
}
|
|
1455
|
+
if (functional) {
|
|
1456
|
+
args[ncap] = js_number(m[0]);
|
|
1457
|
+
args[ncap + 1] = s;
|
|
1458
|
+
JSValue r = js_call(ctx, replace_value, JS_UNDEFINED, ncap + 2, args);
|
|
1459
|
+
JSValue replacement = js_is_exception(r) ? r : js_to_string(ctx, r);
|
|
1460
|
+
if (js_is_exception(replacement)) goto fail;
|
|
1461
|
+
put_string(&b, ctx, replacement);
|
|
1462
|
+
} else if (get_substitution(ctx, &b, args[0], s, m[0], args + 1, ncap - 1, JS_UNDEFINED, replace_value) < 0) {
|
|
1463
|
+
goto fail;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
next = m[1];
|
|
1467
|
+
}
|
|
1468
|
+
uint32_t length = js_string_length(s);
|
|
1469
|
+
if (next < length) put_view(&b, js_string_view(ctx, s), next, length);
|
|
1470
|
+
free(pos);
|
|
1471
|
+
return finish(ctx, &b);
|
|
1472
|
+
fail:
|
|
1473
|
+
free(pos);
|
|
1474
|
+
free(b.units);
|
|
1475
|
+
return JS_EXCEPTION;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
877
1478
|
/* RegExp.prototype[@@replace](string, replaceValue) (§22.2.6.11) */
|
|
878
1479
|
BUILTIN(regexp_symbol_replace) {
|
|
879
1480
|
UNUSED_ARGS;
|
|
@@ -887,6 +1488,9 @@ BUILTIN(regexp_symbol_replace) {
|
|
|
887
1488
|
replace_value = js_to_string(ctx, replace_value);
|
|
888
1489
|
if (js_is_exception(replace_value)) return replace_value;
|
|
889
1490
|
}
|
|
1491
|
+
RegExpObject *re = unmodified(ctx, rx);
|
|
1492
|
+
if (re && lre_get_capture_count(re->bytecode) <= 32 && !lre_get_groupnames(re->bytecode) && flags_unmodified(ctx))
|
|
1493
|
+
return replace_unmodified(ctx, re, s, replace_value, functional);
|
|
890
1494
|
JSValue flags = js_get_value(ctx, rx, JS_ATOM(flags));
|
|
891
1495
|
JSValue f = js_is_exception(flags) ? flags : js_to_string(ctx, flags);
|
|
892
1496
|
if (js_is_exception(f)) return f;
|
|
@@ -989,6 +1593,8 @@ BUILTIN(regexp_symbol_search) {
|
|
|
989
1593
|
if (!js_is_object(rx)) return throw_incompatible(ctx, "@@search", rx);
|
|
990
1594
|
JSValue s = js_to_string(ctx, ARG(0));
|
|
991
1595
|
if (js_is_exception(s)) return s;
|
|
1596
|
+
RegExpObject *re = unmodified(ctx, rx);
|
|
1597
|
+
if (re) return search_unmodified(ctx, re, s);
|
|
992
1598
|
JSValue previous = js_get_value(ctx, rx, JS_ATOM(lastIndex));
|
|
993
1599
|
if (js_is_exception(previous)) return previous;
|
|
994
1600
|
if (!js_same_value(ctx, previous, js_int32(0)) && set_last_index(ctx, rx, 0) < 0) return JS_EXCEPTION;
|
|
@@ -1001,6 +1607,80 @@ BUILTIN(regexp_symbol_search) {
|
|
|
1001
1607
|
return js_get_value(ctx, result, JS_ATOM(index));
|
|
1002
1608
|
}
|
|
1003
1609
|
|
|
1610
|
+
/* @@split's splitter is new %RegExp%(rx, flags + "y") without running code when rx is unmodified,
|
|
1611
|
+
* RegExp.prototype's constructor and @@match and RegExp's @@species are the originals. */
|
|
1612
|
+
static bool species_unmodified(JSContext *ctx) {
|
|
1613
|
+
JSObject *p = js_as_object(ctx->intrinsics[JS_INTRINSIC_REGEXP_PROTOTYPE]);
|
|
1614
|
+
JSValue c = ctx->intrinsics[JS_INTRINSIC_REGEXP];
|
|
1615
|
+
uint8_t attrs;
|
|
1616
|
+
int32_t slot = js_shape_find(p->shape, JS_ATOM(constructor), &attrs);
|
|
1617
|
+
return slot >= 0 && !(attrs & JS_PROP_ACCESSOR) && js_same_bits(*js_object_slot(p, (uint32_t)slot), c) &&
|
|
1618
|
+
own_builtin(p, JS_SYMBOL(match), regexp_symbol_match, false) && own_builtin(js_as_object(c), JS_SYMBOL(species), regexp_species, true);
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
/* @@split on an unmodified RegExp without the y, u or v flags. The spec's splitter tries a
|
|
1622
|
+
* sticky match at each position q in turn; a search from q finds the first q that matches, with
|
|
1623
|
+
* the same match there, and no splitter is made. */
|
|
1624
|
+
static JSValue split_unmodified(JSContext *ctx, RegExpObject *re, JSValue s, uint32_t lim) {
|
|
1625
|
+
JSValue a = js_new_array(ctx, 0);
|
|
1626
|
+
if (lim == 0) return a;
|
|
1627
|
+
uint32_t ncap = (uint32_t)lre_get_capture_count(re->bytecode);
|
|
1628
|
+
uint8_t *small[32], **capture = capture_buffer(re->bytecode, small);
|
|
1629
|
+
uint32_t size = js_string_length(s), p = 0, q = 0;
|
|
1630
|
+
JSValue result = a;
|
|
1631
|
+
if (size == 0) {
|
|
1632
|
+
int rc = run(ctx, re, js_string_view(ctx, s), 0, capture);
|
|
1633
|
+
if (rc < 0) result = throw_exec_failure(ctx, rc);
|
|
1634
|
+
else if (rc == 0 && js_array_push(ctx, js_as_object(a), s) < 0) result = JS_EXCEPTION;
|
|
1635
|
+
goto out;
|
|
1636
|
+
}
|
|
1637
|
+
while (q < size) {
|
|
1638
|
+
JSStrView v = js_string_view(ctx, s);
|
|
1639
|
+
int rc = run(ctx, re, v, q, capture);
|
|
1640
|
+
if (rc < 0) {
|
|
1641
|
+
result = throw_exec_failure(ctx, rc);
|
|
1642
|
+
goto out;
|
|
1643
|
+
}
|
|
1644
|
+
if (rc == 0) break;
|
|
1645
|
+
uint32_t start = index_of(v, capture[0]), e = index_of(v, capture[1]);
|
|
1646
|
+
if (start >= size) break; /* the spec's loop stops before trying the end */
|
|
1647
|
+
if (e == p) { /* empty, where the last piece ended */
|
|
1648
|
+
q = start + 1;
|
|
1649
|
+
continue;
|
|
1650
|
+
}
|
|
1651
|
+
uint32_t bounds[64]; /* the captures, read before allocating */
|
|
1652
|
+
for (uint32_t k = 1; k < ncap && k < 33; k++) {
|
|
1653
|
+
bool set = capture[2 * k] && capture[2 * k + 1];
|
|
1654
|
+
bounds[2 * (k - 1)] = set ? index_of(v, capture[2 * k]) : UINT32_MAX;
|
|
1655
|
+
bounds[2 * (k - 1) + 1] = set ? index_of(v, capture[2 * k + 1]) : UINT32_MAX;
|
|
1656
|
+
}
|
|
1657
|
+
JSValue sub = js_substring(ctx, s, p, start);
|
|
1658
|
+
if (js_is_exception(sub) || js_array_push(ctx, js_as_object(a), sub) < 0) {
|
|
1659
|
+
result = JS_EXCEPTION;
|
|
1660
|
+
goto out;
|
|
1661
|
+
}
|
|
1662
|
+
if (js_array_length(js_as_object(a)) == lim) goto out;
|
|
1663
|
+
p = e;
|
|
1664
|
+
for (uint32_t k = 1; k < ncap; k++) {
|
|
1665
|
+
uint32_t lo = bounds[2 * (k - 1)], hi = bounds[2 * (k - 1) + 1];
|
|
1666
|
+
JSValue c = lo == UINT32_MAX ? JS_UNDEFINED : js_substring(ctx, s, lo, hi);
|
|
1667
|
+
if (js_is_exception(c) || js_array_push(ctx, js_as_object(a), c) < 0) {
|
|
1668
|
+
result = JS_EXCEPTION;
|
|
1669
|
+
goto out;
|
|
1670
|
+
}
|
|
1671
|
+
if (js_array_length(js_as_object(a)) == lim) goto out;
|
|
1672
|
+
}
|
|
1673
|
+
q = p;
|
|
1674
|
+
}
|
|
1675
|
+
{
|
|
1676
|
+
JSValue tail = js_substring(ctx, s, p < size ? p : size, size);
|
|
1677
|
+
if (js_is_exception(tail) || js_array_push(ctx, js_as_object(a), tail) < 0) result = JS_EXCEPTION;
|
|
1678
|
+
}
|
|
1679
|
+
out:
|
|
1680
|
+
if (capture != small) free(capture);
|
|
1681
|
+
return result;
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1004
1684
|
/* RegExp.prototype[@@split](string, limit) (§22.2.6.14) */
|
|
1005
1685
|
BUILTIN(regexp_symbol_split) {
|
|
1006
1686
|
UNUSED_ARGS;
|
|
@@ -1008,6 +1688,11 @@ BUILTIN(regexp_symbol_split) {
|
|
|
1008
1688
|
if (!js_is_object(rx)) return throw_incompatible(ctx, "@@split", rx);
|
|
1009
1689
|
JSValue s = js_to_string(ctx, ARG(0));
|
|
1010
1690
|
if (js_is_exception(s)) return s;
|
|
1691
|
+
RegExpObject *re = unmodified(ctx, rx);
|
|
1692
|
+
JSValue limit = ARG(1);
|
|
1693
|
+
if (re && !(lre_get_flags(re->bytecode) & (LRE_FLAG_STICKY | LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) &&
|
|
1694
|
+
(js_is_undefined(limit) || js_is_number(limit)) && flags_unmodified(ctx) && species_unmodified(ctx))
|
|
1695
|
+
return split_unmodified(ctx, re, s, js_is_undefined(limit) ? UINT32_MAX : (uint32_t)js_double_to_int32(js_as_number(limit)));
|
|
1011
1696
|
JSValue c = species_constructor(ctx, rx);
|
|
1012
1697
|
if (js_is_exception(c)) return c;
|
|
1013
1698
|
JSValue flags = js_get_value(ctx, rx, JS_ATOM(flags));
|
|
@@ -1121,6 +1806,10 @@ static const JSBuiltin regexp_string_iterator_proto[] = {
|
|
|
1121
1806
|
};
|
|
1122
1807
|
|
|
1123
1808
|
static void install_regexp(JSContext *ctx, JSObject *global) {
|
|
1809
|
+
for (uint32_t c = 0; c < 0x100; c++) { /* the same in every realm */
|
|
1810
|
+
canonical[0][c] = (uint32_t)lre_canonicalize(c, 0);
|
|
1811
|
+
canonical[1][c] = (uint32_t)lre_canonicalize(c, 1);
|
|
1812
|
+
}
|
|
1124
1813
|
JSValue proto = js_new_object_proto(ctx, ctx->intrinsics[JS_INTRINSIC_OBJECT_PROTOTYPE], 8);
|
|
1125
1814
|
ctx->intrinsics[JS_INTRINSIC_REGEXP_PROTOTYPE] = proto;
|
|
1126
1815
|
JSValue key = js_atom_from_cstr(ctx, "RegExp");
|