@scriptc/runtime 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/package.json +16 -6
- package/src/scr_array.c +488 -0
- package/src/scr_assert.c +1393 -0
- package/src/scr_async.c +2593 -0
- package/src/scr_async_dyn.c +607 -0
- package/src/scr_bytes.c +1425 -0
- package/src/scr_bytes_io.c +161 -0
- package/src/scr_child.c +3587 -0
- package/src/scr_closure.c +214 -0
- package/src/scr_console.c +143 -0
- package/src/scr_cycle.c +218 -0
- package/src/scr_dc.c +805 -0
- package/src/scr_dgram.c +1007 -0
- package/src/scr_dyn_handle.c +154 -0
- package/src/scr_dyn_invoke.c +644 -0
- package/src/scr_error.c +332 -0
- package/src/scr_events.c +714 -0
- package/src/scr_events_emitter.c +699 -0
- package/src/scr_exception.c +242 -0
- package/src/scr_fetch.c +1130 -0
- package/src/scr_fetch_curl.c +654 -0
- package/src/scr_http.c +3482 -0
- package/src/scr_http2.c +3030 -0
- package/src/scr_inspect.c +803 -0
- package/src/scr_inspect_island.c +51 -0
- package/src/scr_island.c +9363 -0
- package/src/scr_json.c +2151 -0
- package/src/scr_lib.c +3612 -0
- package/src/scr_loop_epoll.c +241 -0
- package/src/scr_loop_kqueue.c +121 -0
- package/src/scr_loop_wsapoll.c +208 -0
- package/src/scr_map.c +591 -0
- package/src/scr_net.c +3017 -0
- package/src/scr_net_island.c +458 -0
- package/src/scr_number.c +115 -0
- package/src/scr_object.c +25 -0
- package/src/scr_path.c +1266 -0
- package/src/scr_platform.h +119 -0
- package/src/scr_readline.c +287 -0
- package/src/scr_regex.c +1080 -0
- package/src/scr_runtime.h +5046 -0
- package/src/scr_stream.c +2877 -0
- package/src/scr_string.c +1264 -0
- package/src/scr_symbol.c +132 -0
- package/src/scr_test.c +662 -0
- package/src/scr_tls.c +1520 -0
- package/src/scr_union.c +105 -0
- package/src/scr_url.c +911 -0
- package/src/scr_url_internal.h +29 -0
- package/src/scr_url_params.c +561 -0
- package/src/scr_watch.c +568 -0
- package/src/scr_web.c +1778 -0
- package/src/scr_win.c +76 -0
- package/src/scr_zlib.c +197 -0
- package/src/scr_zlib_island.c +15 -0
- package/vendor/README.md +52 -0
- package/vendor/curl/COPYRIGHT +534 -0
- package/vendor/curl/include/curl/curl.h +3214 -0
- package/vendor/curl/include/curl/curlver.h +79 -0
- package/vendor/curl/include/curl/easy.h +125 -0
- package/vendor/curl/include/curl/header.h +74 -0
- package/vendor/curl/include/curl/mprintf.h +52 -0
- package/vendor/curl/include/curl/multi.h +460 -0
- package/vendor/curl/include/curl/options.h +70 -0
- package/vendor/curl/include/curl/stdcheaders.h +35 -0
- package/vendor/curl/include/curl/system.h +508 -0
- package/vendor/curl/include/curl/typecheck-gcc.h +716 -0
- package/vendor/curl/include/curl/urlapi.h +149 -0
- package/vendor/curl/include/curl/websockets.h +84 -0
- package/vendor/mbedtls/LICENSE +553 -0
- package/vendor/mbedtls/include/CMakeLists.txt +22 -0
- package/vendor/mbedtls/include/mbedtls/aes.h +631 -0
- package/vendor/mbedtls/include/mbedtls/aria.h +343 -0
- package/vendor/mbedtls/include/mbedtls/asn1.h +642 -0
- package/vendor/mbedtls/include/mbedtls/asn1write.h +390 -0
- package/vendor/mbedtls/include/mbedtls/base64.h +82 -0
- package/vendor/mbedtls/include/mbedtls/bignum.h +1088 -0
- package/vendor/mbedtls/include/mbedtls/block_cipher.h +76 -0
- package/vendor/mbedtls/include/mbedtls/build_info.h +194 -0
- package/vendor/mbedtls/include/mbedtls/camellia.h +305 -0
- package/vendor/mbedtls/include/mbedtls/ccm.h +526 -0
- package/vendor/mbedtls/include/mbedtls/chacha20.h +209 -0
- package/vendor/mbedtls/include/mbedtls/chachapoly.h +351 -0
- package/vendor/mbedtls/include/mbedtls/check_config.h +1149 -0
- package/vendor/mbedtls/include/mbedtls/cipher.h +1250 -0
- package/vendor/mbedtls/include/mbedtls/cmac.h +246 -0
- package/vendor/mbedtls/include/mbedtls/compat-2.x.h +46 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h +578 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_from_psa.h +873 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h +359 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_psa_superset_legacy.h +145 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h +91 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_x509.h +35 -0
- package/vendor/mbedtls/include/mbedtls/config_psa.h +61 -0
- package/vendor/mbedtls/include/mbedtls/constant_time.h +36 -0
- package/vendor/mbedtls/include/mbedtls/ctr_drbg.h +596 -0
- package/vendor/mbedtls/include/mbedtls/debug.h +156 -0
- package/vendor/mbedtls/include/mbedtls/des.h +385 -0
- package/vendor/mbedtls/include/mbedtls/dhm.h +972 -0
- package/vendor/mbedtls/include/mbedtls/ecdh.h +455 -0
- package/vendor/mbedtls/include/mbedtls/ecdsa.h +674 -0
- package/vendor/mbedtls/include/mbedtls/ecjpake.h +298 -0
- package/vendor/mbedtls/include/mbedtls/ecp.h +1517 -0
- package/vendor/mbedtls/include/mbedtls/entropy.h +274 -0
- package/vendor/mbedtls/include/mbedtls/error.h +201 -0
- package/vendor/mbedtls/include/mbedtls/gcm.h +387 -0
- package/vendor/mbedtls/include/mbedtls/hkdf.h +124 -0
- package/vendor/mbedtls/include/mbedtls/hmac_drbg.h +434 -0
- package/vendor/mbedtls/include/mbedtls/lms.h +440 -0
- package/vendor/mbedtls/include/mbedtls/mbedtls_config.h +4446 -0
- package/vendor/mbedtls/include/mbedtls/md.h +526 -0
- package/vendor/mbedtls/include/mbedtls/md5.h +190 -0
- package/vendor/mbedtls/include/mbedtls/memory_buffer_alloc.h +142 -0
- package/vendor/mbedtls/include/mbedtls/net_sockets.h +299 -0
- package/vendor/mbedtls/include/mbedtls/nist_kw.h +166 -0
- package/vendor/mbedtls/include/mbedtls/oid.h +727 -0
- package/vendor/mbedtls/include/mbedtls/pem.h +160 -0
- package/vendor/mbedtls/include/mbedtls/pk.h +1303 -0
- package/vendor/mbedtls/include/mbedtls/pkcs12.h +186 -0
- package/vendor/mbedtls/include/mbedtls/pkcs5.h +198 -0
- package/vendor/mbedtls/include/mbedtls/pkcs7.h +252 -0
- package/vendor/mbedtls/include/mbedtls/platform.h +516 -0
- package/vendor/mbedtls/include/mbedtls/platform_time.h +79 -0
- package/vendor/mbedtls/include/mbedtls/platform_util.h +247 -0
- package/vendor/mbedtls/include/mbedtls/poly1305.h +168 -0
- package/vendor/mbedtls/include/mbedtls/private_access.h +20 -0
- package/vendor/mbedtls/include/mbedtls/psa_util.h +207 -0
- package/vendor/mbedtls/include/mbedtls/ripemd160.h +136 -0
- package/vendor/mbedtls/include/mbedtls/rsa.h +1170 -0
- package/vendor/mbedtls/include/mbedtls/sha1.h +219 -0
- package/vendor/mbedtls/include/mbedtls/sha256.h +200 -0
- package/vendor/mbedtls/include/mbedtls/sha3.h +172 -0
- package/vendor/mbedtls/include/mbedtls/sha512.h +208 -0
- package/vendor/mbedtls/include/mbedtls/ssl.h +5887 -0
- package/vendor/mbedtls/include/mbedtls/ssl_cache.h +187 -0
- package/vendor/mbedtls/include/mbedtls/ssl_ciphersuites.h +482 -0
- package/vendor/mbedtls/include/mbedtls/ssl_cookie.h +106 -0
- package/vendor/mbedtls/include/mbedtls/ssl_ticket.h +199 -0
- package/vendor/mbedtls/include/mbedtls/threading.h +167 -0
- package/vendor/mbedtls/include/mbedtls/timing.h +94 -0
- package/vendor/mbedtls/include/mbedtls/version.h +78 -0
- package/vendor/mbedtls/include/mbedtls/x509.h +500 -0
- package/vendor/mbedtls/include/mbedtls/x509_crl.h +184 -0
- package/vendor/mbedtls/include/mbedtls/x509_crt.h +1208 -0
- package/vendor/mbedtls/include/mbedtls/x509_csr.h +382 -0
- package/vendor/mbedtls/include/psa/build_info.h +20 -0
- package/vendor/mbedtls/include/psa/crypto.h +4998 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_auto_enabled.h +31 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_dependencies.h +51 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_key_pair_types.h +101 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_synonyms.h +49 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_composites.h +214 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_key_derivation.h +118 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_primitives.h +114 -0
- package/vendor/mbedtls/include/psa/crypto_compat.h +230 -0
- package/vendor/mbedtls/include/psa/crypto_config.h +145 -0
- package/vendor/mbedtls/include/psa/crypto_driver_common.h +44 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_composites.h +151 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_key_derivation.h +52 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_primitives.h +105 -0
- package/vendor/mbedtls/include/psa/crypto_extra.h +2145 -0
- package/vendor/mbedtls/include/psa/crypto_legacy.h +88 -0
- package/vendor/mbedtls/include/psa/crypto_platform.h +102 -0
- package/vendor/mbedtls/include/psa/crypto_se_driver.h +1383 -0
- package/vendor/mbedtls/include/psa/crypto_sizes.h +1319 -0
- package/vendor/mbedtls/include/psa/crypto_struct.h +527 -0
- package/vendor/mbedtls/include/psa/crypto_types.h +508 -0
- package/vendor/mbedtls/include/psa/crypto_values.h +2782 -0
- package/vendor/mbedtls/library/aes.c +2294 -0
- package/vendor/mbedtls/library/aesce.c +624 -0
- package/vendor/mbedtls/library/aesce.h +136 -0
- package/vendor/mbedtls/library/aesni.c +846 -0
- package/vendor/mbedtls/library/aesni.h +162 -0
- package/vendor/mbedtls/library/alignment.h +704 -0
- package/vendor/mbedtls/library/aria.c +969 -0
- package/vendor/mbedtls/library/asn1parse.c +468 -0
- package/vendor/mbedtls/library/asn1write.c +440 -0
- package/vendor/mbedtls/library/base64.c +322 -0
- package/vendor/mbedtls/library/base64_internal.h +45 -0
- package/vendor/mbedtls/library/bignum.c +2583 -0
- package/vendor/mbedtls/library/bignum_core.c +1240 -0
- package/vendor/mbedtls/library/bignum_core.h +872 -0
- package/vendor/mbedtls/library/bignum_core_invasive.h +38 -0
- package/vendor/mbedtls/library/bignum_internal.h +122 -0
- package/vendor/mbedtls/library/bignum_mod.c +394 -0
- package/vendor/mbedtls/library/bignum_mod.h +452 -0
- package/vendor/mbedtls/library/bignum_mod_raw.c +276 -0
- package/vendor/mbedtls/library/bignum_mod_raw.h +416 -0
- package/vendor/mbedtls/library/bignum_mod_raw_invasive.h +34 -0
- package/vendor/mbedtls/library/block_cipher.c +207 -0
- package/vendor/mbedtls/library/block_cipher_internal.h +99 -0
- package/vendor/mbedtls/library/bn_mul.h +1094 -0
- package/vendor/mbedtls/library/camellia.c +1058 -0
- package/vendor/mbedtls/library/ccm.c +777 -0
- package/vendor/mbedtls/library/chacha20.c +563 -0
- package/vendor/mbedtls/library/chacha20_internal.h +23 -0
- package/vendor/mbedtls/library/chachapoly.c +487 -0
- package/vendor/mbedtls/library/check_crypto_config.h +136 -0
- package/vendor/mbedtls/library/cipher.c +1712 -0
- package/vendor/mbedtls/library/cipher_invasive.h +28 -0
- package/vendor/mbedtls/library/cipher_wrap.c +2482 -0
- package/vendor/mbedtls/library/cipher_wrap.h +178 -0
- package/vendor/mbedtls/library/cmac.c +1067 -0
- package/vendor/mbedtls/library/common.h +487 -0
- package/vendor/mbedtls/library/constant_time.c +247 -0
- package/vendor/mbedtls/library/constant_time_impl.h +541 -0
- package/vendor/mbedtls/library/constant_time_internal.h +579 -0
- package/vendor/mbedtls/library/ctr.h +35 -0
- package/vendor/mbedtls/library/ctr_drbg.c +1016 -0
- package/vendor/mbedtls/library/debug.c +475 -0
- package/vendor/mbedtls/library/debug_internal.h +185 -0
- package/vendor/mbedtls/library/des.c +1042 -0
- package/vendor/mbedtls/library/dhm.c +700 -0
- package/vendor/mbedtls/library/ecdh.c +696 -0
- package/vendor/mbedtls/library/ecdsa.c +858 -0
- package/vendor/mbedtls/library/ecjpake.c +1216 -0
- package/vendor/mbedtls/library/ecp.c +3674 -0
- package/vendor/mbedtls/library/ecp_curves.c +6125 -0
- package/vendor/mbedtls/library/ecp_curves_new.c +9 -0
- package/vendor/mbedtls/library/ecp_internal_alt.h +287 -0
- package/vendor/mbedtls/library/ecp_invasive.h +305 -0
- package/vendor/mbedtls/library/entropy.c +680 -0
- package/vendor/mbedtls/library/entropy_poll.c +233 -0
- package/vendor/mbedtls/library/entropy_poll.h +64 -0
- package/vendor/mbedtls/library/error.c +878 -0
- package/vendor/mbedtls/library/gcm.c +1330 -0
- package/vendor/mbedtls/library/hkdf.c +161 -0
- package/vendor/mbedtls/library/hmac_drbg.c +633 -0
- package/vendor/mbedtls/library/lmots.c +789 -0
- package/vendor/mbedtls/library/lmots.h +288 -0
- package/vendor/mbedtls/library/lms.c +778 -0
- package/vendor/mbedtls/library/md.c +1108 -0
- package/vendor/mbedtls/library/md5.c +426 -0
- package/vendor/mbedtls/library/md_psa.h +26 -0
- package/vendor/mbedtls/library/md_wrap.h +46 -0
- package/vendor/mbedtls/library/memory_buffer_alloc.c +751 -0
- package/vendor/mbedtls/library/mps_common.h +181 -0
- package/vendor/mbedtls/library/mps_error.h +89 -0
- package/vendor/mbedtls/library/mps_reader.c +538 -0
- package/vendor/mbedtls/library/mps_reader.h +366 -0
- package/vendor/mbedtls/library/mps_trace.c +112 -0
- package/vendor/mbedtls/library/mps_trace.h +154 -0
- package/vendor/mbedtls/library/net_sockets.c +694 -0
- package/vendor/mbedtls/library/nist_kw.c +729 -0
- package/vendor/mbedtls/library/oid.c +1166 -0
- package/vendor/mbedtls/library/padlock.c +157 -0
- package/vendor/mbedtls/library/padlock.h +111 -0
- package/vendor/mbedtls/library/pem.c +554 -0
- package/vendor/mbedtls/library/pk.c +1602 -0
- package/vendor/mbedtls/library/pk_ecc.c +261 -0
- package/vendor/mbedtls/library/pk_internal.h +241 -0
- package/vendor/mbedtls/library/pk_wrap.c +1618 -0
- package/vendor/mbedtls/library/pk_wrap.h +138 -0
- package/vendor/mbedtls/library/pkcs12.c +437 -0
- package/vendor/mbedtls/library/pkcs5.c +500 -0
- package/vendor/mbedtls/library/pkcs7.c +787 -0
- package/vendor/mbedtls/library/pkparse.c +1392 -0
- package/vendor/mbedtls/library/pkwrite.c +631 -0
- package/vendor/mbedtls/library/pkwrite.h +121 -0
- package/vendor/mbedtls/library/platform.c +402 -0
- package/vendor/mbedtls/library/platform_util.c +258 -0
- package/vendor/mbedtls/library/poly1305.c +492 -0
- package/vendor/mbedtls/library/psa_crypto.c +9532 -0
- package/vendor/mbedtls/library/psa_crypto_aead.c +646 -0
- package/vendor/mbedtls/library/psa_crypto_aead.h +499 -0
- package/vendor/mbedtls/library/psa_crypto_cipher.c +747 -0
- package/vendor/mbedtls/library/psa_crypto_cipher.h +316 -0
- package/vendor/mbedtls/library/psa_crypto_client.c +22 -0
- package/vendor/mbedtls/library/psa_crypto_core.h +983 -0
- package/vendor/mbedtls/library/psa_crypto_core_common.h +52 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers.h +2896 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.c +256 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.h +31 -0
- package/vendor/mbedtls/library/psa_crypto_ecp.c +594 -0
- package/vendor/mbedtls/library/psa_crypto_ecp.h +267 -0
- package/vendor/mbedtls/library/psa_crypto_ffdh.c +361 -0
- package/vendor/mbedtls/library/psa_crypto_ffdh.h +131 -0
- package/vendor/mbedtls/library/psa_crypto_hash.c +470 -0
- package/vendor/mbedtls/library/psa_crypto_hash.h +211 -0
- package/vendor/mbedtls/library/psa_crypto_invasive.h +92 -0
- package/vendor/mbedtls/library/psa_crypto_its.h +131 -0
- package/vendor/mbedtls/library/psa_crypto_mac.c +505 -0
- package/vendor/mbedtls/library/psa_crypto_mac.h +264 -0
- package/vendor/mbedtls/library/psa_crypto_pake.c +571 -0
- package/vendor/mbedtls/library/psa_crypto_pake.h +159 -0
- package/vendor/mbedtls/library/psa_crypto_random.c +181 -0
- package/vendor/mbedtls/library/psa_crypto_random.h +72 -0
- package/vendor/mbedtls/library/psa_crypto_random_impl.h +200 -0
- package/vendor/mbedtls/library/psa_crypto_rsa.c +714 -0
- package/vendor/mbedtls/library/psa_crypto_rsa.h +321 -0
- package/vendor/mbedtls/library/psa_crypto_se.c +373 -0
- package/vendor/mbedtls/library/psa_crypto_se.h +192 -0
- package/vendor/mbedtls/library/psa_crypto_slot_management.c +1137 -0
- package/vendor/mbedtls/library/psa_crypto_slot_management.h +344 -0
- package/vendor/mbedtls/library/psa_crypto_storage.c +481 -0
- package/vendor/mbedtls/library/psa_crypto_storage.h +392 -0
- package/vendor/mbedtls/library/psa_its_file.c +254 -0
- package/vendor/mbedtls/library/psa_util.c +614 -0
- package/vendor/mbedtls/library/psa_util_internal.h +100 -0
- package/vendor/mbedtls/library/ripemd160.c +490 -0
- package/vendor/mbedtls/library/rsa.c +3121 -0
- package/vendor/mbedtls/library/rsa_alt_helpers.c +455 -0
- package/vendor/mbedtls/library/rsa_alt_helpers.h +209 -0
- package/vendor/mbedtls/library/rsa_internal.h +188 -0
- package/vendor/mbedtls/library/sha1.c +480 -0
- package/vendor/mbedtls/library/sha256.c +983 -0
- package/vendor/mbedtls/library/sha3.c +721 -0
- package/vendor/mbedtls/library/sha512.c +1115 -0
- package/vendor/mbedtls/library/ssl_cache.c +410 -0
- package/vendor/mbedtls/library/ssl_ciphersuites.c +2050 -0
- package/vendor/mbedtls/library/ssl_ciphersuites_internal.h +154 -0
- package/vendor/mbedtls/library/ssl_client.c +1023 -0
- package/vendor/mbedtls/library/ssl_client.h +22 -0
- package/vendor/mbedtls/library/ssl_cookie.c +384 -0
- package/vendor/mbedtls/library/ssl_debug_helpers.h +85 -0
- package/vendor/mbedtls/library/ssl_debug_helpers_generated.c +251 -0
- package/vendor/mbedtls/library/ssl_misc.h +3198 -0
- package/vendor/mbedtls/library/ssl_msg.c +6619 -0
- package/vendor/mbedtls/library/ssl_ticket.c +556 -0
- package/vendor/mbedtls/library/ssl_tls.c +10234 -0
- package/vendor/mbedtls/library/ssl_tls12_client.c +3688 -0
- package/vendor/mbedtls/library/ssl_tls12_server.c +4311 -0
- package/vendor/mbedtls/library/ssl_tls13_client.c +3208 -0
- package/vendor/mbedtls/library/ssl_tls13_generic.c +1793 -0
- package/vendor/mbedtls/library/ssl_tls13_invasive.h +23 -0
- package/vendor/mbedtls/library/ssl_tls13_keys.c +1918 -0
- package/vendor/mbedtls/library/ssl_tls13_keys.h +668 -0
- package/vendor/mbedtls/library/ssl_tls13_server.c +3624 -0
- package/vendor/mbedtls/library/threading.c +193 -0
- package/vendor/mbedtls/library/threading_internal.h +28 -0
- package/vendor/mbedtls/library/timing.c +152 -0
- package/vendor/mbedtls/library/version.c +32 -0
- package/vendor/mbedtls/library/version_features.c +856 -0
- package/vendor/mbedtls/library/x509.c +1776 -0
- package/vendor/mbedtls/library/x509_create.c +570 -0
- package/vendor/mbedtls/library/x509_crl.c +708 -0
- package/vendor/mbedtls/library/x509_crt.c +3311 -0
- package/vendor/mbedtls/library/x509_csr.c +648 -0
- package/vendor/mbedtls/library/x509_internal.h +101 -0
- package/vendor/mbedtls/library/x509write.c +174 -0
- package/vendor/mbedtls/library/x509write_crt.c +688 -0
- package/vendor/mbedtls/library/x509write_csr.c +336 -0
- package/vendor/quickjs-ng/CMakeLists.txt +566 -0
- package/vendor/quickjs-ng/LICENSE +24 -0
- package/vendor/quickjs-ng/README.md +24 -0
- package/vendor/quickjs-ng/api-test.c +1195 -0
- package/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/vendor/quickjs-ng/cutils.h +1998 -0
- package/vendor/quickjs-ng/dtoa.c +1619 -0
- package/vendor/quickjs-ng/dtoa.h +87 -0
- package/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/vendor/quickjs-ng/gen/hello.c +53 -0
- package/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/vendor/quickjs-ng/gen/repl.c +3036 -0
- package/vendor/quickjs-ng/gen/standalone.c +323 -0
- package/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/vendor/quickjs-ng/libregexp-opcode.h +73 -0
- package/vendor/quickjs-ng/libregexp.c +3474 -0
- package/vendor/quickjs-ng/libregexp.h +101 -0
- package/vendor/quickjs-ng/libunicode-table.h +5173 -0
- package/vendor/quickjs-ng/libunicode.c +2069 -0
- package/vendor/quickjs-ng/libunicode.h +172 -0
- package/vendor/quickjs-ng/list.h +107 -0
- package/vendor/quickjs-ng/lre-test.c +52 -0
- package/vendor/quickjs-ng/qjs.c +762 -0
- package/vendor/quickjs-ng/qjsc.c +673 -0
- package/vendor/quickjs-ng/quickjs-atom.h +280 -0
- package/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/vendor/quickjs-ng/quickjs-libc.c +5037 -0
- package/vendor/quickjs-ng/quickjs-libc.h +87 -0
- package/vendor/quickjs-ng/quickjs-opcode.h +377 -0
- package/vendor/quickjs-ng/quickjs.c +64041 -0
- package/vendor/quickjs-ng/quickjs.h +1447 -0
- package/vendor/quickjs-ng/run-test262.c +2374 -0
- package/vendor/quickjs-ng/unicode_gen.c +3121 -0
- package/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/vendor/ryu/LICENSE-Boost +23 -0
- package/vendor/ryu/common.h +114 -0
- package/vendor/ryu/d2s.c +509 -0
- package/vendor/ryu/d2s_full_table.h +367 -0
- package/vendor/ryu/d2s_intrinsics.h +357 -0
- package/vendor/ryu/d2s_small_table.h +186 -0
- package/vendor/ryu/digit_table.h +35 -0
- package/vendor/ryu/ryu.h +46 -0
- package/vendor/zlib/LICENSE +22 -0
- package/vendor/zlib/adler32.c +164 -0
- package/vendor/zlib/compress.c +75 -0
- package/vendor/zlib/crc32.c +1049 -0
- package/vendor/zlib/crc32.h +9446 -0
- package/vendor/zlib/deflate.c +2139 -0
- package/vendor/zlib/deflate.h +377 -0
- package/vendor/zlib/gzclose.c +23 -0
- package/vendor/zlib/gzguts.h +214 -0
- package/vendor/zlib/gzlib.c +582 -0
- package/vendor/zlib/gzread.c +602 -0
- package/vendor/zlib/gzwrite.c +631 -0
- package/vendor/zlib/infback.c +628 -0
- package/vendor/zlib/inffast.c +320 -0
- package/vendor/zlib/inffast.h +11 -0
- package/vendor/zlib/inffixed.h +94 -0
- package/vendor/zlib/inflate.c +1526 -0
- package/vendor/zlib/inflate.h +126 -0
- package/vendor/zlib/inftrees.c +299 -0
- package/vendor/zlib/inftrees.h +62 -0
- package/vendor/zlib/trees.c +1117 -0
- package/vendor/zlib/trees.h +128 -0
- package/vendor/zlib/uncompr.c +85 -0
- package/vendor/zlib/zconf.h +543 -0
- package/vendor/zlib/zlib.h +1938 -0
- package/vendor/zlib/zutil.c +299 -0
- package/vendor/zlib/zutil.h +254 -0
- package/README.md +0 -3
- package/index.js +0 -2
package/src/scr_regex.c
ADDED
|
@@ -0,0 +1,1080 @@
|
|
|
1
|
+
/* Regular expressions (see scr_runtime.h for the API contract).
|
|
2
|
+
*
|
|
3
|
+
* The engine is quickjs-ng's libregexp — the exact ECMAScript regex
|
|
4
|
+
* implementation the dynamic island uses — compiled standalone (libregexp.c
|
|
5
|
+
* + libunicode.c; cutils is header-only) and linked ONLY into programs that
|
|
6
|
+
* contain a regex literal. This file is likewise regex-only: it is NOT in
|
|
7
|
+
* the always-compiled runtime source list (see cc.ts), so regex-free
|
|
8
|
+
* programs keep a byte-identical link line.
|
|
9
|
+
*
|
|
10
|
+
* - Every ScrRegex today is an immortal interned literal (the compiler
|
|
11
|
+
* emits one static per distinct (pattern, flags) pair, like string
|
|
12
|
+
* literals). The pattern is compiled to bytecode LAZILY on first use and
|
|
13
|
+
* cached on the struct; a pattern lre_compile rejects aborts with a clear
|
|
14
|
+
* message (Node throws SyntaxError at parse time — documented divergence;
|
|
15
|
+
* rare, since tsc's parser has already syntax-checked the literal).
|
|
16
|
+
* - Subjects are matched as UTF-16: lre_exec runs over a per-call
|
|
17
|
+
* conversion of the UTF-8 subject (cbuf_type 1), so every index libregexp
|
|
18
|
+
* reports is a UTF-16 code-unit index — .length/slice/charCodeAt exact,
|
|
19
|
+
* like Node. Correctness-first: the conversion is O(n) per call.
|
|
20
|
+
* - Match loops mirror quickjs.c's own (JS_RegExpDelete /
|
|
21
|
+
* js_regexp_Symbol_replace): capture buffers are sized by
|
|
22
|
+
* lre_get_alloc_count (NOT capture_count*2 — the executor writes
|
|
23
|
+
* temporary registers past the capture slots), unmatched groups leave
|
|
24
|
+
* NULL pointers, and zero-length matches advance by one code unit — or by
|
|
25
|
+
* a whole surrogate pair under /u (AdvanceStringIndex).
|
|
26
|
+
* - Statefulness fence: /g regexes carry mutable lastIndex in JS. This
|
|
27
|
+
* slice supports /g (and /y) only where the iteration is internal —
|
|
28
|
+
* replace/replaceAll/split; test() on a g/y-flagged regex aborts with a
|
|
29
|
+
* clear message (the frontend already rejects the cases it can see).
|
|
30
|
+
*/
|
|
31
|
+
#include "scr_runtime.h"
|
|
32
|
+
|
|
33
|
+
#include <stdio.h>
|
|
34
|
+
#include <stdlib.h>
|
|
35
|
+
#include <string.h>
|
|
36
|
+
|
|
37
|
+
#include "libregexp.h"
|
|
38
|
+
|
|
39
|
+
static void scr_regex_oom(void) {
|
|
40
|
+
fputs("scriptc: out of memory\n", stderr);
|
|
41
|
+
abort();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ── libregexp host hooks ─────────────────────────────────────────────
|
|
45
|
+
* Static builds provide the minimal hooks (malloc-backed, no interrupt,
|
|
46
|
+
* no stack guard — patterns come from source literals and the executor's
|
|
47
|
+
* backtrack stack is heap-allocated). --dynamic builds MUST NOT define
|
|
48
|
+
* them: the engine archive's quickjs.c already does, with the opaque
|
|
49
|
+
* interpreted as the island's JSContext — so under SCR_DYNAMIC every
|
|
50
|
+
* lre_compile/lre_exec call here passes the island's context instead
|
|
51
|
+
* (forcing lazy engine init on first regex use).
|
|
52
|
+
*/
|
|
53
|
+
#ifdef SCR_DYNAMIC
|
|
54
|
+
static void *lre_opaque(void) { return scr_island_lre_opaque(); }
|
|
55
|
+
#else
|
|
56
|
+
static void *lre_opaque(void) { return NULL; }
|
|
57
|
+
|
|
58
|
+
bool lre_check_stack_overflow(void *opaque, size_t alloca_size) {
|
|
59
|
+
(void)opaque;
|
|
60
|
+
(void)alloca_size;
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
int lre_check_timeout(void *opaque) {
|
|
65
|
+
(void)opaque;
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
void *lre_realloc(void *opaque, void *ptr, size_t size) {
|
|
70
|
+
(void)opaque;
|
|
71
|
+
if (size == 0) {
|
|
72
|
+
free(ptr);
|
|
73
|
+
return NULL;
|
|
74
|
+
}
|
|
75
|
+
return realloc(ptr, size);
|
|
76
|
+
}
|
|
77
|
+
#endif /* SCR_DYNAMIC */
|
|
78
|
+
|
|
79
|
+
/* ── lazy compilation ─────────────────────────────────────────────────
|
|
80
|
+
* Compiled bytecodes are cached on the immortal ScrRegex statics and freed
|
|
81
|
+
* at exit through lre_realloc (registered AFTER the first compile, so under
|
|
82
|
+
* --dynamic it runs before the LIFO-later island teardown and the island's
|
|
83
|
+
* allocation audit sees the bytecode gone).
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
static ScrRegex **scr_compiled = NULL;
|
|
87
|
+
static size_t scr_compiled_len = 0, scr_compiled_cap = 0;
|
|
88
|
+
|
|
89
|
+
static void scr_regex_free_bytecodes(void) {
|
|
90
|
+
for (size_t i = 0; i < scr_compiled_len; i++) {
|
|
91
|
+
lre_realloc(lre_opaque(), scr_compiled[i]->bc, 0);
|
|
92
|
+
scr_compiled[i]->bc = NULL;
|
|
93
|
+
}
|
|
94
|
+
free(scr_compiled);
|
|
95
|
+
scr_compiled = NULL;
|
|
96
|
+
scr_compiled_len = scr_compiled_cap = 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static void scr_note_compiled(ScrRegex *re) {
|
|
100
|
+
if (scr_compiled_len == scr_compiled_cap) {
|
|
101
|
+
scr_compiled_cap = scr_compiled_cap ? scr_compiled_cap * 2 : 8;
|
|
102
|
+
scr_compiled = realloc(scr_compiled, scr_compiled_cap * sizeof *scr_compiled);
|
|
103
|
+
if (!scr_compiled) scr_regex_oom();
|
|
104
|
+
}
|
|
105
|
+
if (scr_compiled_len == 0) atexit(scr_regex_free_bytecodes);
|
|
106
|
+
scr_compiled[scr_compiled_len++] = re;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Flags string → LRE_FLAG_* mask. The frontend fences the flag alphabet to
|
|
110
|
+
* g/i/m/s/u/y, so anything else here is a compiler bug. */
|
|
111
|
+
static int scr_lre_flags(const ScrStr *flags) {
|
|
112
|
+
int mask = 0;
|
|
113
|
+
for (size_t i = 0; i < flags->len; i++) {
|
|
114
|
+
switch (flags->data[i]) {
|
|
115
|
+
case 'g': mask |= LRE_FLAG_GLOBAL; break;
|
|
116
|
+
case 'i': mask |= LRE_FLAG_IGNORECASE; break;
|
|
117
|
+
case 'm': mask |= LRE_FLAG_MULTILINE; break;
|
|
118
|
+
case 's': mask |= LRE_FLAG_DOTALL; break;
|
|
119
|
+
case 'u': mask |= LRE_FLAG_UNICODE; break;
|
|
120
|
+
case 'y': mask |= LRE_FLAG_STICKY; break;
|
|
121
|
+
default:
|
|
122
|
+
fprintf(stderr, "scriptc: internal error: unexpected regex flag '%c'\n",
|
|
123
|
+
flags->data[i]);
|
|
124
|
+
abort();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return mask;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Without /u, JS treats the pattern itself as UTF-16 code units: an astral
|
|
131
|
+
* character in the pattern SOURCE is two separate surrogate units.
|
|
132
|
+
* libregexp expects that spelled as CESU-8 (quickjs feeds it
|
|
133
|
+
* JS_ToCStringLen2(cesu8=true) for non-unicode patterns), so a non-/u
|
|
134
|
+
* pattern containing a 4-byte UTF-8 sequence is re-encoded: each astral
|
|
135
|
+
* code point becomes two 3-byte surrogate encodings. Returns NULL when the
|
|
136
|
+
* pattern needs no re-encoding (the common case — no copy). */
|
|
137
|
+
static char *scr_pattern_cesu8(const ScrStr *src, size_t *plen) {
|
|
138
|
+
bool has_astral = false;
|
|
139
|
+
for (size_t i = 0; i < src->len; i++) {
|
|
140
|
+
if ((unsigned char)src->data[i] >= 0xF0) {
|
|
141
|
+
has_astral = true;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (!has_astral) return NULL;
|
|
146
|
+
char *out = malloc(src->len / 2 * 3 + src->len + 1); /* 4 bytes → 6 worst case */
|
|
147
|
+
if (!out) scr_regex_oom();
|
|
148
|
+
size_t o = 0;
|
|
149
|
+
for (size_t i = 0; i < src->len;) {
|
|
150
|
+
unsigned char c = (unsigned char)src->data[i];
|
|
151
|
+
if (c < 0xF0) {
|
|
152
|
+
out[o++] = src->data[i++];
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
uint32_t cp = ((uint32_t)(c & 0x07) << 18) |
|
|
156
|
+
((uint32_t)((unsigned char)src->data[i + 1] & 0x3F) << 12) |
|
|
157
|
+
((uint32_t)((unsigned char)src->data[i + 2] & 0x3F) << 6) |
|
|
158
|
+
((unsigned char)src->data[i + 3] & 0x3F);
|
|
159
|
+
i += 4;
|
|
160
|
+
uint32_t hi = 0xD800 + ((cp - 0x10000) >> 10);
|
|
161
|
+
uint32_t lo = 0xDC00 + ((cp - 0x10000) & 0x3FF);
|
|
162
|
+
out[o++] = (char)(0xE0 | (hi >> 12));
|
|
163
|
+
out[o++] = (char)(0x80 | ((hi >> 6) & 0x3F));
|
|
164
|
+
out[o++] = (char)(0x80 | (hi & 0x3F));
|
|
165
|
+
out[o++] = (char)(0xE0 | (lo >> 12));
|
|
166
|
+
out[o++] = (char)(0x80 | ((lo >> 6) & 0x3F));
|
|
167
|
+
out[o++] = (char)(0x80 | (lo & 0x3F));
|
|
168
|
+
}
|
|
169
|
+
/* lre_compile needs the NUL sentinel in ADDITION to buf_len: quickjs
|
|
170
|
+
* always hands it NUL-terminated C strings, and the parser reads *p
|
|
171
|
+
* against '\0' at end-of-pattern (found the hard way — an unterminated
|
|
172
|
+
* buffer reports "extraneous characters at the end"). */
|
|
173
|
+
out[o] = '\0';
|
|
174
|
+
*plen = o;
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* The compiled bytecode, compiling (and caching) on first use. */
|
|
179
|
+
static uint8_t *scr_regex_bc(ScrRegex *re) {
|
|
180
|
+
if (re->bc) return re->bc;
|
|
181
|
+
int flags = scr_lre_flags(re->flags);
|
|
182
|
+
const char *pat = re->source->data;
|
|
183
|
+
size_t pat_len = re->source->len;
|
|
184
|
+
char *cesu = NULL;
|
|
185
|
+
if (!(flags & LRE_FLAG_UNICODE)) {
|
|
186
|
+
cesu = scr_pattern_cesu8(re->source, &pat_len);
|
|
187
|
+
if (cesu) pat = cesu;
|
|
188
|
+
}
|
|
189
|
+
char error_msg[64];
|
|
190
|
+
int bc_len;
|
|
191
|
+
uint8_t *bc = lre_compile(&bc_len, error_msg, sizeof error_msg, pat, pat_len,
|
|
192
|
+
flags, lre_opaque());
|
|
193
|
+
free(cesu);
|
|
194
|
+
if (!bc) {
|
|
195
|
+
/* Node rejects the pattern with a SyntaxError at PARSE time; scriptc
|
|
196
|
+
* compiles lazily, so the failure lands here (documented divergence —
|
|
197
|
+
* tsc's parser has already caught plain syntax errors, so this is
|
|
198
|
+
* rare). */
|
|
199
|
+
fflush(stdout);
|
|
200
|
+
fprintf(stderr, "scriptc: SyntaxError: Invalid regular expression: /%s/%s: %s\n",
|
|
201
|
+
re->source->data, re->flags->data, error_msg);
|
|
202
|
+
abort();
|
|
203
|
+
}
|
|
204
|
+
re->bc = bc;
|
|
205
|
+
scr_note_compiled(re);
|
|
206
|
+
return bc;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* ── RC entry points ──────────────────────────────────────────────────
|
|
210
|
+
* Dead paths today (every regex value is an immortal interned literal);
|
|
211
|
+
* correct anyway so dynamic construction can arrive without surprises. */
|
|
212
|
+
|
|
213
|
+
void scr_regex_release(ScrRegex *re) {
|
|
214
|
+
if (!re || re->rc == SIZE_MAX) return;
|
|
215
|
+
if (--re->rc == 0) {
|
|
216
|
+
scr_str_release(re->source);
|
|
217
|
+
scr_str_release(re->flags);
|
|
218
|
+
if (re->bc) lre_realloc(lre_opaque(), re->bc, 0);
|
|
219
|
+
free(re);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
void *scr_regex_retain_v(void *re) { return scr_regex_retain(re); }
|
|
224
|
+
void scr_regex_release_v(void *re) { scr_regex_release(re); }
|
|
225
|
+
|
|
226
|
+
ScrStr *scr_regex_source(ScrRegex *re) { return scr_str_retain(re->source); }
|
|
227
|
+
ScrStr *scr_regex_flags(ScrRegex *re) { return scr_str_retain(re->flags); }
|
|
228
|
+
|
|
229
|
+
/* ── UTF-8 ⇄ UTF-16 (the exec buffer strategy) ──────────────────────── */
|
|
230
|
+
|
|
231
|
+
/* Subject as freshly-malloc'd UTF-16 code units (strings are well-formed
|
|
232
|
+
* UTF-8, so no validation). Unit count ≤ byte count. */
|
|
233
|
+
static uint16_t *scr_to_utf16(const ScrStr *s, int *plen) {
|
|
234
|
+
uint16_t *u = malloc((s->len ? s->len : 1) * sizeof(uint16_t));
|
|
235
|
+
if (!u) scr_regex_oom();
|
|
236
|
+
int n = 0;
|
|
237
|
+
for (size_t i = 0; i < s->len;) {
|
|
238
|
+
unsigned char c = (unsigned char)s->data[i];
|
|
239
|
+
uint32_t cp;
|
|
240
|
+
if (c < 0x80) {
|
|
241
|
+
cp = c;
|
|
242
|
+
i += 1;
|
|
243
|
+
} else if (c < 0xE0) {
|
|
244
|
+
cp = ((uint32_t)(c & 0x1F) << 6) | ((unsigned char)s->data[i + 1] & 0x3F);
|
|
245
|
+
i += 2;
|
|
246
|
+
} else if (c < 0xF0) {
|
|
247
|
+
cp = ((uint32_t)(c & 0x0F) << 12) |
|
|
248
|
+
((uint32_t)((unsigned char)s->data[i + 1] & 0x3F) << 6) |
|
|
249
|
+
((unsigned char)s->data[i + 2] & 0x3F);
|
|
250
|
+
i += 3;
|
|
251
|
+
} else {
|
|
252
|
+
cp = ((uint32_t)(c & 0x07) << 18) |
|
|
253
|
+
((uint32_t)((unsigned char)s->data[i + 1] & 0x3F) << 12) |
|
|
254
|
+
((uint32_t)((unsigned char)s->data[i + 2] & 0x3F) << 6) |
|
|
255
|
+
((unsigned char)s->data[i + 3] & 0x3F);
|
|
256
|
+
i += 4;
|
|
257
|
+
}
|
|
258
|
+
if (cp >= 0x10000) {
|
|
259
|
+
u[n++] = (uint16_t)(0xD800 + ((cp - 0x10000) >> 10));
|
|
260
|
+
u[n++] = (uint16_t)(0xDC00 + ((cp - 0x10000) & 0x3FF));
|
|
261
|
+
} else {
|
|
262
|
+
u[n++] = (uint16_t)cp;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
*plen = n;
|
|
266
|
+
return u;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* Append u[start..end) as UTF-8. A lone surrogate (a non-/u match boundary
|
|
270
|
+
* split an astral pair) becomes U+FFFD — the house rule for JS results that
|
|
271
|
+
* are not well-formed UTF-16 (same divergence class as charAt/slice,
|
|
272
|
+
* SEMANTICS.md). */
|
|
273
|
+
static void scr_jb_put_utf16(ScrJsonBuf *b, const uint16_t *u, int start, int end) {
|
|
274
|
+
for (int i = start; i < end; i++) {
|
|
275
|
+
uint32_t cp = u[i];
|
|
276
|
+
if (cp >= 0xD800 && cp < 0xDC00 && i + 1 < end && u[i + 1] >= 0xDC00 &&
|
|
277
|
+
u[i + 1] < 0xE000) {
|
|
278
|
+
cp = 0x10000 + ((cp - 0xD800) << 10) + (u[i + 1] - 0xDC00);
|
|
279
|
+
i++;
|
|
280
|
+
} else if (cp >= 0xD800 && cp < 0xE000) {
|
|
281
|
+
cp = 0xFFFD;
|
|
282
|
+
}
|
|
283
|
+
if (cp < 0x80) {
|
|
284
|
+
scr_jb_putc(b, (char)cp);
|
|
285
|
+
} else if (cp < 0x800) {
|
|
286
|
+
scr_jb_putc(b, (char)(0xC0 | (cp >> 6)));
|
|
287
|
+
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
288
|
+
} else if (cp < 0x10000) {
|
|
289
|
+
scr_jb_putc(b, (char)(0xE0 | (cp >> 12)));
|
|
290
|
+
scr_jb_putc(b, (char)(0x80 | ((cp >> 6) & 0x3F)));
|
|
291
|
+
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
292
|
+
} else {
|
|
293
|
+
scr_jb_putc(b, (char)(0xF0 | (cp >> 18)));
|
|
294
|
+
scr_jb_putc(b, (char)(0x80 | ((cp >> 12) & 0x3F)));
|
|
295
|
+
scr_jb_putc(b, (char)(0x80 | ((cp >> 6) & 0x3F)));
|
|
296
|
+
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
static ScrStr *scr_str_from_utf16(const uint16_t *u, int start, int end) {
|
|
302
|
+
ScrJsonBuf b;
|
|
303
|
+
scr_jb_init(&b);
|
|
304
|
+
scr_jb_put_utf16(&b, u, start, end);
|
|
305
|
+
return scr_jb_finish(&b);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* ── exec plumbing ────────────────────────────────────────────────────── */
|
|
309
|
+
|
|
310
|
+
/* One lre_exec over the UTF-16 subject. Returns 1 (match), 0 (no match);
|
|
311
|
+
* engine-level failures (OOM, corrupt bytecode — no timeout handler is
|
|
312
|
+
* installed) abort like every runtime OOM. */
|
|
313
|
+
static int scr_exec(uint8_t **capture, const uint8_t *bc, const uint16_t *u,
|
|
314
|
+
int index, int len) {
|
|
315
|
+
int rc = lre_exec(capture, bc, (const uint8_t *)u, index, len, 1, lre_opaque());
|
|
316
|
+
if (rc < 0) {
|
|
317
|
+
fflush(stdout);
|
|
318
|
+
fputs("scriptc: regular expression execution failed\n", stderr);
|
|
319
|
+
abort();
|
|
320
|
+
}
|
|
321
|
+
return rc;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* Capture buffer sized by lre_get_alloc_count: the register-based executor
|
|
325
|
+
* writes temporary registers past the capture pairs (quickjs.c documents
|
|
326
|
+
* sizing by capture_count*2 as a silent heap overflow). */
|
|
327
|
+
static uint8_t **scr_capture_alloc(const uint8_t *bc) {
|
|
328
|
+
int n = lre_get_alloc_count(bc);
|
|
329
|
+
uint8_t **cap = malloc((n > 0 ? (size_t)n : 1) * sizeof *cap);
|
|
330
|
+
if (!cap) scr_regex_oom();
|
|
331
|
+
return cap;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/* ECMA-262 AdvanceStringIndex: past a whole surrogate pair under /u, one
|
|
335
|
+
* code unit otherwise — the rule that keeps zero-length matches from
|
|
336
|
+
* looping forever. */
|
|
337
|
+
static int scr_advance(const uint16_t *u, int len, int i, bool unicode) {
|
|
338
|
+
if (unicode && i + 1 < len && u[i] >= 0xD800 && u[i] < 0xDC00 &&
|
|
339
|
+
u[i + 1] >= 0xDC00 && u[i + 1] < 0xE000) {
|
|
340
|
+
return i + 2;
|
|
341
|
+
}
|
|
342
|
+
return i + 1;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* ── test ─────────────────────────────────────────────────────────────── */
|
|
346
|
+
|
|
347
|
+
bool scr_regex_test(ScrRegex *re, ScrStr *s) {
|
|
348
|
+
uint8_t *bc = scr_regex_bc(re);
|
|
349
|
+
if (lre_get_flags(bc) & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
|
|
350
|
+
/* JS test() on a g/y regex reads AND writes lastIndex — stateful
|
|
351
|
+
* iteration this slice does not model (the frontend rejects the sites
|
|
352
|
+
* it can see; values that flow through variables land here). */
|
|
353
|
+
fflush(stdout);
|
|
354
|
+
fprintf(stderr,
|
|
355
|
+
"scriptc: test() on a regex with the 'g' or 'y' flag is not "
|
|
356
|
+
"supported (stateful lastIndex); drop the flag, or use "
|
|
357
|
+
"replace/replaceAll/split\n");
|
|
358
|
+
abort();
|
|
359
|
+
}
|
|
360
|
+
int len;
|
|
361
|
+
uint16_t *u = scr_to_utf16(s, &len);
|
|
362
|
+
uint8_t **capture = scr_capture_alloc(bc);
|
|
363
|
+
int rc = scr_exec(capture, bc, u, 0, len);
|
|
364
|
+
free(capture);
|
|
365
|
+
free(u);
|
|
366
|
+
return rc == 1;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/* ── match ────────────────────────────────────────────────────────────── */
|
|
370
|
+
|
|
371
|
+
/* s.match(re) for non-g/y regexes: Node's exec-shaped result reduced to
|
|
372
|
+
* the honest slice — a fresh string[] of [whole match, ...captures], or
|
|
373
|
+
* NULL for no match (the compiler wraps the `string[] | null` union). A
|
|
374
|
+
* NONPARTICIPATING capture holds "" where Node's slot is undefined
|
|
375
|
+
* (truthiness tests agree; SEMANTICS.md documents the divergence). g/y
|
|
376
|
+
* regexes abort like test() — a g-flagged match returns EVERY match, a
|
|
377
|
+
* different shape the frontend fences on literals. */
|
|
378
|
+
ScrArr *scr_regex_match(ScrStr *s, ScrRegex *re) {
|
|
379
|
+
uint8_t *bc = scr_regex_bc(re);
|
|
380
|
+
if (lre_get_flags(bc) & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
|
|
381
|
+
fflush(stdout);
|
|
382
|
+
fprintf(stderr,
|
|
383
|
+
"scriptc: match() on a regex with the 'g' or 'y' flag is not "
|
|
384
|
+
"supported (an every-match array is a different shape); drop the "
|
|
385
|
+
"flag, or use replace/replaceAll/split\n");
|
|
386
|
+
abort();
|
|
387
|
+
}
|
|
388
|
+
int len;
|
|
389
|
+
uint16_t *u = scr_to_utf16(s, &len);
|
|
390
|
+
uint8_t **capture = scr_capture_alloc(bc);
|
|
391
|
+
int rc = scr_exec(capture, bc, u, 0, len);
|
|
392
|
+
ScrArr *out = NULL;
|
|
393
|
+
if (rc == 1) {
|
|
394
|
+
const uint8_t *ubase = (const uint8_t *)u;
|
|
395
|
+
int count = lre_get_capture_count(bc);
|
|
396
|
+
out = scr_arr_new(SCR_ELEM_STR, (size_t)count);
|
|
397
|
+
for (int k = 0; k < count; k++) {
|
|
398
|
+
const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
|
|
399
|
+
if (cs == NULL || ce == NULL) {
|
|
400
|
+
scr_arr_push_ref(out, scr_str_new("", 0));
|
|
401
|
+
} else {
|
|
402
|
+
scr_arr_push_ref(
|
|
403
|
+
out, scr_str_from_utf16(u, (int)((cs - ubase) >> 1), (int)((ce - ubase) >> 1)));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
free(capture);
|
|
408
|
+
free(u);
|
|
409
|
+
return out; /* +1, or NULL (no match) */
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/* ── search ───────────────────────────────────────────────────────────── */
|
|
413
|
+
|
|
414
|
+
/* s.search(re): the first match's UTF-16 index, or -1 — Symbol.search's
|
|
415
|
+
* fresh exec from position 0. lastIndex is neither read nor written in JS
|
|
416
|
+
* (the spec saves and restores it), so no flag fence applies here, unlike
|
|
417
|
+
* test/match: /g is irrelevant and /y anchors at 0 (libregexp's sticky
|
|
418
|
+
* bytecode omits the implicit forward scan) — exactly Node. */
|
|
419
|
+
double scr_regex_search(ScrStr *s, ScrRegex *re) {
|
|
420
|
+
uint8_t *bc = scr_regex_bc(re);
|
|
421
|
+
int len;
|
|
422
|
+
uint16_t *u = scr_to_utf16(s, &len);
|
|
423
|
+
uint8_t **capture = scr_capture_alloc(bc);
|
|
424
|
+
int rc = scr_exec(capture, bc, u, 0, len);
|
|
425
|
+
double out = -1;
|
|
426
|
+
if (rc == 1) out = (double)((capture[0] - (const uint8_t *)u) >> 1);
|
|
427
|
+
free(capture);
|
|
428
|
+
free(u);
|
|
429
|
+
return out;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/* matchAll(re): every match as its honest slice string[] (whole match +
|
|
433
|
+
* captures, nonparticipating = "" — match()'s rule) drained EAGERLY into
|
|
434
|
+
* a fresh string[][]. The lazy iterator is unobservable across the
|
|
435
|
+
* lowered surface: strings are immutable and the spec clones the regex at
|
|
436
|
+
* the call, so nothing can perturb the drain. Non-global regexes throw
|
|
437
|
+
* Node's exact TypeError (catchable — replaceAll's stance). Empty matches
|
|
438
|
+
* advance one unit, unicode-aware (AdvanceStringIndex). `indices`, when
|
|
439
|
+
* non-NULL, receives each match's UTF-16 start index (the row's .index —
|
|
440
|
+
* the companion array the for-of-over-matchAll desugar reads). */
|
|
441
|
+
static ScrArr *scr_regex_match_all_core(ScrStr *s, ScrRegex *re, ScrArr *indices) {
|
|
442
|
+
uint8_t *bc = scr_regex_bc(re);
|
|
443
|
+
int re_flags = lre_get_flags(bc);
|
|
444
|
+
if (!(re_flags & LRE_FLAG_GLOBAL)) {
|
|
445
|
+
static const char msg[] =
|
|
446
|
+
"String.prototype.matchAll called with a non-global RegExp argument";
|
|
447
|
+
scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1);
|
|
448
|
+
return NULL; /* callers are compiler-emitted pending checks */
|
|
449
|
+
}
|
|
450
|
+
bool unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
451
|
+
int capture_count = lre_get_capture_count(bc);
|
|
452
|
+
int len;
|
|
453
|
+
uint16_t *u = scr_to_utf16(s, &len);
|
|
454
|
+
uint8_t **capture = scr_capture_alloc(bc);
|
|
455
|
+
const uint8_t *ubase = (const uint8_t *)u;
|
|
456
|
+
ScrArr *out = scr_arr_new(SCR_ELEM_ARR, 4);
|
|
457
|
+
int pos = 0;
|
|
458
|
+
while (pos <= len) {
|
|
459
|
+
if (scr_exec(capture, bc, u, pos, len) != 1) break;
|
|
460
|
+
int start = (int)((capture[0] - ubase) >> 1);
|
|
461
|
+
int end = (int)((capture[1] - ubase) >> 1);
|
|
462
|
+
ScrArr *row = scr_arr_new(SCR_ELEM_STR, (size_t)capture_count);
|
|
463
|
+
for (int k = 0; k < capture_count; k++) {
|
|
464
|
+
const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
|
|
465
|
+
if (cs == NULL || ce == NULL) {
|
|
466
|
+
scr_arr_push_ref(row, scr_str_new("", 0));
|
|
467
|
+
} else {
|
|
468
|
+
scr_arr_push_ref(
|
|
469
|
+
row, scr_str_from_utf16(u, (int)((cs - ubase) >> 1), (int)((ce - ubase) >> 1)));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
scr_arr_push_ref(out, row);
|
|
473
|
+
if (indices != NULL) scr_arr_push_f64(indices, (double)start);
|
|
474
|
+
pos = end == start ? scr_advance(u, len, end, unicode) : end;
|
|
475
|
+
}
|
|
476
|
+
free(capture);
|
|
477
|
+
free(u);
|
|
478
|
+
return out; /* +1 (possibly empty — Node's no-match drain is []) */
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
ScrArr *scr_regex_match_all(ScrStr *s, ScrRegex *re) {
|
|
482
|
+
return scr_regex_match_all_core(s, re, NULL);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
ScrArr *scr_regex_match_all_into(ScrStr *s, ScrRegex *re, ScrArr *indices) {
|
|
486
|
+
return scr_regex_match_all_core(s, re, indices);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* ── replace / replaceAll ─────────────────────────────────────────────── */
|
|
490
|
+
|
|
491
|
+
/* ECMA-262 GetSubstitution over the replacement TEMPLATE (function
|
|
492
|
+
* replacements are frontend-fenced): $$, $&, $` and $', $1..$99 (two digits
|
|
493
|
+
* win when in range — the refined ES2019 rule quickjs implements), with
|
|
494
|
+
* out-of-range references left literal and unmatched groups substituting
|
|
495
|
+
* empty. $<name> stays literal: named capture groups are frontend-fenced,
|
|
496
|
+
* so namedCaptures is always undefined here (the spec's literal case).
|
|
497
|
+
* The template is scanned byte-wise: every '$' directive is ASCII, and
|
|
498
|
+
* UTF-8 continuation bytes can never alias it. */
|
|
499
|
+
static void scr_put_substitution(ScrJsonBuf *b, const uint16_t *u, int len,
|
|
500
|
+
int start, int end, uint8_t **capture,
|
|
501
|
+
int capture_count, const ScrStr *rep) {
|
|
502
|
+
const uint8_t *ubase = (const uint8_t *)u;
|
|
503
|
+
size_t i = 0;
|
|
504
|
+
while (i < rep->len) {
|
|
505
|
+
char c = rep->data[i];
|
|
506
|
+
if (c != '$' || i + 1 >= rep->len) {
|
|
507
|
+
scr_jb_putc(b, c);
|
|
508
|
+
i++;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
char c1 = rep->data[i + 1];
|
|
512
|
+
if (c1 == '$') {
|
|
513
|
+
scr_jb_putc(b, '$');
|
|
514
|
+
i += 2;
|
|
515
|
+
} else if (c1 == '&') {
|
|
516
|
+
scr_jb_put_utf16(b, u, start, end);
|
|
517
|
+
i += 2;
|
|
518
|
+
} else if (c1 == '`') {
|
|
519
|
+
scr_jb_put_utf16(b, u, 0, start);
|
|
520
|
+
i += 2;
|
|
521
|
+
} else if (c1 == '\'') {
|
|
522
|
+
scr_jb_put_utf16(b, u, end, len);
|
|
523
|
+
i += 2;
|
|
524
|
+
} else if (c1 >= '0' && c1 <= '9') {
|
|
525
|
+
int k = c1 - '0';
|
|
526
|
+
size_t adv = 2;
|
|
527
|
+
if (i + 2 < rep->len && rep->data[i + 2] >= '0' && rep->data[i + 2] <= '9') {
|
|
528
|
+
int k1 = k * 10 + (rep->data[i + 2] - '0');
|
|
529
|
+
if (k1 >= 1 && k1 < capture_count) {
|
|
530
|
+
k = k1;
|
|
531
|
+
adv = 3;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (k >= 1 && k < capture_count) {
|
|
535
|
+
const uint8_t *cs = capture[2 * k], *ce = capture[2 * k + 1];
|
|
536
|
+
if (cs && ce) {
|
|
537
|
+
scr_jb_put_utf16(b, u, (int)((cs - ubase) >> 1), (int)((ce - ubase) >> 1));
|
|
538
|
+
}
|
|
539
|
+
i += adv;
|
|
540
|
+
} else {
|
|
541
|
+
/* Out of range: the '$' is literal (the digits re-scan verbatim). */
|
|
542
|
+
scr_jb_putc(b, '$');
|
|
543
|
+
i++;
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
scr_jb_putc(b, '$');
|
|
547
|
+
i++;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* The shared match loop (the shape of quickjs's JS_RegExpDelete): search
|
|
553
|
+
* from `pos`, copy the gap, emit the substitution, continue from the match
|
|
554
|
+
* end when global — advancing zero-length matches per AdvanceStringIndex. */
|
|
555
|
+
static ScrStr *scr_replace_impl(ScrStr *s, ScrRegex *re, ScrStr *rep) {
|
|
556
|
+
uint8_t *bc = scr_regex_bc(re);
|
|
557
|
+
int re_flags = lre_get_flags(bc);
|
|
558
|
+
bool global = (re_flags & LRE_FLAG_GLOBAL) != 0;
|
|
559
|
+
bool unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
560
|
+
int capture_count = lre_get_capture_count(bc);
|
|
561
|
+
int len;
|
|
562
|
+
uint16_t *u = scr_to_utf16(s, &len);
|
|
563
|
+
uint8_t **capture = scr_capture_alloc(bc);
|
|
564
|
+
const uint8_t *ubase = (const uint8_t *)u;
|
|
565
|
+
ScrJsonBuf b;
|
|
566
|
+
scr_jb_init(&b);
|
|
567
|
+
int next = 0, pos = 0;
|
|
568
|
+
while (pos <= len) {
|
|
569
|
+
if (scr_exec(capture, bc, u, pos, len) != 1) break;
|
|
570
|
+
int start = (int)((capture[0] - ubase) >> 1);
|
|
571
|
+
int end = (int)((capture[1] - ubase) >> 1);
|
|
572
|
+
scr_jb_put_utf16(&b, u, next, start);
|
|
573
|
+
scr_put_substitution(&b, u, len, start, end, capture, capture_count, rep);
|
|
574
|
+
next = end;
|
|
575
|
+
if (!global) break;
|
|
576
|
+
pos = end == start ? scr_advance(u, len, end, unicode) : end;
|
|
577
|
+
}
|
|
578
|
+
scr_jb_put_utf16(&b, u, next, len);
|
|
579
|
+
free(capture);
|
|
580
|
+
free(u);
|
|
581
|
+
return scr_jb_finish(&b);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
ScrStr *scr_regex_replace(ScrStr *s, ScrRegex *re, ScrStr *rep) {
|
|
585
|
+
return scr_replace_impl(s, re, rep);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
ScrStr *scr_regex_replace_all(ScrStr *s, ScrRegex *re, ScrStr *rep) {
|
|
589
|
+
if (!(lre_get_flags(scr_regex_bc(re)) & LRE_FLAG_GLOBAL)) {
|
|
590
|
+
/* Node's exact TypeError — a real instance now: catch bindings narrow
|
|
591
|
+
* it and e.message carries V8's text byte-for-byte. */
|
|
592
|
+
static const char msg[] =
|
|
593
|
+
"String.prototype.replaceAll called with a non-global RegExp argument";
|
|
594
|
+
scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1);
|
|
595
|
+
return NULL; /* callers are compiler-emitted pending checks */
|
|
596
|
+
}
|
|
597
|
+
return scr_replace_impl(s, re, rep);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/* ── split ────────────────────────────────────────────────────────────── */
|
|
601
|
+
|
|
602
|
+
ScrArr *scr_regex_split(ScrStr *s, ScrRegex *re) {
|
|
603
|
+
uint8_t *bc = scr_regex_bc(re);
|
|
604
|
+
if (lre_get_capture_count(bc) > 1) {
|
|
605
|
+
/* JS splices every capture group's value into the result between the
|
|
606
|
+
* pieces, changing the array's SHAPE per match — not modeled this
|
|
607
|
+
* slice. Catchable, scriptc-specific. */
|
|
608
|
+
static const char msg[] =
|
|
609
|
+
"split() with capture groups in the pattern is not "
|
|
610
|
+
"supported (JS splices the captured values into the result); use a "
|
|
611
|
+
"non-capturing group (?:...)";
|
|
612
|
+
scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1);
|
|
613
|
+
return NULL; /* callers are compiler-emitted pending checks */
|
|
614
|
+
}
|
|
615
|
+
int re_flags = lre_get_flags(bc);
|
|
616
|
+
bool unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;
|
|
617
|
+
bool sticky = (re_flags & LRE_FLAG_STICKY) != 0;
|
|
618
|
+
int len;
|
|
619
|
+
uint16_t *u = scr_to_utf16(s, &len);
|
|
620
|
+
uint8_t **capture = scr_capture_alloc(bc);
|
|
621
|
+
const uint8_t *ubase = (const uint8_t *)u;
|
|
622
|
+
ScrArr *out = scr_arr_new(SCR_ELEM_STR, 0);
|
|
623
|
+
|
|
624
|
+
/* ECMA-262 22.2.6.14 (Symbol.split, no limit). The spec probes every
|
|
625
|
+
* position with a sticky matcher; for non-sticky patterns a forward
|
|
626
|
+
* SEARCH from q is equivalent (the earliest match position >= q is the
|
|
627
|
+
* first probe that would succeed) and one exec replaces the per-position
|
|
628
|
+
* loop. A genuinely sticky pattern keeps the spec's probe-and-advance. */
|
|
629
|
+
if (len == 0) {
|
|
630
|
+
/* Empty subject: one probe — a match yields [], no match yields [""]. */
|
|
631
|
+
if (scr_exec(capture, bc, u, 0, len) != 1) {
|
|
632
|
+
scr_arr_push_ref(out, scr_str_new("", 0));
|
|
633
|
+
}
|
|
634
|
+
free(capture);
|
|
635
|
+
free(u);
|
|
636
|
+
return out;
|
|
637
|
+
}
|
|
638
|
+
int p = 0, q = 0;
|
|
639
|
+
while (q < len) {
|
|
640
|
+
if (scr_exec(capture, bc, u, q, len) != 1) {
|
|
641
|
+
if (!sticky) break; /* no match anywhere right of q */
|
|
642
|
+
q = scr_advance(u, len, q, unicode);
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
int start = (int)((capture[0] - ubase) >> 1);
|
|
646
|
+
int end = (int)((capture[1] - ubase) >> 1);
|
|
647
|
+
if (end == p) {
|
|
648
|
+
/* Zero-length match adjacent to the previous split point: advance
|
|
649
|
+
* (start == q == p here — the search cannot skip a match). */
|
|
650
|
+
q = scr_advance(u, len, start, unicode);
|
|
651
|
+
} else {
|
|
652
|
+
scr_arr_push_ref(out, scr_str_from_utf16(u, p, start));
|
|
653
|
+
p = end;
|
|
654
|
+
q = p;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
scr_arr_push_ref(out, scr_str_from_utf16(u, p, len));
|
|
658
|
+
free(capture);
|
|
659
|
+
free(u);
|
|
660
|
+
return out;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/* ── String.prototype.toLowerCase / toUpperCase (the static path) ──────
|
|
664
|
+
* ECMA-262 Default Case Conversion via the vendored libunicode's
|
|
665
|
+
* lre_case_conv — the exact tables and algorithm the engine's own
|
|
666
|
+
* String.prototype methods run (quickjs.c's js_string_toLowerCase), the
|
|
667
|
+
* context-sensitive Greek final-sigma rule included. Lives HERE, not in
|
|
668
|
+
* scr_string.c, because it needs libunicode: the compiler sets the lre
|
|
669
|
+
* link flag for case-conversion sites exactly like regex nodes, so
|
|
670
|
+
* case-free (and regex-free) programs keep their historical link line.
|
|
671
|
+
* Node runs full ICU case mapping, but for the locale-independent
|
|
672
|
+
* toLowerCase/toUpperCase the two agree — ICU's locale tailorings
|
|
673
|
+
* (Turkish/Azeri dotted I, Lithuanian accent handling) apply only to
|
|
674
|
+
* toLocaleLowerCase with an explicit locale, which stays fenced. The
|
|
675
|
+
* receiver is BORROWED; the result is a fresh +1 string. */
|
|
676
|
+
|
|
677
|
+
/* Decode the code point at p (well-formed UTF-8); *adv gets the length. */
|
|
678
|
+
static uint32_t scr_case_decode(const char *p, size_t *adv) {
|
|
679
|
+
unsigned char c = (unsigned char)p[0];
|
|
680
|
+
if (c < 0x80) {
|
|
681
|
+
*adv = 1;
|
|
682
|
+
return c;
|
|
683
|
+
}
|
|
684
|
+
if (c < 0xE0) {
|
|
685
|
+
*adv = 2;
|
|
686
|
+
return ((uint32_t)(c & 0x1F) << 6) | ((unsigned char)p[1] & 0x3F);
|
|
687
|
+
}
|
|
688
|
+
if (c < 0xF0) {
|
|
689
|
+
*adv = 3;
|
|
690
|
+
return ((uint32_t)(c & 0x0F) << 12) |
|
|
691
|
+
((uint32_t)((unsigned char)p[1] & 0x3F) << 6) |
|
|
692
|
+
((unsigned char)p[2] & 0x3F);
|
|
693
|
+
}
|
|
694
|
+
*adv = 4;
|
|
695
|
+
return ((uint32_t)(c & 0x07) << 18) |
|
|
696
|
+
((uint32_t)((unsigned char)p[1] & 0x3F) << 12) |
|
|
697
|
+
((uint32_t)((unsigned char)p[2] & 0x3F) << 6) |
|
|
698
|
+
((unsigned char)p[3] & 0x3F);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/* Step back one code point from *off (> 0) and decode it. */
|
|
702
|
+
static uint32_t scr_case_prev(const ScrStr *s, size_t *off) {
|
|
703
|
+
size_t i = *off;
|
|
704
|
+
do {
|
|
705
|
+
i--;
|
|
706
|
+
} while (i > 0 && ((unsigned char)s->data[i] & 0xC0) == 0x80);
|
|
707
|
+
*off = i;
|
|
708
|
+
size_t adv;
|
|
709
|
+
return scr_case_decode(s->data + i, &adv);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/* Unicode Final_Sigma: Σ is preceded by a cased letter (after skipping
|
|
713
|
+
* case-ignorable characters) and NOT followed by one — quickjs.c's
|
|
714
|
+
* test_final_sigma over the UTF-8 storage. `next_off` is the byte offset
|
|
715
|
+
* just past the sigma. */
|
|
716
|
+
static bool scr_final_sigma(const ScrStr *s, size_t sigma_off, size_t next_off) {
|
|
717
|
+
size_t k = sigma_off;
|
|
718
|
+
uint32_t c1;
|
|
719
|
+
for (;;) {
|
|
720
|
+
if (k == 0) return false; /* nothing cased before C */
|
|
721
|
+
c1 = scr_case_prev(s, &k);
|
|
722
|
+
if (!lre_is_case_ignorable(c1)) break;
|
|
723
|
+
}
|
|
724
|
+
if (!lre_is_cased(c1)) return false;
|
|
725
|
+
k = next_off;
|
|
726
|
+
for (;;) {
|
|
727
|
+
if (k >= s->len) return true;
|
|
728
|
+
size_t adv;
|
|
729
|
+
c1 = scr_case_decode(s->data + k, &adv);
|
|
730
|
+
k += adv;
|
|
731
|
+
if (!lre_is_case_ignorable(c1)) break;
|
|
732
|
+
}
|
|
733
|
+
return !lre_is_cased(c1);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/* Append one code point as UTF-8 (case results never mint surrogates). */
|
|
737
|
+
static void scr_case_put_cp(ScrJsonBuf *b, uint32_t cp) {
|
|
738
|
+
if (cp < 0x80) {
|
|
739
|
+
scr_jb_putc(b, (char)cp);
|
|
740
|
+
} else if (cp < 0x800) {
|
|
741
|
+
scr_jb_putc(b, (char)(0xC0 | (cp >> 6)));
|
|
742
|
+
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
743
|
+
} else if (cp < 0x10000) {
|
|
744
|
+
scr_jb_putc(b, (char)(0xE0 | (cp >> 12)));
|
|
745
|
+
scr_jb_putc(b, (char)(0x80 | ((cp >> 6) & 0x3F)));
|
|
746
|
+
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
747
|
+
} else {
|
|
748
|
+
scr_jb_putc(b, (char)(0xF0 | (cp >> 18)));
|
|
749
|
+
scr_jb_putc(b, (char)(0x80 | ((cp >> 12) & 0x3F)));
|
|
750
|
+
scr_jb_putc(b, (char)(0x80 | ((cp >> 6) & 0x3F)));
|
|
751
|
+
scr_jb_putc(b, (char)(0x80 | (cp & 0x3F)));
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
static ScrStr *scr_str_case_conv(const ScrStr *s, int to_lower) {
|
|
756
|
+
ScrJsonBuf b;
|
|
757
|
+
scr_jb_init(&b);
|
|
758
|
+
uint32_t res[LRE_CC_RES_LEN_MAX];
|
|
759
|
+
for (size_t i = 0; i < s->len;) {
|
|
760
|
+
size_t adv;
|
|
761
|
+
uint32_t c = scr_case_decode(s->data + i, &adv);
|
|
762
|
+
int l;
|
|
763
|
+
if (c == 0x3a3 && to_lower && scr_final_sigma(s, i, i + adv)) {
|
|
764
|
+
res[0] = 0x3c2; /* final sigma */
|
|
765
|
+
l = 1;
|
|
766
|
+
} else {
|
|
767
|
+
l = lre_case_conv(res, c, to_lower);
|
|
768
|
+
}
|
|
769
|
+
i += adv;
|
|
770
|
+
for (int j = 0; j < l; j++) scr_case_put_cp(&b, res[j]);
|
|
771
|
+
}
|
|
772
|
+
return scr_jb_finish(&b);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
ScrStr *scr_str_to_lower(const ScrStr *s) { return scr_str_case_conv(s, 1); }
|
|
776
|
+
ScrStr *scr_str_to_upper(const ScrStr *s) { return scr_str_case_conv(s, 0); }
|
|
777
|
+
|
|
778
|
+
/* ── assert.match / assert.doesNotMatch ──────────────────────────────────
|
|
779
|
+
* Lives here (not scr_assert.c) because it needs the matcher, and every
|
|
780
|
+
* call site carries a regex value — the regex link switch is already on,
|
|
781
|
+
* so assert-only binaries never pull libregexp. A fresh exec from index 0:
|
|
782
|
+
* Node's exec on a fresh regex literal; lastIndex statefulness is not
|
|
783
|
+
* modeled anywhere in this runtime, so g/y-flagged regexes test like
|
|
784
|
+
* their flag-free twins here instead of aborting (assert.match(s, /x/g)
|
|
785
|
+
* works in Node — matching that beats scr_regex_test's fence;
|
|
786
|
+
* SEMANTICS.md 107 covers reused stateful regexes). */
|
|
787
|
+
/* A fresh exec from index 0 (assert.match's stance: g/y-flagged regexes
|
|
788
|
+
* test like their flag-free twins here — SEMANTICS.md 107 covers reused
|
|
789
|
+
* stateful regexes). */
|
|
790
|
+
static bool scr_assert_regex_hits(ScrRegex *re, ScrStr *s) {
|
|
791
|
+
uint8_t *bc = scr_regex_bc(re);
|
|
792
|
+
int len;
|
|
793
|
+
uint16_t *u = scr_to_utf16(s, &len);
|
|
794
|
+
uint8_t **capture = scr_capture_alloc(bc);
|
|
795
|
+
bool matched = scr_exec(capture, bc, u, 0, len) == 1;
|
|
796
|
+
free(capture);
|
|
797
|
+
free(u);
|
|
798
|
+
return matched;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/* The regex's own inspection — /source/ + FLAGS IN GETTER ORDER
|
|
802
|
+
* (dgimsuvy), not source order. +1. */
|
|
803
|
+
static ScrStr *scr_assert_regex_render(ScrRegex *re) {
|
|
804
|
+
size_t cap = re->source->len + re->flags->len + 2;
|
|
805
|
+
char *buf = malloc(cap);
|
|
806
|
+
if (!buf) abort();
|
|
807
|
+
size_t n = 0;
|
|
808
|
+
buf[n++] = '/';
|
|
809
|
+
memcpy(buf + n, re->source->data, re->source->len);
|
|
810
|
+
n += re->source->len;
|
|
811
|
+
buf[n++] = '/';
|
|
812
|
+
for (const char *f = "dgimsuvy"; *f; f++) {
|
|
813
|
+
for (size_t i = 0; i < re->flags->len; i++) {
|
|
814
|
+
if (re->flags->data[i] == *f) buf[n++] = *f;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
ScrStr *out = scr_str_new(buf, n);
|
|
818
|
+
free(buf);
|
|
819
|
+
return out;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/* Node's regex-mismatch AssertionError: 'The input did not match the
|
|
823
|
+
* regular expression /re/flags. Input:\n\n<inspect(input)>\n' (the
|
|
824
|
+
* was-expected-to-not-match head when negated). Always throws. */
|
|
825
|
+
static void scr_assert_regex_input_fail(bool negated, ScrRegex *re, ScrStr *input) {
|
|
826
|
+
ScrStr *insp = scr_assert_inspect_str(input);
|
|
827
|
+
ScrStr *rre = scr_assert_regex_render(re);
|
|
828
|
+
const char *head = negated
|
|
829
|
+
? "The input was expected to not match the regular expression "
|
|
830
|
+
: "The input did not match the regular expression ";
|
|
831
|
+
const char *mid = ". Input:\n\n";
|
|
832
|
+
size_t cap = strlen(head) + rre->len + strlen(mid) + insp->len + 1;
|
|
833
|
+
char *buf = malloc(cap);
|
|
834
|
+
if (!buf) abort();
|
|
835
|
+
size_t n = 0;
|
|
836
|
+
memcpy(buf + n, head, strlen(head));
|
|
837
|
+
n += strlen(head);
|
|
838
|
+
memcpy(buf + n, rre->data, rre->len);
|
|
839
|
+
n += rre->len;
|
|
840
|
+
memcpy(buf + n, mid, strlen(mid));
|
|
841
|
+
n += strlen(mid);
|
|
842
|
+
memcpy(buf + n, insp->data, insp->len);
|
|
843
|
+
n += insp->len;
|
|
844
|
+
buf[n++] = '\n';
|
|
845
|
+
scr_str_release(insp);
|
|
846
|
+
scr_str_release(rre);
|
|
847
|
+
ScrStr *message = scr_str_new(buf, n);
|
|
848
|
+
free(buf);
|
|
849
|
+
scr_assert_fail_msg(message);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
void scr_assert_match(ScrStr *s, ScrRegex *re, bool negated, ScrStr *msg,
|
|
853
|
+
bool has_msg) {
|
|
854
|
+
bool matched = scr_assert_regex_hits(re, s);
|
|
855
|
+
if (negated ? !matched : matched) return;
|
|
856
|
+
if (has_msg) {
|
|
857
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
scr_assert_regex_input_fail(negated, re, s);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/* assert.throws(fn, /re/) whose thrown Error did not satisfy the regex:
|
|
864
|
+
* Node tests String(actual) — Error.prototype.toString's "Name: message"
|
|
865
|
+
* — and reports the mismatch with that string inspected. */
|
|
866
|
+
void scr_assert_throws_regex(ScrRegex *re, ScrError *err, ScrStr *msg, bool has_msg) {
|
|
867
|
+
ScrStr *str = scr_error_to_string(err);
|
|
868
|
+
bool matched = scr_assert_regex_hits(re, str);
|
|
869
|
+
if (matched) {
|
|
870
|
+
scr_str_release(str);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (has_msg) {
|
|
874
|
+
scr_str_release(str);
|
|
875
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
scr_assert_regex_input_fail(false, re, str);
|
|
879
|
+
scr_str_release(str);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/* assert.doesNotReject's regex predicate: does String(error) satisfy the
|
|
883
|
+
* regex? Never throws — the caller inverts the verdict into either the
|
|
884
|
+
* unwanted-rejection AssertionError or a rethrow of the original. */
|
|
885
|
+
bool scr_assert_regex_err_test(ScrRegex *re, ScrError *err) {
|
|
886
|
+
ScrStr *str = scr_error_to_string(err);
|
|
887
|
+
bool matched = scr_assert_regex_hits(re, str);
|
|
888
|
+
scr_str_release(str);
|
|
889
|
+
return matched;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/* The regex-valued shape slot (assert.throws(fn, {message: /re/})):
|
|
893
|
+
* test the stashed actual key eagerly and store verdict + rendering, so
|
|
894
|
+
* scr_assert.c's comparison and diff stay libregexp-free. An absent
|
|
895
|
+
* actual key (NULL code) is a mismatch — Node's `key in actual` test. */
|
|
896
|
+
void scr_assert_shape_re(int key, ScrRegex *re) {
|
|
897
|
+
ScrStr *actual = scr_assert_shape_actual(key);
|
|
898
|
+
bool matched = actual != NULL && scr_assert_regex_hits(re, actual);
|
|
899
|
+
scr_assert_shape_slot_re(key, matched, scr_assert_regex_render(re));
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/* ── new RegExp(pattern, flags) — runtime construction ────────────────
|
|
903
|
+
* A heap ScrRegex (rc 1) over the same engine the literals use. The
|
|
904
|
+
* pattern compiles EAGERLY so an invalid pattern throws Node's catchable
|
|
905
|
+
* SyntaxError at construction (Node: "Invalid regular expression:
|
|
906
|
+
* /pat/: detail" — the detail text is libregexp's, approximate fidelity
|
|
907
|
+
* by design; e.name is exact). Unknown flag letters throw Node's
|
|
908
|
+
* "Invalid flags supplied to RegExp constructor 'x'". An empty pattern
|
|
909
|
+
* stores the spec's "(?:)" source, like Node. Borrows both; +1. */
|
|
910
|
+
ScrRegex *scr_regex_new(ScrStr *pattern, ScrStr *flags) {
|
|
911
|
+
for (size_t i = 0; i < flags->len; i++) {
|
|
912
|
+
switch (flags->data[i]) {
|
|
913
|
+
case 'g': case 'i': case 'm': case 's': case 'u': case 'y':
|
|
914
|
+
break;
|
|
915
|
+
default: {
|
|
916
|
+
char msg[80];
|
|
917
|
+
int n = snprintf(msg, sizeof msg,
|
|
918
|
+
"Invalid flags supplied to RegExp constructor '%.20s'",
|
|
919
|
+
flags->data);
|
|
920
|
+
scr_throw_error_msg(SCR_ERR_SYNTAX, msg, (size_t)n);
|
|
921
|
+
return NULL;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
ScrRegex *re = calloc(1, sizeof *re);
|
|
926
|
+
if (!re) {
|
|
927
|
+
fputs("scriptc: out of memory\n", stderr);
|
|
928
|
+
abort();
|
|
929
|
+
}
|
|
930
|
+
re->rc = 1;
|
|
931
|
+
re->source = pattern->len > 0 ? scr_str_retain(pattern) : scr_str_new("(?:)", 4);
|
|
932
|
+
re->flags = scr_str_retain(flags);
|
|
933
|
+
/* Eager compile — the literal path stays lazy (its failure is an
|
|
934
|
+
* abort; tsc already parsed those patterns). */
|
|
935
|
+
int lre_flags = scr_lre_flags(re->flags);
|
|
936
|
+
const char *pat = re->source->data;
|
|
937
|
+
size_t pat_len = re->source->len;
|
|
938
|
+
char *cesu = NULL;
|
|
939
|
+
if (!(lre_flags & LRE_FLAG_UNICODE)) {
|
|
940
|
+
cesu = scr_pattern_cesu8(re->source, &pat_len);
|
|
941
|
+
if (cesu) pat = cesu;
|
|
942
|
+
}
|
|
943
|
+
char error_msg[64];
|
|
944
|
+
int bc_len;
|
|
945
|
+
uint8_t *bc = lre_compile(&bc_len, error_msg, sizeof error_msg, pat, pat_len,
|
|
946
|
+
lre_flags, lre_opaque());
|
|
947
|
+
free(cesu);
|
|
948
|
+
if (!bc) {
|
|
949
|
+
char msg[192];
|
|
950
|
+
int n = snprintf(msg, sizeof msg, "Invalid regular expression: /%.64s/%.8s: %s",
|
|
951
|
+
re->source->data, re->flags->data, error_msg);
|
|
952
|
+
scr_str_release(re->source);
|
|
953
|
+
scr_str_release(re->flags);
|
|
954
|
+
free(re);
|
|
955
|
+
scr_throw_error_msg(SCR_ERR_SYNTAX, msg, (size_t)n);
|
|
956
|
+
return NULL;
|
|
957
|
+
}
|
|
958
|
+
re->bc = bc;
|
|
959
|
+
return re;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/* Decode the code point at p (well-formed UTF-8 by the string
|
|
963
|
+
* invariant); *adv gets the byte length of the sequence. */
|
|
964
|
+
static uint32_t scr_re_utf8_decode(const char *p, size_t *adv) {
|
|
965
|
+
unsigned char c = (unsigned char)p[0];
|
|
966
|
+
if (c < 0x80) { *adv = 1; return c; }
|
|
967
|
+
if (c < 0xE0) { *adv = 2; return ((uint32_t)(c & 0x1F) << 6) | ((unsigned char)p[1] & 0x3F); }
|
|
968
|
+
if (c < 0xF0) {
|
|
969
|
+
*adv = 3;
|
|
970
|
+
return ((uint32_t)(c & 0x0F) << 12) | ((uint32_t)((unsigned char)p[1] & 0x3F) << 6) | ((unsigned char)p[2] & 0x3F);
|
|
971
|
+
}
|
|
972
|
+
*adv = 4;
|
|
973
|
+
return ((uint32_t)(c & 0x07) << 18) | ((uint32_t)((unsigned char)p[1] & 0x3F) << 12) |
|
|
974
|
+
((uint32_t)((unsigned char)p[2] & 0x3F) << 6) | ((unsigned char)p[3] & 0x3F);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/* ── RegExp.escape ────────────────────────────────────────────────────
|
|
978
|
+
* ECMA-262 (ES2025) RegExp.escape over the UTF-8 storage. Per-code-point
|
|
979
|
+
* EncodeForRegExpEscape: a LEADING ASCII letter/digit hex-escapes (so a
|
|
980
|
+
* concatenation can't extend a token), SyntaxCharacters and '/' take a
|
|
981
|
+
* backslash, the "other punctuators" ∪ WhiteSpace ∪ LineTerminator set
|
|
982
|
+
* hex-escapes (\xNN below U+0100, \uNNNN above — lowercase hex, per
|
|
983
|
+
* spec), and everything else passes through. The spec's surrogate arm is
|
|
984
|
+
* unreachable over well-formed storage (SEMANTICS.md 2). Borrows s;
|
|
985
|
+
* result +1. */
|
|
986
|
+
static bool scr_regexp_syntax_char(uint32_t cp) {
|
|
987
|
+
switch (cp) {
|
|
988
|
+
case '^': case '$': case '\\': case '.': case '*': case '+': case '?':
|
|
989
|
+
case '(': case ')': case '[': case ']': case '{': case '}': case '|':
|
|
990
|
+
case '/':
|
|
991
|
+
return true;
|
|
992
|
+
default:
|
|
993
|
+
return false;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/* The ControlEscape arm: TAB/LF/VT/FF/CR escape as \t \n \v \f \r (the
|
|
998
|
+
* spec maps them through ControlEscape before the hex arm). Returns the
|
|
999
|
+
* escape letter, or 0 when cp isn't one of the five. */
|
|
1000
|
+
static char scr_regexp_control_escape(uint32_t cp) {
|
|
1001
|
+
switch (cp) {
|
|
1002
|
+
case 0x09: return 't';
|
|
1003
|
+
case 0x0A: return 'n';
|
|
1004
|
+
case 0x0B: return 'v';
|
|
1005
|
+
case 0x0C: return 'f';
|
|
1006
|
+
case 0x0D: return 'r';
|
|
1007
|
+
default: return 0;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
static bool scr_regexp_hex_escaped(uint32_t cp) {
|
|
1012
|
+
switch (cp) {
|
|
1013
|
+
/* other punctuators */
|
|
1014
|
+
case ',': case '-': case '=': case '<': case '>': case '#': case '&':
|
|
1015
|
+
case '!': case '%': case ':': case ';': case '@': case '~': case '\'':
|
|
1016
|
+
case '`': case '"':
|
|
1017
|
+
return true;
|
|
1018
|
+
/* WhiteSpace ∪ LineTerminator less the ControlEscape five */
|
|
1019
|
+
case 0x20: case 0xA0: case 0x1680: case 0x2028: case 0x2029:
|
|
1020
|
+
case 0x202F: case 0x205F: case 0x3000: case 0xFEFF:
|
|
1021
|
+
return true;
|
|
1022
|
+
default:
|
|
1023
|
+
return cp >= 0x2000 && cp <= 0x200A;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/* Encoded byte length of cp at position `first` (raw = its UTF-8 length). */
|
|
1028
|
+
static size_t scr_regexp_escape_len(uint32_t cp, bool first, size_t raw) {
|
|
1029
|
+
if (first && ((cp >= '0' && cp <= '9') || (cp >= 'A' && cp <= 'Z') || (cp >= 'a' && cp <= 'z'))) return 4;
|
|
1030
|
+
if (scr_regexp_syntax_char(cp) || scr_regexp_control_escape(cp) != 0) return 2;
|
|
1031
|
+
if (scr_regexp_hex_escaped(cp)) return cp < 0x100 ? 4 : 6;
|
|
1032
|
+
return raw;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
ScrStr *scr_regexp_escape(ScrStr *s) {
|
|
1036
|
+
static const char hex[] = "0123456789abcdef";
|
|
1037
|
+
size_t out_len = 0;
|
|
1038
|
+
bool first = true;
|
|
1039
|
+
for (size_t i = 0; i < s->len;) {
|
|
1040
|
+
size_t adv;
|
|
1041
|
+
uint32_t cp = scr_re_utf8_decode(s->data + i, &adv);
|
|
1042
|
+
out_len += scr_regexp_escape_len(cp, first, adv);
|
|
1043
|
+
first = false;
|
|
1044
|
+
i += adv;
|
|
1045
|
+
}
|
|
1046
|
+
if (out_len == s->len) return scr_str_retain(s); /* nothing escapes — share */
|
|
1047
|
+
ScrStr *out = scr_str_alloc_raw(out_len, out_len);
|
|
1048
|
+
char *w = out->data;
|
|
1049
|
+
first = true;
|
|
1050
|
+
for (size_t i = 0; i < s->len;) {
|
|
1051
|
+
size_t adv;
|
|
1052
|
+
uint32_t cp = scr_re_utf8_decode(s->data + i, &adv);
|
|
1053
|
+
size_t enc = scr_regexp_escape_len(cp, first, adv);
|
|
1054
|
+
if (enc == adv) { /* pass-through: an escape's length never matches raw */
|
|
1055
|
+
memcpy(w, s->data + i, adv);
|
|
1056
|
+
w += adv;
|
|
1057
|
+
} else if (enc == 2) {
|
|
1058
|
+
char ctl = scr_regexp_control_escape(cp);
|
|
1059
|
+
*w++ = '\\';
|
|
1060
|
+
*w++ = ctl != 0 ? ctl : (char)cp;
|
|
1061
|
+
} else if (enc == 4) {
|
|
1062
|
+
*w++ = '\\';
|
|
1063
|
+
*w++ = 'x';
|
|
1064
|
+
*w++ = hex[(cp >> 4) & 0xF];
|
|
1065
|
+
*w++ = hex[cp & 0xF];
|
|
1066
|
+
} else {
|
|
1067
|
+
*w++ = '\\';
|
|
1068
|
+
*w++ = 'u';
|
|
1069
|
+
*w++ = hex[(cp >> 12) & 0xF];
|
|
1070
|
+
*w++ = hex[(cp >> 8) & 0xF];
|
|
1071
|
+
*w++ = hex[(cp >> 4) & 0xF];
|
|
1072
|
+
*w++ = hex[cp & 0xF];
|
|
1073
|
+
}
|
|
1074
|
+
first = false;
|
|
1075
|
+
i += adv;
|
|
1076
|
+
}
|
|
1077
|
+
out->len = out_len;
|
|
1078
|
+
out->data[out_len] = '\0';
|
|
1079
|
+
return out;
|
|
1080
|
+
}
|