package quickjs
Install
dune-project
Dependency
Authors
Maintainers
Sources
sha256=42397865f43779613b04bb2f3532b060c6dcca2d41aa1337b31124fca21629a4
sha512=52bf83c9e3a9e37764b514e34e1acbcdabef9ccac9cefa510e4683b693328ddde42ff59e8475e19c9f1a90caee8b790f2438f5808a11eca7700412b55f41a30e
doc/index.html
quickjs
quickjs.ml is a set of OCaml bindings to some libraries from quickjs-ng, a small and embeddable JavaScript engine that aims to support the latest ECMAScript specification.
This project exposes two libraries:
quickjs.c: Low-level OCaml bindings to QuickJS C functions (Libregexp, Libunicode, Dtoa, Atod, and Cutils)
- quickjs: A high-level API that mirrors JavaScript's built-in objects and methods. Modules include RegExp, String, Number, and Global.
Motivation
The purpose of this project is to provide the same behaviour as the JavaScript engines from browsers (SpiderMonkey, JavaScriptCore, ChakraCore, v8) into native OCaml. So code that runs in the browser (via Melange) can be run in native with the same results.
Test262 Compatibility
We are translating TC39/test262 tests into OCaml to ensure full compatibility with the ECMAScript specification. This allows us to verify that our implementations behave exactly as expected by the JavaScript standard, guaranteeing consistent behaviour between browser engines and native OCaml.
Usage
All string indices (match positions, last_index, String.Prototype methods) are UTF-16 code units, exactly like JavaScript.
open Quickjs
let () =
(* RegExp - JavaScript-compatible regular expressions *)
let re = RegExp.compile ~flags:"g" "(?<word>\\w+)" |> Result.get_ok in
(match RegExp.exec re "hello world" with
| Some m ->
assert (m.captures = [| Some "hello"; Some "hello" |]);
assert (RegExp.group "word" m = Some "hello");
assert (m.index = 0)
| None -> assert false);
(* the global flag advances last_index: the next exec finds "world" *)
(match RegExp.exec re "hello world" with
| Some m -> assert (RegExp.group "word" m = Some "world")
| None -> assert false);
(* The 'd' flag records capture group positions (match.indices) *)
let re = RegExp.compile ~flags:"d" "b(c)" |> Result.get_ok in
(match RegExp.exec re "abcd" with
| Some m ->
let indices = Option.get m.indices in
assert (indices.ranges = [| Some (1, 3); Some (2, 3) |])
| None -> assert false);
(* Number.Prototype - JavaScript-identical number formatting *)
assert (Number.Prototype.to_string 0.1 = "0.1");
assert (Number.Prototype.to_fixed 2 3.14159 = "3.14");
assert (Number.Prototype.to_radix 16 255.0 = "ff");
assert (Number.Prototype.to_exponential 2 123.456 = "1.23e+2");
(* Global - JavaScript global functions *)
assert (Global.parse_float "3.14" = Some 3.14);
assert (Global.parse_int "0x10" = Some 16);
assert (
Global.parse_float ~options:Global.js_number_options "0xff" = Some 255.0);
(* Number - fast integer to string *)
assert (Number.of_int 42 = "42");
assert (Number.of_int_radix ~radix:16 255 = "ff");
(* String.Prototype - JavaScript string methods *)
assert (String.Prototype.to_lower_case "HELLO" = "hello");
assert (String.Prototype.to_upper_case "world" = "WORLD");
assert (String.from_code_point [| 0x1F600 |] = "😀");
assert (
String.Prototype.split_regex "(x)?(b)" "ab"
= [| Some "a"; None; Some "b"; Some "" |]);
(* Unicode - case folding and the property tables behind \p{...} *)
assert (Unicode.fold_case "Straße" = Unicode.fold_case "STRASSE");
let greek = Option.get (Unicode.script "Greek") in
assert (Unicode.CharSet.mem (Uchar.of_int 0x03B1) greek) (* α *)