123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272(** C function bindings for QuickJS utilities
This module defines the FFI bindings to QuickJS's internal libraries:
- libregexp: Regular expression engine
- libunicode: Unicode character utilities
- dtoa: Number ↔ String conversion (js_dtoa, js_atod)
- cutils: Integer to string conversion (itoa family)
Some functions are bound through wrappers in [shims.c], either because
ctypes cannot express the exact C signature (const qualifiers), or to add
behavior the raw library delegates to its embedder (stack-overflow guard,
execution deadline, allocation). *)[@@@ocamlformat"disable"](* We want to keep the comments aligned with the C code *)moduleFunctions(F:Ctypes.FOREIGN)=structlet(@->)=F.(@->)(* =========================================================================
libregexp.c - Regular Expression Engine
QuickJS's ES2023-compliant regex engine with Unicode support.
========================================================================= *)(** Compile a regular expression pattern into bytecode (via shim that arms
the C-stack guard). The returned buffer must be released with
[lre_bytecode_free]. Returns NULL on error with message in error_msg. *)letlre_compile=F.foreign"lre_compile_shim"(Ctypes.ptrCtypes.int(* [out] int *plen - bytecode length *)@->Ctypes.ptrCtypes.char(* [out] char *error_msg *)@->Ctypes.int(* int error_msg_size *)@->Ctypes.ocaml_string(* const char *buf - pattern *)@->Ctypes.size_t(* size_t buf_len *)@->Ctypes.int(* int re_flags *)@->Ctypes.ptrCtypes.void(* void *opaque *)@->F.returning(Ctypes.ptrCtypes.uint8_t))(** Execute a compiled regex against input string (via shim that arms the
C-stack guard and threads an optional deadline).
Returns: 1 = match, 0 = no match,
-1 = LRE_RET_MEMORY_ERROR, -2 = LRE_RET_TIMEOUT *)letlre_exec=F.foreign"lre_exec_shim"(Ctypes.ptr(Ctypes.ptrCtypes.uint8_t)(* [out] uint8_t **capture *)@->Ctypes.ptrCtypes.uint8_t(* const uint8_t *bc_buf - bytecode *)@->Ctypes.ptrCtypes.uint8_t(* const uint8_t *cbuf - input *)@->Ctypes.int(* int cindex - start index *)@->Ctypes.int(* int clen - input length *)@->Ctypes.int(* int cbuf_type: 0=8bit, 1=16bit *)@->Ctypes.ptr_optCtypes.double(* double *deadline (NULL = none) *)@->F.returningCtypes.int)(** Free a bytecode buffer returned by [lre_compile] *)letlre_bytecode_free=F.foreign"lre_bytecode_free"(Ctypes.ptrCtypes.uint8_t(* uint8_t *bc_buf *)@->F.returningCtypes.void)(** Monotonic clock in milliseconds; basis for [lre_exec] deadlines *)letlre_now_ms=F.foreign"lre_now_ms"(Ctypes.void@->F.returningCtypes.double)(** Get number of capture groups (including group 0 for full match) *)letlre_get_capture_count=F.foreign"lre_get_capture_count"(Ctypes.ptrCtypes.uint8_t(* const uint8_t *bc_buf *)@->F.returningCtypes.int)(** Get pointer to null-terminated group names (via shim) *)letlre_get_groupnames=F.foreign"lre_get_groupnames_shim"(Ctypes.ptrCtypes.uint8_t(* const uint8_t *bc_buf *)@->F.returning(Ctypes.ptr_optCtypes.char))(** Get flags from compiled bytecode *)letlre_get_flags=F.foreign"lre_get_flags"(Ctypes.ptrCtypes.uint8_t(* const uint8_t *bc_buf *)@->F.returningCtypes.int)(* =========================================================================
libunicode.c - Unicode Character Utilities
Unicode character classification and case conversion.
========================================================================= *)(* --- Character Classification --- *)(** Check if character has uppercase/lowercase variants (Cased property) *)letlre_is_cased=F.foreign"lre_is_cased"(Ctypes.uint32_t@->F.returningCtypes.bool)(** Check if character is ignored during case mapping (Case_Ignorable) *)letlre_is_case_ignorable=F.foreign"lre_is_case_ignorable"(Ctypes.uint32_t@->F.returningCtypes.bool)(** Check if character can start an identifier (ID_Start) *)letlre_is_id_start=F.foreign"lre_is_id_start"(Ctypes.uint32_t@->F.returningCtypes.bool)(** Check if character can continue an identifier (ID_Continue) *)letlre_is_id_continue=F.foreign"lre_is_id_continue"(Ctypes.uint32_t@->F.returningCtypes.bool)(** Check if character is whitespace per ECMA-262 (WhiteSpace or
LineTerminator; matches regexp \s, String.prototype.trim and the
whitespace skipped by parseInt/parseFloat) *)letlre_is_space=F.foreign"lre_is_space"(Ctypes.int@->F.returningCtypes.bool)(* --- Case Conversion --- *)(** Convert character case.
conv_type: 0 = uppercase, 1 = lowercase, 2 = case folding
Returns number of output codepoints (1-3) *)letlre_case_conv=F.foreign"lre_case_conv"(Ctypes.ptrCtypes.uint32_t(* [out] uint32_t *res - output buffer *)@->Ctypes.uint32_t(* uint32_t c - input codepoint *)@->Ctypes.int(* int conv_type *)@->F.returningCtypes.int)(** Canonicalize character for case-insensitive regex matching.
is_unicode: true = full Unicode folding, false = ASCII only *)letlre_canonicalize=F.foreign"lre_canonicalize"(Ctypes.uint32_t(* uint32_t c *)@->Ctypes.bool(* bool is_unicode *)@->F.returningCtypes.int)(* --- Normalization --- *)(** Normalize Unicode string (via C shim that handles allocation).
n_type: 0 = NFC, 1 = NFD, 2 = NFKC, 3 = NFKD
Returns length of output, or -1 on error *)letunicode_normalize_shim=F.foreign"unicode_normalize_shim"(Ctypes.ptrCtypes.uint32_t(* const uint32_t *src *)@->Ctypes.int(* int src_len *)@->Ctypes.int(* int n_type *)@->Ctypes.ptr(Ctypes.ptrCtypes.uint32_t)(* [out] uint32_t **pdst *)@->F.returningCtypes.int)(** Free buffer allocated by unicode_normalize_shim *)letunicode_normalize_free=F.foreign"unicode_normalize_free"(Ctypes.ptrCtypes.uint32_t@->F.returningCtypes.void)(* --- Character Ranges (Script / General_Category / binary properties) --- *)(** Look up a Unicode character range table by name (via C shim).
kind: 0 = Script, 1 = Script_Extensions, 2 = General_Category,
3 = binary property.
On success returns the number of points (always even) with the buffer
in *out_points (half-open intervals [points[2i], points[2i+1])).
Returns -1 on memory error, -2 when the name is unknown. *)letunicode_char_range_shim=F.foreign"unicode_char_range_shim"(Ctypes.int(* int kind *)@->Ctypes.string(* const char *name *)@->Ctypes.ptr(Ctypes.ptrCtypes.uint32_t)(* [out] uint32_t **out_points *)@->F.returningCtypes.int)(** Free buffer allocated by unicode_char_range_shim *)letunicode_char_range_free=F.foreign"unicode_char_range_free"(Ctypes.ptrCtypes.uint32_t@->F.returningCtypes.void)(* =========================================================================
dtoa.c - Number ↔ String Conversion
JavaScript-compatible floating point parsing and formatting.
dtoa = Double TO Ascii, atod = Ascii TO Double
========================================================================= *)(* --- dtoa: Double → String --- *)(** Calculate maximum buffer size needed for js_dtoa *)letjs_dtoa_max_len=F.foreign"js_dtoa_max_len"(Ctypes.double(* double d *)@->Ctypes.int(* int radix *)@->Ctypes.int(* int n_digits *)@->Ctypes.int(* int flags *)@->F.returningCtypes.int)(** Convert double to string with JS semantics.
Flags: JS_DTOA_FORMAT_* | JS_DTOA_EXP_* | JS_DTOA_MINUS_ZERO
Returns actual string length *)letjs_dtoa=F.foreign"js_dtoa"(Ctypes.ptrCtypes.char(* [out] char *buf *)@->Ctypes.double(* double d *)@->Ctypes.int(* int radix (2-36) *)@->Ctypes.int(* int n_digits *)@->Ctypes.int(* int flags *)@->Ctypes.ptrCtypes.void(* JSDTOATempMem *tmp_mem *)@->F.returningCtypes.int)(* --- atod: String → Double --- *)(** Parse string to double with JS semantics (via shim).
Flags: JS_ATOD_INT_ONLY | JS_ATOD_ACCEPT_BIN_OCT | etc.
Sets *poffset to the number of bytes consumed (0 when parsing failed).
Returns NaN when nothing could be parsed. *)letjs_atod=F.foreign"js_atod_shim"(Ctypes.string(* const char *str *)@->Ctypes.ptrCtypes.int(* [out] int *poffset *)@->Ctypes.int(* int radix (0=auto, 2-36) *)@->Ctypes.int(* int flags *)@->Ctypes.ptrCtypes.void(* JSATODTempMem *tmp_mem *)@->F.returningCtypes.double)(* =========================================================================
cutils.c / dtoa.c - Integer to String Conversion
Fast integer-to-string functions (itoa family). These do not
NUL-terminate; they return the number of bytes written.
========================================================================= *)(** Convert unsigned 32-bit integer to decimal string *)letu32toa=F.foreign"u32toa"(Ctypes.ptrCtypes.char(* [out] char *buf *)@->Ctypes.uint32_t(* uint32_t n *)@->F.returningCtypes.size_t)(** Convert signed 32-bit integer to decimal string *)leti32toa=F.foreign"i32toa"(Ctypes.ptrCtypes.char(* [out] char *buf *)@->Ctypes.int32_t(* int32_t n *)@->F.returningCtypes.size_t)(** Convert unsigned 64-bit integer to decimal string *)letu64toa=F.foreign"u64toa"(Ctypes.ptrCtypes.char(* [out] char *buf *)@->Ctypes.uint64_t(* uint64_t n *)@->F.returningCtypes.size_t)(** Convert signed 64-bit integer to decimal string *)leti64toa=F.foreign"i64toa"(Ctypes.ptrCtypes.char(* [out] char *buf *)@->Ctypes.int64_t(* int64_t n *)@->F.returningCtypes.size_t)(** Convert unsigned 64-bit integer to string in given radix (2-36) *)letu64toa_radix=F.foreign"u64toa_radix"(Ctypes.ptrCtypes.char(* [out] char *buf *)@->Ctypes.uint64_t(* uint64_t n *)@->Ctypes.uint(* unsigned int radix *)@->F.returningCtypes.size_t)(** Convert signed 64-bit integer to string in given radix (2-36) *)leti64toa_radix=F.foreign"i64toa_radix"(Ctypes.ptrCtypes.char(* [out] char *buf *)@->Ctypes.int64_t(* int64_t n *)@->Ctypes.int(* int radix *)@->F.returningCtypes.size_t)end