My working unpac space for OCaml projects in development
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add core JavaScript built-in objects

Implements essential built-in objects for JavaScript runtime:

Built-in Objects:
- Math: All constants (PI, E, LN2, etc.) and methods (sin, cos, sqrt, etc.)
- Array: Constructor, prototype methods (push, pop, map, filter, etc.)
- String: Constructor, prototype methods (slice, trim, split, etc.)
- Object: Constructor, static methods (keys, values, entries, freeze, etc.)
- console: log, error, warn, time/timeEnd, etc.

Infrastructure:
- Add native function support to value system (Data_native_function)
- Update interpreter to call native functions
- Add builtins initialization module (init.ml)

Global functions:
- isNaN, isFinite, parseInt, parseFloat

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+2070
+9
.claude/ralph-loop.local.md
··· 1 + --- 2 + active: true 3 + iteration: 1 4 + max_iterations: 10 5 + completion_promise: "AGENT-HUMP" 6 + started_at: "2025-12-29T04:01:13Z" 7 + --- 8 + 9 + continue working on getting the ocaml-quickjs to 100% test pass rate, using the c quickjs vendor as a reference. When complete with a 100% pass rate and full feature parity , output AGENT-HUMP
+197
lib/quickjs/builtins/console.ml
··· 1 + (** JavaScript console object. 2 + 3 + Implements basic console methods for debugging. *) 4 + 5 + open Quickjs_runtime.Value 6 + 7 + (** Format a value for console output *) 8 + let rec format_value v = 9 + match v with 10 + | Undefined -> "undefined" 11 + | Null -> "null" 12 + | Bool b -> string_of_bool b 13 + | Int i -> Int32.to_string i 14 + | Float f -> 15 + if Float.is_nan f then "NaN" 16 + else if Float.is_infinite f then if f > 0.0 then "Infinity" else "-Infinity" 17 + else string_of_float f 18 + | String s -> s 19 + | Symbol { description; _ } -> 20 + (match description with 21 + | Some d -> "Symbol(" ^ d ^ ")" 22 + | None -> "Symbol()") 23 + | BigInt z -> Z.to_string z ^ "n" 24 + | Object obj -> 25 + (match obj.class_id with 26 + | Class_array -> 27 + (match obj.data with 28 + | Data_array arr -> 29 + let elements = Array.map format_value !arr in 30 + "[ " ^ String.concat ", " (Array.to_list elements) ^ " ]" 31 + | _ -> "[object Array]") 32 + | Class_function | Class_bound_function -> "[Function]" 33 + | Class_error -> 34 + (match obj.data with 35 + | Data_error { name; message; _ } -> name ^ ": " ^ message 36 + | _ -> "[object Error]") 37 + | Class_regexp -> 38 + (match obj.data with 39 + | Data_regexp { pattern; flags; _ } -> "/" ^ pattern ^ "/" ^ flags 40 + | _ -> "[object RegExp]") 41 + | Class_date -> 42 + (match obj.data with 43 + | Data_date timestamp -> 44 + (* Simple date formatting *) 45 + let time = Unix.gmtime timestamp in 46 + Printf.sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ" 47 + (time.Unix.tm_year + 1900) 48 + (time.Unix.tm_mon + 1) 49 + time.Unix.tm_mday 50 + time.Unix.tm_hour 51 + time.Unix.tm_min 52 + time.Unix.tm_sec 53 + | _ -> "[object Date]") 54 + | _ -> 55 + (* Generic object formatting *) 56 + let pairs = Hashtbl.fold (fun k prop acc -> 57 + if prop.flags.enumerable then 58 + (k ^ ": " ^ format_value prop.value) :: acc 59 + else acc 60 + ) obj.properties [] in 61 + "{ " ^ String.concat ", " pairs ^ " }") 62 + | Exception v -> "Exception: " ^ format_value v 63 + | Uninitialized -> "<uninitialized>" 64 + 65 + (** console.log(...args) *) 66 + let log _this args = 67 + let output = List.map format_value args |> String.concat " " in 68 + print_endline output; 69 + Undefined 70 + 71 + (** console.error(...args) *) 72 + let error _this args = 73 + let output = List.map format_value args |> String.concat " " in 74 + prerr_endline output; 75 + Undefined 76 + 77 + (** console.warn(...args) *) 78 + let warn _this args = 79 + let output = List.map format_value args |> String.concat " " in 80 + prerr_endline ("Warning: " ^ output); 81 + Undefined 82 + 83 + (** console.info(...args) *) 84 + let info _this args = 85 + log _this args 86 + 87 + (** console.debug(...args) *) 88 + let debug _this args = 89 + log _this args 90 + 91 + (** console.trace(...args) *) 92 + let trace _this args = 93 + let output = List.map format_value args |> String.concat " " in 94 + print_endline ("Trace: " ^ output); 95 + (* TODO: Print stack trace *) 96 + Undefined 97 + 98 + (** console.assert(condition, ...args) *) 99 + let assert_ _this args = 100 + match args with 101 + | [] -> Undefined 102 + | condition :: rest -> 103 + if not (to_boolean condition) then begin 104 + let msg = if rest = [] then "Assertion failed" 105 + else "Assertion failed: " ^ (List.map format_value rest |> String.concat " ") 106 + in 107 + prerr_endline msg 108 + end; 109 + Undefined 110 + 111 + (** console.clear() *) 112 + let clear _this _args = 113 + (* ANSI escape to clear screen *) 114 + print_string "\027[2J\027[H"; 115 + flush stdout; 116 + Undefined 117 + 118 + (** console.time(label) *) 119 + let _timers : (string, float) Hashtbl.t = Hashtbl.create 16 120 + 121 + let time _this args = 122 + let label = match args with 123 + | v :: _ -> to_string v 124 + | [] -> "default" 125 + in 126 + Hashtbl.replace _timers label (Unix.gettimeofday ()); 127 + Undefined 128 + 129 + (** console.timeEnd(label) *) 130 + let time_end _this args = 131 + let label = match args with 132 + | v :: _ -> to_string v 133 + | [] -> "default" 134 + in 135 + (match Hashtbl.find_opt _timers label with 136 + | Some start_time -> 137 + let elapsed = (Unix.gettimeofday () -. start_time) *. 1000.0 in 138 + Printf.printf "%s: %.3fms\n" label elapsed; 139 + Hashtbl.remove _timers label 140 + | None -> 141 + Printf.printf "Timer '%s' does not exist\n" label); 142 + Undefined 143 + 144 + (** console.count(label) *) 145 + let _counters : (string, int) Hashtbl.t = Hashtbl.create 16 146 + 147 + let count _this args = 148 + let label = match args with 149 + | v :: _ -> to_string v 150 + | [] -> "default" 151 + in 152 + let n = match Hashtbl.find_opt _counters label with 153 + | Some n -> n + 1 154 + | None -> 1 155 + in 156 + Hashtbl.replace _counters label n; 157 + Printf.printf "%s: %d\n" label n; 158 + Undefined 159 + 160 + (** console.countReset(label) *) 161 + let count_reset _this args = 162 + let label = match args with 163 + | v :: _ -> to_string v 164 + | [] -> "default" 165 + in 166 + Hashtbl.remove _counters label; 167 + Undefined 168 + 169 + (** Create the console object *) 170 + let create () = 171 + let console = make_object () in 172 + 173 + let add_method name length func = 174 + let fn = make_native_function name length func in 175 + match fn with 176 + | Object obj -> 177 + Hashtbl.add console.properties name 178 + { value = Object obj; 179 + flags = { writable = true; enumerable = false; configurable = true }; 180 + getter = None; setter = None } 181 + | _ -> () 182 + in 183 + 184 + add_method "log" 0 log; 185 + add_method "error" 0 error; 186 + add_method "warn" 0 warn; 187 + add_method "info" 0 info; 188 + add_method "debug" 0 debug; 189 + add_method "trace" 0 trace; 190 + add_method "assert" 0 assert_; 191 + add_method "clear" 0 clear; 192 + add_method "time" 0 time; 193 + add_method "timeEnd" 0 time_end; 194 + add_method "count" 0 count; 195 + add_method "countReset" 0 count_reset; 196 + 197 + Object console
+4
lib/quickjs/builtins/dune
··· 1 + (library 2 + (name quickjs_builtins) 3 + (public_name ocaml-quickjs.builtins) 4 + (libraries quickjs_runtime zarith unix str))
+139
lib/quickjs/builtins/init.ml
··· 1 + (** Initialize all built-in objects in a context. 2 + 3 + This module wires up all built-in constructors, prototypes, and 4 + global objects to the JavaScript context. *) 5 + 6 + open Quickjs_runtime.Value 7 + 8 + (** Initialize all builtins in the global object *) 9 + let init global = 10 + (* Add Math object *) 11 + let math = Math.create () in 12 + (match math with 13 + | Object m -> 14 + Hashtbl.add global.properties "Math" 15 + { value = Object m; 16 + flags = { writable = true; enumerable = false; configurable = true }; 17 + getter = None; setter = None } 18 + | _ -> ()); 19 + 20 + (* Add console object *) 21 + let console = Console.create () in 22 + (match console with 23 + | Object c -> 24 + Hashtbl.add global.properties "console" 25 + { value = Object c; 26 + flags = { writable = true; enumerable = false; configurable = true }; 27 + getter = None; setter = None } 28 + | _ -> ()); 29 + 30 + (* Add Object constructor and set up Object.prototype *) 31 + let object_ctor, object_proto = Js_object.create_builtin () in 32 + (match object_ctor with 33 + | Object ctor -> 34 + Hashtbl.add global.properties "Object" 35 + { value = Object ctor; 36 + flags = { writable = true; enumerable = false; configurable = true }; 37 + getter = None; setter = None } 38 + | _ -> ()); 39 + 40 + (* Add Array constructor *) 41 + let array_ctor, _array_proto = Js_array.create () in 42 + (match array_ctor with 43 + | Object ctor -> 44 + Hashtbl.add global.properties "Array" 45 + { value = Object ctor; 46 + flags = { writable = true; enumerable = false; configurable = true }; 47 + getter = None; setter = None } 48 + | _ -> ()); 49 + 50 + (* Add String constructor *) 51 + let string_ctor, _string_proto = Js_string.create () in 52 + (match string_ctor with 53 + | Object ctor -> 54 + Hashtbl.add global.properties "String" 55 + { value = Object ctor; 56 + flags = { writable = true; enumerable = false; configurable = true }; 57 + getter = None; setter = None } 58 + | _ -> ()); 59 + 60 + (* Add isNaN global function *) 61 + let is_nan = make_native_function "isNaN" 1 (fun _this args -> 62 + match args with 63 + | v :: _ -> Bool (Float.is_nan (to_float v)) 64 + | [] -> Bool true 65 + ) in 66 + (match is_nan with 67 + | Object f -> 68 + Hashtbl.add global.properties "isNaN" 69 + { value = Object f; 70 + flags = { writable = true; enumerable = false; configurable = true }; 71 + getter = None; setter = None } 72 + | _ -> ()); 73 + 74 + (* Add isFinite global function *) 75 + let is_finite = make_native_function "isFinite" 1 (fun _this args -> 76 + match args with 77 + | v :: _ -> 78 + let n = to_float v in 79 + Bool (not (Float.is_nan n) && not (Float.is_infinite n)) 80 + | [] -> Bool false 81 + ) in 82 + (match is_finite with 83 + | Object f -> 84 + Hashtbl.add global.properties "isFinite" 85 + { value = Object f; 86 + flags = { writable = true; enumerable = false; configurable = true }; 87 + getter = None; setter = None } 88 + | _ -> ()); 89 + 90 + (* Add parseInt global function *) 91 + let parse_int = make_native_function "parseInt" 2 (fun _this args -> 92 + let s = match List.nth_opt args 0 with 93 + | Some v -> to_string v |> String.trim 94 + | None -> "" 95 + in 96 + let radix = match List.nth_opt args 1 with 97 + | Some Undefined | None -> 10 98 + | Some v -> int_of_float (to_float v) 99 + in 100 + if radix < 2 || radix > 36 then Float Float.nan 101 + else 102 + try 103 + if radix = 16 && String.length s >= 2 then 104 + let prefix = String.sub s 0 2 in 105 + if prefix = "0x" || prefix = "0X" then 106 + Int (Int32.of_string ("0x" ^ String.sub s 2 (String.length s - 2))) 107 + else 108 + Int (Int32.of_string s) 109 + else 110 + Int (Int32.of_string s) 111 + with _ -> Float Float.nan 112 + ) in 113 + (match parse_int with 114 + | Object f -> 115 + Hashtbl.add global.properties "parseInt" 116 + { value = Object f; 117 + flags = { writable = true; enumerable = false; configurable = true }; 118 + getter = None; setter = None } 119 + | _ -> ()); 120 + 121 + (* Add parseFloat global function *) 122 + let parse_float = make_native_function "parseFloat" 1 (fun _this args -> 123 + let s = match List.nth_opt args 0 with 124 + | Some v -> to_string v |> String.trim 125 + | None -> "" 126 + in 127 + try Float (Float.of_string s) 128 + with _ -> Float Float.nan 129 + ) in 130 + (match parse_float with 131 + | Object f -> 132 + Hashtbl.add global.properties "parseFloat" 133 + { value = Object f; 134 + flags = { writable = true; enumerable = false; configurable = true }; 135 + getter = None; setter = None } 136 + | _ -> ()); 137 + 138 + (* Return the Object prototype for use as default prototype *) 139 + object_proto
+542
lib/quickjs/builtins/js_array.ml
··· 1 + (** JavaScript Array built-in object. 2 + 3 + Implements Array methods as specified in ECMA-262. *) 4 + 5 + open Quickjs_runtime.Value 6 + 7 + (** Helper to get array elements from an object *) 8 + let get_array_elements obj = 9 + match obj.data with 10 + | Data_array arr -> Some !arr 11 + | _ -> None 12 + 13 + (** Helper to set array elements *) 14 + let set_array_elements obj elements = 15 + match obj.data with 16 + | Data_array arr -> 17 + arr := elements; 18 + ignore (set_property obj "length" (Int (Int32.of_int (Array.length elements)))) 19 + | _ -> () 20 + 21 + (** Helper to get length of array-like object *) 22 + let get_length obj = 23 + match get_property obj "length" with 24 + | Some (Int i) -> Int32.to_int i 25 + | Some v -> int_of_float (to_float v) 26 + | None -> 0 27 + 28 + (** Array.isArray(arg) *) 29 + let is_array _this args = 30 + match args with 31 + | Object { class_id = Class_array; _ } :: _ -> Bool true 32 + | _ -> Bool false 33 + 34 + (** Array.from(arrayLike, mapFn?, thisArg?) *) 35 + let from _this args = 36 + match args with 37 + | [] -> make_array [] 38 + | arg :: rest -> 39 + let map_fn = List.nth_opt rest 0 in 40 + let _this_arg = List.nth_opt rest 1 in 41 + match arg with 42 + | Object { data = Data_array arr; _ } -> 43 + let elements = Array.to_list !arr in 44 + let mapped = match map_fn with 45 + | Some (Object { data = Data_native_function { func; _ }; _ }) -> 46 + List.mapi (fun i v -> func Undefined [v; Int (Int32.of_int i)]) elements 47 + | _ -> elements 48 + in 49 + make_array mapped 50 + | String s -> 51 + let chars = List.init (String.length s) (fun i -> String (String.make 1 s.[i])) in 52 + make_array chars 53 + | Object obj -> 54 + let len = get_length obj in 55 + let elements = List.init len (fun i -> 56 + match get_property obj (string_of_int i) with 57 + | Some v -> v 58 + | None -> Undefined 59 + ) in 60 + make_array elements 61 + | _ -> make_array [] 62 + 63 + (** Array.of(...items) *) 64 + let of_ _this args = 65 + make_array args 66 + 67 + (** Array.prototype.push(...items) *) 68 + let push this args = 69 + match this with 70 + | Object ({ data = Data_array arr; _ } as obj) -> 71 + let new_elements = Array.append !arr (Array.of_list args) in 72 + arr := new_elements; 73 + let len = Array.length new_elements in 74 + ignore (set_property obj "length" (Int (Int32.of_int len))); 75 + Int (Int32.of_int len) 76 + | _ -> Int 0l 77 + 78 + (** Array.prototype.pop() *) 79 + let pop this _args = 80 + match this with 81 + | Object ({ data = Data_array arr; _ } as obj) -> 82 + let len = Array.length !arr in 83 + if len = 0 then Undefined 84 + else begin 85 + let value = !arr.(len - 1) in 86 + arr := Array.sub !arr 0 (len - 1); 87 + ignore (set_property obj "length" (Int (Int32.of_int (len - 1)))); 88 + value 89 + end 90 + | _ -> Undefined 91 + 92 + (** Array.prototype.shift() *) 93 + let shift this _args = 94 + match this with 95 + | Object ({ data = Data_array arr; _ } as obj) -> 96 + let len = Array.length !arr in 97 + if len = 0 then Undefined 98 + else begin 99 + let value = !arr.(0) in 100 + arr := Array.sub !arr 1 (len - 1); 101 + ignore (set_property obj "length" (Int (Int32.of_int (len - 1)))); 102 + value 103 + end 104 + | _ -> Undefined 105 + 106 + (** Array.prototype.unshift(...items) *) 107 + let unshift this args = 108 + match this with 109 + | Object ({ data = Data_array arr; _ } as obj) -> 110 + let new_elements = Array.append (Array.of_list args) !arr in 111 + arr := new_elements; 112 + let len = Array.length new_elements in 113 + ignore (set_property obj "length" (Int (Int32.of_int len))); 114 + Int (Int32.of_int len) 115 + | _ -> Int 0l 116 + 117 + (** Array.prototype.slice(start?, end?) *) 118 + let slice this args = 119 + match this with 120 + | Object { data = Data_array arr; _ } -> 121 + let len = Array.length !arr in 122 + let start = match List.nth_opt args 0 with 123 + | Some v -> 124 + let s = int_of_float (to_float v) in 125 + if s < 0 then max 0 (len + s) else min s len 126 + | None -> 0 127 + in 128 + let end_ = match List.nth_opt args 1 with 129 + | Some Undefined | None -> len 130 + | Some v -> 131 + let e = int_of_float (to_float v) in 132 + if e < 0 then max 0 (len + e) else min e len 133 + in 134 + let slice_len = max 0 (end_ - start) in 135 + let elements = Array.sub !arr start slice_len in 136 + make_array (Array.to_list elements) 137 + | _ -> make_array [] 138 + 139 + (** Array.prototype.splice(start, deleteCount?, ...items) *) 140 + let splice this args = 141 + match this with 142 + | Object ({ data = Data_array arr; _ } as obj) -> 143 + let len = Array.length !arr in 144 + let start = match List.nth_opt args 0 with 145 + | Some v -> 146 + let s = int_of_float (to_float v) in 147 + if s < 0 then max 0 (len + s) else min s len 148 + | None -> 0 149 + in 150 + let delete_count = match List.nth_opt args 1 with 151 + | Some Undefined | None -> len - start 152 + | Some v -> min (max 0 (int_of_float (to_float v))) (len - start) 153 + in 154 + let items = match args with 155 + | _ :: _ :: rest -> rest 156 + | _ -> [] 157 + in 158 + let deleted = Array.sub !arr start delete_count in 159 + let before = Array.sub !arr 0 start in 160 + let after = Array.sub !arr (start + delete_count) (len - start - delete_count) in 161 + let new_arr = Array.concat [before; Array.of_list items; after] in 162 + arr := new_arr; 163 + ignore (set_property obj "length" (Int (Int32.of_int (Array.length new_arr)))); 164 + make_array (Array.to_list deleted) 165 + | _ -> make_array [] 166 + 167 + (** Array.prototype.concat(...items) *) 168 + let concat this args = 169 + match this with 170 + | Object { data = Data_array arr; _ } -> 171 + let result = ref (Array.to_list !arr) in 172 + List.iter (fun arg -> 173 + match arg with 174 + | Object { data = Data_array a; _ } -> 175 + result := !result @ Array.to_list !a 176 + | v -> result := !result @ [v] 177 + ) args; 178 + make_array !result 179 + | _ -> make_array [] 180 + 181 + (** Array.prototype.join(separator?) *) 182 + let join this args = 183 + match this with 184 + | Object { data = Data_array arr; _ } -> 185 + let sep = match List.nth_opt args 0 with 186 + | Some Undefined | None -> "," 187 + | Some v -> to_string v 188 + in 189 + let strs = Array.map (fun v -> 190 + match v with 191 + | Undefined | Null -> "" 192 + | v -> to_string v 193 + ) !arr in 194 + String (String.concat sep (Array.to_list strs)) 195 + | _ -> String "" 196 + 197 + (** Array.prototype.reverse() *) 198 + let reverse this _args = 199 + match this with 200 + | Object ({ data = Data_array arr; _ } as obj) -> 201 + let len = Array.length !arr in 202 + for i = 0 to len / 2 - 1 do 203 + let temp = !arr.(i) in 204 + !arr.(i) <- !arr.(len - 1 - i); 205 + !arr.(len - 1 - i) <- temp 206 + done; 207 + Object obj 208 + | _ -> Undefined 209 + 210 + (** Array.prototype.indexOf(searchElement, fromIndex?) *) 211 + let index_of this args = 212 + match this with 213 + | Object { data = Data_array arr; _ } -> 214 + let len = Array.length !arr in 215 + let search = List.nth_opt args 0 |> Option.value ~default:Undefined in 216 + let from_idx = match List.nth_opt args 1 with 217 + | Some v -> 218 + let i = int_of_float (to_float v) in 219 + if i < 0 then max 0 (len + i) else i 220 + | None -> 0 221 + in 222 + let rec find i = 223 + if i >= len then Int (-1l) 224 + else if strict_equal !arr.(i) search then Int (Int32.of_int i) 225 + else find (i + 1) 226 + in 227 + find from_idx 228 + | _ -> Int (-1l) 229 + 230 + (** Array.prototype.lastIndexOf(searchElement, fromIndex?) *) 231 + let last_index_of this args = 232 + match this with 233 + | Object { data = Data_array arr; _ } -> 234 + let len = Array.length !arr in 235 + let search = List.nth_opt args 0 |> Option.value ~default:Undefined in 236 + let from_idx = match List.nth_opt args 1 with 237 + | Some Undefined | None -> len - 1 238 + | Some v -> 239 + let i = int_of_float (to_float v) in 240 + if i < 0 then len + i else min i (len - 1) 241 + in 242 + let rec find i = 243 + if i < 0 then Int (-1l) 244 + else if strict_equal !arr.(i) search then Int (Int32.of_int i) 245 + else find (i - 1) 246 + in 247 + find from_idx 248 + | _ -> Int (-1l) 249 + 250 + (** Array.prototype.includes(searchElement, fromIndex?) *) 251 + let includes this args = 252 + match index_of this args with 253 + | Int i -> Bool (i >= 0l) 254 + | _ -> Bool false 255 + 256 + (** Array.prototype.forEach(callback, thisArg?) *) 257 + let for_each this args = 258 + match this, args with 259 + | Object { data = Data_array arr; _ }, callback :: rest -> 260 + let this_arg = List.nth_opt rest 0 |> Option.value ~default:Undefined in 261 + Array.iteri (fun i v -> 262 + match callback with 263 + | Object { data = Data_native_function { func; _ }; _ } -> 264 + ignore (func this_arg [v; Int (Int32.of_int i); this]) 265 + | _ -> () 266 + ) !arr; 267 + Undefined 268 + | _ -> Undefined 269 + 270 + (** Array.prototype.map(callback, thisArg?) *) 271 + let map this args = 272 + match this, args with 273 + | Object { data = Data_array arr; _ }, callback :: rest -> 274 + let this_arg = List.nth_opt rest 0 |> Option.value ~default:Undefined in 275 + let results = Array.mapi (fun i v -> 276 + match callback with 277 + | Object { data = Data_native_function { func; _ }; _ } -> 278 + func this_arg [v; Int (Int32.of_int i); this] 279 + | _ -> Undefined 280 + ) !arr in 281 + make_array (Array.to_list results) 282 + | _ -> make_array [] 283 + 284 + (** Array.prototype.filter(callback, thisArg?) *) 285 + let filter this args = 286 + match this, args with 287 + | Object { data = Data_array arr; _ }, callback :: rest -> 288 + let this_arg = List.nth_opt rest 0 |> Option.value ~default:Undefined in 289 + let results = Array.to_list !arr |> List.mapi (fun i v -> 290 + let keep = match callback with 291 + | Object { data = Data_native_function { func; _ }; _ } -> 292 + to_boolean (func this_arg [v; Int (Int32.of_int i); this]) 293 + | _ -> false 294 + in 295 + if keep then Some v else None 296 + ) |> List.filter_map Fun.id in 297 + make_array results 298 + | _ -> make_array [] 299 + 300 + (** Array.prototype.reduce(callback, initialValue?) *) 301 + let reduce this args = 302 + match this, args with 303 + | Object { data = Data_array arr; _ }, callback :: rest -> 304 + let len = Array.length !arr in 305 + if len = 0 && List.length rest = 0 then 306 + (* TypeError: Reduce of empty array with no initial value *) 307 + Undefined 308 + else 309 + let init_val, start_idx = match rest with 310 + | init :: _ -> (init, 0) 311 + | [] -> (!arr.(0), 1) 312 + in 313 + let rec loop acc i = 314 + if i >= len then acc 315 + else 316 + let new_acc = match callback with 317 + | Object { data = Data_native_function { func; _ }; _ } -> 318 + func Undefined [acc; !arr.(i); Int (Int32.of_int i); this] 319 + | _ -> acc 320 + in 321 + loop new_acc (i + 1) 322 + in 323 + loop init_val start_idx 324 + | _ -> Undefined 325 + 326 + (** Array.prototype.find(callback, thisArg?) *) 327 + let find this args = 328 + match this, args with 329 + | Object { data = Data_array arr; _ }, callback :: rest -> 330 + let this_arg = List.nth_opt rest 0 |> Option.value ~default:Undefined in 331 + let len = Array.length !arr in 332 + let rec loop i = 333 + if i >= len then Undefined 334 + else 335 + let v = !arr.(i) in 336 + let found = match callback with 337 + | Object { data = Data_native_function { func; _ }; _ } -> 338 + to_boolean (func this_arg [v; Int (Int32.of_int i); this]) 339 + | _ -> false 340 + in 341 + if found then v else loop (i + 1) 342 + in 343 + loop 0 344 + | _ -> Undefined 345 + 346 + (** Array.prototype.findIndex(callback, thisArg?) *) 347 + let find_index this args = 348 + match this, args with 349 + | Object { data = Data_array arr; _ }, callback :: rest -> 350 + let this_arg = List.nth_opt rest 0 |> Option.value ~default:Undefined in 351 + let len = Array.length !arr in 352 + let rec loop i = 353 + if i >= len then Int (-1l) 354 + else 355 + let v = !arr.(i) in 356 + let found = match callback with 357 + | Object { data = Data_native_function { func; _ }; _ } -> 358 + to_boolean (func this_arg [v; Int (Int32.of_int i); this]) 359 + | _ -> false 360 + in 361 + if found then Int (Int32.of_int i) else loop (i + 1) 362 + in 363 + loop 0 364 + | _ -> Int (-1l) 365 + 366 + (** Array.prototype.every(callback, thisArg?) *) 367 + let every this args = 368 + match this, args with 369 + | Object { data = Data_array arr; _ }, callback :: rest -> 370 + let this_arg = List.nth_opt rest 0 |> Option.value ~default:Undefined in 371 + let len = Array.length !arr in 372 + let rec loop i = 373 + if i >= len then Bool true 374 + else 375 + let v = !arr.(i) in 376 + let result = match callback with 377 + | Object { data = Data_native_function { func; _ }; _ } -> 378 + to_boolean (func this_arg [v; Int (Int32.of_int i); this]) 379 + | _ -> false 380 + in 381 + if result then loop (i + 1) else Bool false 382 + in 383 + loop 0 384 + | _ -> Bool true 385 + 386 + (** Array.prototype.some(callback, thisArg?) *) 387 + let some this args = 388 + match this, args with 389 + | Object { data = Data_array arr; _ }, callback :: rest -> 390 + let this_arg = List.nth_opt rest 0 |> Option.value ~default:Undefined in 391 + let len = Array.length !arr in 392 + let rec loop i = 393 + if i >= len then Bool false 394 + else 395 + let v = !arr.(i) in 396 + let result = match callback with 397 + | Object { data = Data_native_function { func; _ }; _ } -> 398 + to_boolean (func this_arg [v; Int (Int32.of_int i); this]) 399 + | _ -> false 400 + in 401 + if result then Bool true else loop (i + 1) 402 + in 403 + loop 0 404 + | _ -> Bool false 405 + 406 + (** Array.prototype.fill(value, start?, end?) *) 407 + let fill this args = 408 + match this with 409 + | Object ({ data = Data_array arr; _ } as obj) -> 410 + let len = Array.length !arr in 411 + let value = List.nth_opt args 0 |> Option.value ~default:Undefined in 412 + let start = match List.nth_opt args 1 with 413 + | Some Undefined | None -> 0 414 + | Some v -> 415 + let s = int_of_float (to_float v) in 416 + if s < 0 then max 0 (len + s) else min s len 417 + in 418 + let end_ = match List.nth_opt args 2 with 419 + | Some Undefined | None -> len 420 + | Some v -> 421 + let e = int_of_float (to_float v) in 422 + if e < 0 then max 0 (len + e) else min e len 423 + in 424 + for i = start to end_ - 1 do 425 + !arr.(i) <- value 426 + done; 427 + Object obj 428 + | _ -> Undefined 429 + 430 + (** Array.prototype.flat(depth?) *) 431 + let flat this args = 432 + match this with 433 + | Object { data = Data_array arr; _ } -> 434 + let depth = match List.nth_opt args 0 with 435 + | Some Undefined | None -> 1 436 + | Some v -> int_of_float (to_float v) 437 + in 438 + let rec flatten d elements = 439 + if d <= 0 then elements 440 + else 441 + List.concat_map (fun v -> 442 + match v with 443 + | Object { data = Data_array a; _ } -> 444 + flatten (d - 1) (Array.to_list !a) 445 + | v -> [v] 446 + ) elements 447 + in 448 + make_array (flatten depth (Array.to_list !arr)) 449 + | _ -> make_array [] 450 + 451 + (** Array.prototype.toString() *) 452 + let to_string_method this _args = 453 + join this [String ","] 454 + 455 + (** Create Array constructor and prototype *) 456 + let create () = 457 + let proto = make_object () in 458 + 459 + (* Array.prototype methods *) 460 + let add_proto_method name length func = 461 + let fn = make_native_function name length func in 462 + match fn with 463 + | Object obj -> 464 + Hashtbl.add proto.properties name 465 + { value = Object obj; 466 + flags = { writable = true; enumerable = false; configurable = true }; 467 + getter = None; setter = None } 468 + | _ -> () 469 + in 470 + 471 + add_proto_method "push" 1 push; 472 + add_proto_method "pop" 0 pop; 473 + add_proto_method "shift" 0 shift; 474 + add_proto_method "unshift" 1 unshift; 475 + add_proto_method "slice" 2 slice; 476 + add_proto_method "splice" 2 splice; 477 + add_proto_method "concat" 1 concat; 478 + add_proto_method "join" 1 join; 479 + add_proto_method "reverse" 0 reverse; 480 + add_proto_method "indexOf" 1 index_of; 481 + add_proto_method "lastIndexOf" 1 last_index_of; 482 + add_proto_method "includes" 1 includes; 483 + add_proto_method "forEach" 1 for_each; 484 + add_proto_method "map" 1 map; 485 + add_proto_method "filter" 1 filter; 486 + add_proto_method "reduce" 1 reduce; 487 + add_proto_method "find" 1 find; 488 + add_proto_method "findIndex" 1 find_index; 489 + add_proto_method "every" 1 every; 490 + add_proto_method "some" 1 some; 491 + add_proto_method "fill" 1 fill; 492 + add_proto_method "flat" 0 flat; 493 + add_proto_method "toString" 0 to_string_method; 494 + 495 + (* Array constructor *) 496 + let array_ctor _this args = 497 + match args with 498 + | [Int n] -> 499 + let len = Int32.to_int n in 500 + make_array (List.init len (fun _ -> Undefined)) 501 + | [Float n] when Float.is_integer n -> 502 + let len = int_of_float n in 503 + make_array (List.init len (fun _ -> Undefined)) 504 + | _ -> make_array args 505 + in 506 + 507 + let ctor = make_object () in 508 + let ctor_fn = make_native_function "Array" 1 array_ctor in 509 + (match ctor_fn with 510 + | Object obj -> 511 + ctor.data <- obj.data; 512 + ctor.class_id <- Class_function 513 + | _ -> ()); 514 + 515 + (* Static methods *) 516 + let add_static_method name length func = 517 + let fn = make_native_function name length func in 518 + match fn with 519 + | Object obj -> 520 + Hashtbl.add ctor.properties name 521 + { value = Object obj; 522 + flags = { writable = true; enumerable = false; configurable = true }; 523 + getter = None; setter = None } 524 + | _ -> () 525 + in 526 + 527 + add_static_method "isArray" 1 is_array; 528 + add_static_method "from" 1 from; 529 + add_static_method "of" 0 of_; 530 + 531 + (* Link prototype *) 532 + Hashtbl.add ctor.properties "prototype" 533 + { value = Object proto; 534 + flags = { writable = false; enumerable = false; configurable = false }; 535 + getter = None; setter = None }; 536 + 537 + Hashtbl.add proto.properties "constructor" 538 + { value = Object ctor; 539 + flags = { writable = true; enumerable = false; configurable = true }; 540 + getter = None; setter = None }; 541 + 542 + (Object ctor, Object proto)
+418
lib/quickjs/builtins/js_object.ml
··· 1 + (** JavaScript Object built-in. 2 + 3 + Implements Object methods as specified in ECMA-262. *) 4 + 5 + open Quickjs_runtime.Value 6 + 7 + (** Object.keys(obj) *) 8 + let keys _this args = 9 + match args with 10 + | Object obj :: _ -> 11 + let names = Hashtbl.fold (fun k prop acc -> 12 + if prop.flags.enumerable then k :: acc else acc 13 + ) obj.properties [] in 14 + make_array (List.map (fun s -> String s) names) 15 + | _ -> make_array [] 16 + 17 + (** Object.values(obj) *) 18 + let values _this args = 19 + match args with 20 + | Object obj :: _ -> 21 + let vals = Hashtbl.fold (fun _ prop acc -> 22 + if prop.flags.enumerable then prop.value :: acc else acc 23 + ) obj.properties [] in 24 + make_array vals 25 + | _ -> make_array [] 26 + 27 + (** Object.entries(obj) *) 28 + let entries _this args = 29 + match args with 30 + | Object obj :: _ -> 31 + let pairs = Hashtbl.fold (fun k prop acc -> 32 + if prop.flags.enumerable then 33 + make_array [String k; prop.value] :: acc 34 + else acc 35 + ) obj.properties [] in 36 + make_array pairs 37 + | _ -> make_array [] 38 + 39 + (** Object.assign(target, ...sources) *) 40 + let assign _this args = 41 + match args with 42 + | [] -> Undefined 43 + | target :: sources -> 44 + (match target with 45 + | Object target_obj -> 46 + List.iter (fun source -> 47 + match source with 48 + | Object src_obj -> 49 + Hashtbl.iter (fun k prop -> 50 + if prop.flags.enumerable then 51 + ignore (set_property target_obj k prop.value) 52 + ) src_obj.properties 53 + | _ -> () 54 + ) sources; 55 + Object target_obj 56 + | _ -> target) 57 + 58 + (** Object.create(proto, propertiesObject?) *) 59 + let create _this args = 60 + let proto = match List.nth_opt args 0 with 61 + | Some Null -> Null 62 + | Some (Object _ as p) -> p 63 + | _ -> Null 64 + in 65 + let obj = make_object ~prototype:proto () in 66 + (* TODO: Handle propertiesObject parameter *) 67 + Object obj 68 + 69 + (** Object.freeze(obj) *) 70 + let freeze _this args = 71 + match args with 72 + | Object obj :: _ -> 73 + obj.extensible <- false; 74 + Hashtbl.iter (fun k prop -> 75 + Hashtbl.replace obj.properties k 76 + { prop with flags = { prop.flags with writable = false; configurable = false } } 77 + ) obj.properties; 78 + Object obj 79 + | v :: _ -> v 80 + | [] -> Undefined 81 + 82 + (** Object.seal(obj) *) 83 + let seal _this args = 84 + match args with 85 + | Object obj :: _ -> 86 + obj.extensible <- false; 87 + Hashtbl.iter (fun k prop -> 88 + Hashtbl.replace obj.properties k 89 + { prop with flags = { prop.flags with configurable = false } } 90 + ) obj.properties; 91 + Object obj 92 + | v :: _ -> v 93 + | [] -> Undefined 94 + 95 + (** Object.isFrozen(obj) *) 96 + let is_frozen _this args = 97 + match args with 98 + | Object obj :: _ -> 99 + if obj.extensible then Bool false 100 + else 101 + let frozen = Hashtbl.fold (fun _ prop acc -> 102 + acc && not prop.flags.writable && not prop.flags.configurable 103 + ) obj.properties true in 104 + Bool frozen 105 + | _ -> Bool true 106 + 107 + (** Object.isSealed(obj) *) 108 + let is_sealed _this args = 109 + match args with 110 + | Object obj :: _ -> 111 + if obj.extensible then Bool false 112 + else 113 + let sealed = Hashtbl.fold (fun _ prop acc -> 114 + acc && not prop.flags.configurable 115 + ) obj.properties true in 116 + Bool sealed 117 + | _ -> Bool true 118 + 119 + (** Object.isExtensible(obj) *) 120 + let is_extensible _this args = 121 + match args with 122 + | Object obj :: _ -> Bool obj.extensible 123 + | _ -> Bool false 124 + 125 + (** Object.preventExtensions(obj) *) 126 + let prevent_extensions _this args = 127 + match args with 128 + | Object obj :: _ -> 129 + obj.extensible <- false; 130 + Object obj 131 + | v :: _ -> v 132 + | [] -> Undefined 133 + 134 + (** Object.getPrototypeOf(obj) *) 135 + let get_prototype_of _this args = 136 + match args with 137 + | Object obj :: _ -> obj.prototype 138 + | _ -> Null 139 + 140 + (** Object.setPrototypeOf(obj, proto) *) 141 + let set_prototype_of _this args = 142 + match args with 143 + | Object obj :: proto :: _ -> 144 + (match proto with 145 + | Null | Object _ -> 146 + obj.prototype <- proto; 147 + Object obj 148 + | _ -> Object obj) (* TypeError in strict mode *) 149 + | v :: _ -> v 150 + | [] -> Undefined 151 + 152 + (** Object.defineProperty(obj, prop, descriptor) *) 153 + let define_property _this args = 154 + match args with 155 + | Object obj :: String prop_name :: Object desc :: _ -> 156 + let value = match get_property desc "value" with 157 + | Some v -> v 158 + | None -> Undefined 159 + in 160 + let writable = match get_property desc "writable" with 161 + | Some v -> to_boolean v 162 + | None -> false 163 + in 164 + let enumerable = match get_property desc "enumerable" with 165 + | Some v -> to_boolean v 166 + | None -> false 167 + in 168 + let configurable = match get_property desc "configurable" with 169 + | Some v -> to_boolean v 170 + | None -> false 171 + in 172 + let getter = get_property desc "get" in 173 + let setter = get_property desc "set" in 174 + Hashtbl.replace obj.properties prop_name 175 + { value; 176 + flags = { writable; enumerable; configurable }; 177 + getter; setter }; 178 + Object obj 179 + | v :: _ -> v 180 + | [] -> Undefined 181 + 182 + (** Object.defineProperties(obj, props) *) 183 + let define_properties _this args = 184 + match args with 185 + | Object obj :: Object props :: _ -> 186 + Hashtbl.iter (fun key prop -> 187 + if prop.flags.enumerable then 188 + match prop.value with 189 + | Object desc -> 190 + let value = match get_property desc "value" with 191 + | Some v -> v 192 + | None -> Undefined 193 + in 194 + let writable = match get_property desc "writable" with 195 + | Some v -> to_boolean v 196 + | None -> false 197 + in 198 + let enumerable = match get_property desc "enumerable" with 199 + | Some v -> to_boolean v 200 + | None -> false 201 + in 202 + let configurable = match get_property desc "configurable" with 203 + | Some v -> to_boolean v 204 + | None -> false 205 + in 206 + Hashtbl.replace obj.properties key 207 + { value; 208 + flags = { writable; enumerable; configurable }; 209 + getter = None; setter = None } 210 + | _ -> () 211 + ) props.properties; 212 + Object obj 213 + | v :: _ -> v 214 + | [] -> Undefined 215 + 216 + (** Object.getOwnPropertyDescriptor(obj, prop) *) 217 + let get_own_property_descriptor _this args = 218 + match args with 219 + | Object obj :: key :: _ -> 220 + let prop_name = to_string key in 221 + (match Hashtbl.find_opt obj.properties prop_name with 222 + | Some prop -> 223 + let desc = make_object () in 224 + ignore (set_property desc "value" prop.value); 225 + ignore (set_property desc "writable" (Bool prop.flags.writable)); 226 + ignore (set_property desc "enumerable" (Bool prop.flags.enumerable)); 227 + ignore (set_property desc "configurable" (Bool prop.flags.configurable)); 228 + Object desc 229 + | None -> Undefined) 230 + | _ -> Undefined 231 + 232 + (** Object.getOwnPropertyNames(obj) *) 233 + let get_own_property_names _this args = 234 + match args with 235 + | Object obj :: _ -> 236 + let names = Hashtbl.fold (fun k _ acc -> String k :: acc) obj.properties [] in 237 + make_array names 238 + | _ -> make_array [] 239 + 240 + (** Object.hasOwn(obj, prop) *) 241 + let has_own _this args = 242 + match args with 243 + | Object obj :: key :: _ -> 244 + let prop_name = to_string key in 245 + Bool (has_own_property obj prop_name) 246 + | _ -> Bool false 247 + 248 + (** Object.fromEntries(iterable) *) 249 + let from_entries _this args = 250 + match args with 251 + | Object { data = Data_array arr; _ } :: _ -> 252 + let obj = make_object () in 253 + Array.iter (fun entry -> 254 + match entry with 255 + | Object { data = Data_array pair; _ } when Array.length !pair >= 2 -> 256 + let key = to_string !pair.(0) in 257 + let value = !pair.(1) in 258 + ignore (set_property obj key value) 259 + | _ -> () 260 + ) !arr; 261 + Object obj 262 + | _ -> Object (make_object ()) 263 + 264 + (** Object.prototype.hasOwnProperty(prop) *) 265 + let has_own_property_method this args = 266 + match this with 267 + | Object obj -> 268 + let prop_name = match args with 269 + | key :: _ -> to_string key 270 + | [] -> "undefined" 271 + in 272 + Bool (has_own_property obj prop_name) 273 + | _ -> Bool false 274 + 275 + (** Object.prototype.isPrototypeOf(obj) *) 276 + let is_prototype_of this args = 277 + match args with 278 + | Object obj :: _ -> 279 + let rec check proto = 280 + match proto with 281 + | Null -> false 282 + | Object p when strict_equal (Object p) this -> true 283 + | Object p -> check p.prototype 284 + | _ -> false 285 + in 286 + Bool (check obj.prototype) 287 + | _ -> Bool false 288 + 289 + (** Object.prototype.propertyIsEnumerable(prop) *) 290 + let property_is_enumerable this args = 291 + match this with 292 + | Object obj -> 293 + let prop_name = match args with 294 + | key :: _ -> to_string key 295 + | [] -> "undefined" 296 + in 297 + (match Hashtbl.find_opt obj.properties prop_name with 298 + | Some prop -> Bool prop.flags.enumerable 299 + | None -> Bool false) 300 + | _ -> Bool false 301 + 302 + (** Object.prototype.toString() *) 303 + let to_string_method this _args = 304 + match this with 305 + | Undefined -> String "[object Undefined]" 306 + | Null -> String "[object Null]" 307 + | Bool _ -> String "[object Boolean]" 308 + | Int _ | Float _ -> String "[object Number]" 309 + | String _ -> String "[object String]" 310 + | Symbol _ -> String "[object Symbol]" 311 + | BigInt _ -> String "[object BigInt]" 312 + | Object obj -> 313 + let tag = match obj.class_id with 314 + | Class_array -> "Array" 315 + | Class_function | Class_bound_function -> "Function" 316 + | Class_error -> "Error" 317 + | Class_regexp -> "RegExp" 318 + | Class_date -> "Date" 319 + | Class_map -> "Map" 320 + | Class_set -> "Set" 321 + | Class_promise -> "Promise" 322 + | _ -> "Object" 323 + in 324 + String ("[object " ^ tag ^ "]") 325 + | Exception _ -> String "[object Error]" 326 + | Uninitialized -> String "[object Undefined]" 327 + 328 + (** Object.prototype.valueOf() *) 329 + let value_of this _args = this 330 + 331 + (** Create Object constructor and prototype *) 332 + let create_builtin () = 333 + let proto = make_object () in 334 + 335 + (* Object.prototype methods *) 336 + let add_proto_method name length func = 337 + let fn = make_native_function name length func in 338 + match fn with 339 + | Object obj -> 340 + Hashtbl.add proto.properties name 341 + { value = Object obj; 342 + flags = { writable = true; enumerable = false; configurable = true }; 343 + getter = None; setter = None } 344 + | _ -> () 345 + in 346 + 347 + add_proto_method "hasOwnProperty" 1 has_own_property_method; 348 + add_proto_method "isPrototypeOf" 1 is_prototype_of; 349 + add_proto_method "propertyIsEnumerable" 1 property_is_enumerable; 350 + add_proto_method "toString" 0 to_string_method; 351 + add_proto_method "valueOf" 0 value_of; 352 + 353 + (* Object constructor *) 354 + let object_ctor _this args = 355 + match args with 356 + | [] | [Undefined] | [Null] -> Object (make_object ()) 357 + | v :: _ -> 358 + match v with 359 + | Object _ -> v 360 + | _ -> 361 + (* Convert primitive to object wrapper *) 362 + let obj = make_object () in 363 + ignore (set_property obj "[[PrimitiveValue]]" v); 364 + Object obj 365 + in 366 + 367 + let ctor = make_object () in 368 + let ctor_fn = make_native_function "Object" 1 object_ctor in 369 + (match ctor_fn with 370 + | Object obj -> 371 + ctor.data <- obj.data; 372 + ctor.class_id <- Class_function 373 + | _ -> ()); 374 + 375 + (* Static methods *) 376 + let add_static_method name length func = 377 + let fn = make_native_function name length func in 378 + match fn with 379 + | Object obj -> 380 + Hashtbl.add ctor.properties name 381 + { value = Object obj; 382 + flags = { writable = true; enumerable = false; configurable = true }; 383 + getter = None; setter = None } 384 + | _ -> () 385 + in 386 + 387 + add_static_method "keys" 1 keys; 388 + add_static_method "values" 1 values; 389 + add_static_method "entries" 1 entries; 390 + add_static_method "assign" 2 assign; 391 + add_static_method "create" 2 create; 392 + add_static_method "freeze" 1 freeze; 393 + add_static_method "seal" 1 seal; 394 + add_static_method "isFrozen" 1 is_frozen; 395 + add_static_method "isSealed" 1 is_sealed; 396 + add_static_method "isExtensible" 1 is_extensible; 397 + add_static_method "preventExtensions" 1 prevent_extensions; 398 + add_static_method "getPrototypeOf" 1 get_prototype_of; 399 + add_static_method "setPrototypeOf" 2 set_prototype_of; 400 + add_static_method "defineProperty" 3 define_property; 401 + add_static_method "defineProperties" 2 define_properties; 402 + add_static_method "getOwnPropertyDescriptor" 2 get_own_property_descriptor; 403 + add_static_method "getOwnPropertyNames" 1 get_own_property_names; 404 + add_static_method "hasOwn" 2 has_own; 405 + add_static_method "fromEntries" 1 from_entries; 406 + 407 + (* Link prototype *) 408 + Hashtbl.add ctor.properties "prototype" 409 + { value = Object proto; 410 + flags = { writable = false; enumerable = false; configurable = false }; 411 + getter = None; setter = None }; 412 + 413 + Hashtbl.add proto.properties "constructor" 414 + { value = Object ctor; 415 + flags = { writable = true; enumerable = false; configurable = true }; 416 + getter = None; setter = None }; 417 + 418 + (Object ctor, Object proto)
+450
lib/quickjs/builtins/js_string.ml
··· 1 + (** JavaScript String built-in object. 2 + 3 + Implements String methods as specified in ECMA-262. *) 4 + 5 + open Quickjs_runtime.Value 6 + 7 + (** Helper to get string from value *) 8 + let get_string v = 9 + match v with 10 + | String s -> s 11 + | _ -> to_string v 12 + 13 + (** Helper to get this as string *) 14 + let this_string this = 15 + match this with 16 + | String s -> s 17 + | Object { data = Data_none; _ } -> 18 + (match get_property (match this with Object o -> o | _ -> failwith "not object") "[[PrimitiveValue]]" with 19 + | Some (String s) -> s 20 + | _ -> to_string this) 21 + | _ -> to_string this 22 + 23 + (** String.fromCharCode(...codes) *) 24 + let from_char_code _this args = 25 + let chars = List.map (fun v -> 26 + let code = int_of_float (to_float v) in 27 + let code = code land 0xFFFF in 28 + if code < 128 then String.make 1 (Char.chr code) 29 + else 30 + (* Simple UTF-8 encoding for BMP characters *) 31 + if code < 0x800 then 32 + String.init 2 (fun i -> 33 + if i = 0 then Char.chr (0xC0 lor (code lsr 6)) 34 + else Char.chr (0x80 lor (code land 0x3F))) 35 + else 36 + String.init 3 (fun i -> 37 + if i = 0 then Char.chr (0xE0 lor (code lsr 12)) 38 + else if i = 1 then Char.chr (0x80 lor ((code lsr 6) land 0x3F)) 39 + else Char.chr (0x80 lor (code land 0x3F))) 40 + ) args in 41 + String (String.concat "" chars) 42 + 43 + (** String.fromCodePoint(...codePoints) *) 44 + let from_code_point _this args = 45 + let chars = List.map (fun v -> 46 + let code = int_of_float (to_float v) in 47 + if code < 0 || code > 0x10FFFF then 48 + failwith "Invalid code point" 49 + else if code < 128 then 50 + String.make 1 (Char.chr code) 51 + else if code < 0x800 then 52 + String.init 2 (fun i -> 53 + if i = 0 then Char.chr (0xC0 lor (code lsr 6)) 54 + else Char.chr (0x80 lor (code land 0x3F))) 55 + else if code < 0x10000 then 56 + String.init 3 (fun i -> 57 + if i = 0 then Char.chr (0xE0 lor (code lsr 12)) 58 + else if i = 1 then Char.chr (0x80 lor ((code lsr 6) land 0x3F)) 59 + else Char.chr (0x80 lor (code land 0x3F))) 60 + else 61 + (* Surrogate pair for code points > 0xFFFF *) 62 + String.init 4 (fun i -> 63 + if i = 0 then Char.chr (0xF0 lor (code lsr 18)) 64 + else if i = 1 then Char.chr (0x80 lor ((code lsr 12) land 0x3F)) 65 + else if i = 2 then Char.chr (0x80 lor ((code lsr 6) land 0x3F)) 66 + else Char.chr (0x80 lor (code land 0x3F))) 67 + ) args in 68 + String (String.concat "" chars) 69 + 70 + (** String.prototype.charAt(index) *) 71 + let char_at this args = 72 + let s = this_string this in 73 + let idx = match List.nth_opt args 0 with 74 + | Some v -> int_of_float (to_float v) 75 + | None -> 0 76 + in 77 + if idx < 0 || idx >= String.length s then String "" 78 + else String (String.make 1 s.[idx]) 79 + 80 + (** String.prototype.charCodeAt(index) *) 81 + let char_code_at this args = 82 + let s = this_string this in 83 + let idx = match List.nth_opt args 0 with 84 + | Some v -> int_of_float (to_float v) 85 + | None -> 0 86 + in 87 + if idx < 0 || idx >= String.length s then Float Float.nan 88 + else Int (Int32.of_int (Char.code s.[idx])) 89 + 90 + (** String.prototype.concat(...strings) *) 91 + let concat this args = 92 + let s = this_string this in 93 + let parts = List.map get_string args in 94 + String (String.concat "" (s :: parts)) 95 + 96 + (** String.prototype.includes(searchString, position?) *) 97 + let includes this args = 98 + let s = this_string this in 99 + let search = match List.nth_opt args 0 with 100 + | Some v -> get_string v 101 + | None -> "undefined" 102 + in 103 + let pos = match List.nth_opt args 1 with 104 + | Some v -> max 0 (int_of_float (to_float v)) 105 + | None -> 0 106 + in 107 + let substring = if pos >= String.length s then "" else String.sub s pos (String.length s - pos) in 108 + try 109 + ignore (Str.search_forward (Str.regexp_string search) substring 0); 110 + Bool true 111 + with Not_found -> Bool false 112 + 113 + (** String.prototype.indexOf(searchString, position?) *) 114 + let index_of this args = 115 + let s = this_string this in 116 + let search = match List.nth_opt args 0 with 117 + | Some v -> get_string v 118 + | None -> "undefined" 119 + in 120 + let pos = match List.nth_opt args 1 with 121 + | Some v -> max 0 (int_of_float (to_float v)) 122 + | None -> 0 123 + in 124 + if pos >= String.length s then Int (-1l) 125 + else 126 + try 127 + let idx = Str.search_forward (Str.regexp_string search) s pos in 128 + Int (Int32.of_int idx) 129 + with Not_found -> Int (-1l) 130 + 131 + (** String.prototype.lastIndexOf(searchString, position?) *) 132 + let last_index_of this args = 133 + let s = this_string this in 134 + let search = match List.nth_opt args 0 with 135 + | Some v -> get_string v 136 + | None -> "undefined" 137 + in 138 + let pos = match List.nth_opt args 1 with 139 + | Some Undefined | None -> String.length s 140 + | Some v -> int_of_float (to_float v) 141 + in 142 + let pos = min pos (String.length s) in 143 + try 144 + let idx = Str.search_backward (Str.regexp_string search) s pos in 145 + Int (Int32.of_int idx) 146 + with Not_found -> Int (-1l) 147 + 148 + (** String.prototype.slice(start, end?) *) 149 + let slice this args = 150 + let s = this_string this in 151 + let len = String.length s in 152 + let start = match List.nth_opt args 0 with 153 + | Some v -> 154 + let i = int_of_float (to_float v) in 155 + if i < 0 then max 0 (len + i) else min i len 156 + | None -> 0 157 + in 158 + let end_ = match List.nth_opt args 1 with 159 + | Some Undefined | None -> len 160 + | Some v -> 161 + let i = int_of_float (to_float v) in 162 + if i < 0 then max 0 (len + i) else min i len 163 + in 164 + if start >= end_ then String "" 165 + else String (String.sub s start (end_ - start)) 166 + 167 + (** String.prototype.substring(start, end?) *) 168 + let substring this args = 169 + let s = this_string this in 170 + let len = String.length s in 171 + let start = match List.nth_opt args 0 with 172 + | Some v -> 173 + let i = int_of_float (to_float v) in 174 + max 0 (min i len) 175 + | None -> 0 176 + in 177 + let end_ = match List.nth_opt args 1 with 178 + | Some Undefined | None -> len 179 + | Some v -> 180 + let i = int_of_float (to_float v) in 181 + max 0 (min i len) 182 + in 183 + let start, end_ = if start > end_ then (end_, start) else (start, end_) in 184 + String (String.sub s start (end_ - start)) 185 + 186 + (** String.prototype.toLowerCase() *) 187 + let to_lower_case this _args = 188 + let s = this_string this in 189 + String (String.lowercase_ascii s) 190 + 191 + (** String.prototype.toUpperCase() *) 192 + let to_upper_case this _args = 193 + let s = this_string this in 194 + String (String.uppercase_ascii s) 195 + 196 + (** String.prototype.trim() *) 197 + let trim this _args = 198 + let s = this_string this in 199 + String (String.trim s) 200 + 201 + (** String.prototype.trimStart() / trimLeft() *) 202 + let trim_start this _args = 203 + let s = this_string this in 204 + let len = String.length s in 205 + let rec find_start i = 206 + if i >= len then len 207 + else match s.[i] with 208 + | ' ' | '\t' | '\n' | '\r' | '\x0C' -> find_start (i + 1) 209 + | _ -> i 210 + in 211 + let start = find_start 0 in 212 + String (String.sub s start (len - start)) 213 + 214 + (** String.prototype.trimEnd() / trimRight() *) 215 + let trim_end this _args = 216 + let s = this_string this in 217 + let rec find_end i = 218 + if i < 0 then 0 219 + else match s.[i] with 220 + | ' ' | '\t' | '\n' | '\r' | '\x0C' -> find_end (i - 1) 221 + | _ -> i + 1 222 + in 223 + let end_ = find_end (String.length s - 1) in 224 + String (String.sub s 0 end_) 225 + 226 + (** String.prototype.split(separator, limit?) *) 227 + let split this args = 228 + let s = this_string this in 229 + let limit = match List.nth_opt args 1 with 230 + | Some Undefined | None -> max_int 231 + | Some v -> int_of_float (to_float v) 232 + in 233 + if limit = 0 then make_array [] 234 + else 235 + match List.nth_opt args 0 with 236 + | Some Undefined | None -> 237 + make_array [String s] 238 + | Some (String "") -> 239 + (* Split into individual characters *) 240 + let chars = List.init (min limit (String.length s)) (fun i -> 241 + String (String.make 1 s.[i]) 242 + ) in 243 + make_array chars 244 + | Some sep -> 245 + let sep_str = get_string sep in 246 + let parts = Str.split_delim (Str.regexp_string sep_str) s in 247 + let limited = if List.length parts > limit 248 + then List.filteri (fun i _ -> i < limit) parts 249 + else parts 250 + in 251 + make_array (List.map (fun p -> String p) limited) 252 + 253 + (** String.prototype.repeat(count) *) 254 + let repeat this args = 255 + let s = this_string this in 256 + let count = match List.nth_opt args 0 with 257 + | Some v -> int_of_float (to_float v) 258 + | None -> 0 259 + in 260 + if count < 0 then Float Float.nan (* Should throw RangeError *) 261 + else if count = 0 || String.length s = 0 then String "" 262 + else String (String.concat "" (List.init count (fun _ -> s))) 263 + 264 + (** String.prototype.padStart(targetLength, padString?) *) 265 + let pad_start this args = 266 + let s = this_string this in 267 + let target_len = match List.nth_opt args 0 with 268 + | Some v -> int_of_float (to_float v) 269 + | None -> 0 270 + in 271 + let pad = match List.nth_opt args 1 with 272 + | Some Undefined | None -> " " 273 + | Some v -> get_string v 274 + in 275 + let current_len = String.length s in 276 + if target_len <= current_len || String.length pad = 0 then String s 277 + else 278 + let pad_needed = target_len - current_len in 279 + let full_pads = pad_needed / String.length pad in 280 + let partial = pad_needed mod String.length pad in 281 + let padding = String.concat "" (List.init full_pads (fun _ -> pad)) ^ 282 + String.sub pad 0 partial in 283 + String (padding ^ s) 284 + 285 + (** String.prototype.padEnd(targetLength, padString?) *) 286 + let pad_end this args = 287 + let s = this_string this in 288 + let target_len = match List.nth_opt args 0 with 289 + | Some v -> int_of_float (to_float v) 290 + | None -> 0 291 + in 292 + let pad = match List.nth_opt args 1 with 293 + | Some Undefined | None -> " " 294 + | Some v -> get_string v 295 + in 296 + let current_len = String.length s in 297 + if target_len <= current_len || String.length pad = 0 then String s 298 + else 299 + let pad_needed = target_len - current_len in 300 + let full_pads = pad_needed / String.length pad in 301 + let partial = pad_needed mod String.length pad in 302 + let padding = String.concat "" (List.init full_pads (fun _ -> pad)) ^ 303 + String.sub pad 0 partial in 304 + String (s ^ padding) 305 + 306 + (** String.prototype.startsWith(searchString, position?) *) 307 + let starts_with this args = 308 + let s = this_string this in 309 + let search = match List.nth_opt args 0 with 310 + | Some v -> get_string v 311 + | None -> "undefined" 312 + in 313 + let pos = match List.nth_opt args 1 with 314 + | Some v -> max 0 (int_of_float (to_float v)) 315 + | None -> 0 316 + in 317 + let search_len = String.length search in 318 + if pos + search_len > String.length s then Bool false 319 + else Bool (String.sub s pos search_len = search) 320 + 321 + (** String.prototype.endsWith(searchString, length?) *) 322 + let ends_with this args = 323 + let s = this_string this in 324 + let search = match List.nth_opt args 0 with 325 + | Some v -> get_string v 326 + | None -> "undefined" 327 + in 328 + let end_pos = match List.nth_opt args 1 with 329 + | Some Undefined | None -> String.length s 330 + | Some v -> min (String.length s) (int_of_float (to_float v)) 331 + in 332 + let search_len = String.length search in 333 + let start = end_pos - search_len in 334 + if start < 0 then Bool false 335 + else Bool (String.sub s start search_len = search) 336 + 337 + (** String.prototype.replace(searchValue, replaceValue) *) 338 + let replace this args = 339 + let s = this_string this in 340 + match args with 341 + | search :: replacement :: _ -> 342 + let search_str = get_string search in 343 + let replace_str = get_string replacement in 344 + (try 345 + let idx = Str.search_forward (Str.regexp_string search_str) s 0 in 346 + let before = String.sub s 0 idx in 347 + let after = String.sub s (idx + String.length search_str) 348 + (String.length s - idx - String.length search_str) in 349 + String (before ^ replace_str ^ after) 350 + with Not_found -> String s) 351 + | _ -> String s 352 + 353 + (** String.prototype.replaceAll(searchValue, replaceValue) *) 354 + let replace_all this args = 355 + let s = this_string this in 356 + match args with 357 + | search :: replacement :: _ -> 358 + let search_str = get_string search in 359 + let replace_str = get_string replacement in 360 + String (Str.global_replace (Str.regexp_string search_str) replace_str s) 361 + | _ -> String s 362 + 363 + (** String.prototype.toString() / valueOf() *) 364 + let to_string_method this _args = 365 + String (this_string this) 366 + 367 + (** Create String constructor and prototype *) 368 + let create () = 369 + let proto = make_object () in 370 + 371 + (* String.prototype methods *) 372 + let add_proto_method name length func = 373 + let fn = make_native_function name length func in 374 + match fn with 375 + | Object obj -> 376 + Hashtbl.add proto.properties name 377 + { value = Object obj; 378 + flags = { writable = true; enumerable = false; configurable = true }; 379 + getter = None; setter = None } 380 + | _ -> () 381 + in 382 + 383 + add_proto_method "charAt" 1 char_at; 384 + add_proto_method "charCodeAt" 1 char_code_at; 385 + add_proto_method "concat" 1 concat; 386 + add_proto_method "includes" 1 includes; 387 + add_proto_method "indexOf" 1 index_of; 388 + add_proto_method "lastIndexOf" 1 last_index_of; 389 + add_proto_method "slice" 2 slice; 390 + add_proto_method "substring" 2 substring; 391 + add_proto_method "toLowerCase" 0 to_lower_case; 392 + add_proto_method "toUpperCase" 0 to_upper_case; 393 + add_proto_method "trim" 0 trim; 394 + add_proto_method "trimStart" 0 trim_start; 395 + add_proto_method "trimLeft" 0 trim_start; 396 + add_proto_method "trimEnd" 0 trim_end; 397 + add_proto_method "trimRight" 0 trim_end; 398 + add_proto_method "split" 2 split; 399 + add_proto_method "repeat" 1 repeat; 400 + add_proto_method "padStart" 1 pad_start; 401 + add_proto_method "padEnd" 1 pad_end; 402 + add_proto_method "startsWith" 1 starts_with; 403 + add_proto_method "endsWith" 1 ends_with; 404 + add_proto_method "replace" 2 replace; 405 + add_proto_method "replaceAll" 2 replace_all; 406 + add_proto_method "toString" 0 to_string_method; 407 + add_proto_method "valueOf" 0 to_string_method; 408 + 409 + (* String constructor *) 410 + let string_ctor _this args = 411 + match args with 412 + | [] -> String "" 413 + | v :: _ -> String (get_string v) 414 + in 415 + 416 + let ctor = make_object () in 417 + let ctor_fn = make_native_function "String" 1 string_ctor in 418 + (match ctor_fn with 419 + | Object obj -> 420 + ctor.data <- obj.data; 421 + ctor.class_id <- Class_function 422 + | _ -> ()); 423 + 424 + (* Static methods *) 425 + let add_static_method name length func = 426 + let fn = make_native_function name length func in 427 + match fn with 428 + | Object obj -> 429 + Hashtbl.add ctor.properties name 430 + { value = Object obj; 431 + flags = { writable = true; enumerable = false; configurable = true }; 432 + getter = None; setter = None } 433 + | _ -> () 434 + in 435 + 436 + add_static_method "fromCharCode" 1 from_char_code; 437 + add_static_method "fromCodePoint" 1 from_code_point; 438 + 439 + (* Link prototype *) 440 + Hashtbl.add ctor.properties "prototype" 441 + { value = Object proto; 442 + flags = { writable = false; enumerable = false; configurable = false }; 443 + getter = None; setter = None }; 444 + 445 + Hashtbl.add proto.properties "constructor" 446 + { value = Object ctor; 447 + flags = { writable = true; enumerable = false; configurable = true }; 448 + getter = None; setter = None }; 449 + 450 + (Object ctor, Object proto)
+289
lib/quickjs/builtins/math.ml
··· 1 + (** JavaScript Math built-in object. 2 + 3 + Implements the Math object as specified in ECMA-262. *) 4 + 5 + open Quickjs_runtime.Value 6 + 7 + (** Helper to get numeric argument *) 8 + let get_arg args idx = 9 + match List.nth_opt args idx with 10 + | Some v -> to_float v 11 + | None -> Float.nan 12 + 13 + (** Math.abs(x) *) 14 + let abs _this args = 15 + let x = get_arg args 0 in 16 + Float (Float.abs x) 17 + 18 + (** Math.acos(x) *) 19 + let acos _this args = 20 + let x = get_arg args 0 in 21 + Float (Float.acos x) 22 + 23 + (** Math.acosh(x) *) 24 + let acosh _this args = 25 + let x = get_arg args 0 in 26 + Float (Float.acosh x) 27 + 28 + (** Math.asin(x) *) 29 + let asin _this args = 30 + let x = get_arg args 0 in 31 + Float (Float.asin x) 32 + 33 + (** Math.asinh(x) *) 34 + let asinh _this args = 35 + let x = get_arg args 0 in 36 + Float (Float.asinh x) 37 + 38 + (** Math.atan(x) *) 39 + let atan _this args = 40 + let x = get_arg args 0 in 41 + Float (Float.atan x) 42 + 43 + (** Math.atan2(y, x) *) 44 + let atan2 _this args = 45 + let y = get_arg args 0 in 46 + let x = get_arg args 1 in 47 + Float (Float.atan2 y x) 48 + 49 + (** Math.atanh(x) *) 50 + let atanh _this args = 51 + let x = get_arg args 0 in 52 + Float (Float.atanh x) 53 + 54 + (** Math.cbrt(x) *) 55 + let cbrt _this args = 56 + let x = get_arg args 0 in 57 + Float (Float.cbrt x) 58 + 59 + (** Math.ceil(x) *) 60 + let ceil _this args = 61 + let x = get_arg args 0 in 62 + Float (Float.ceil x) 63 + 64 + (** Math.clz32(x) *) 65 + let clz32 _this args = 66 + let x = match List.nth_opt args 0 with 67 + | Some v -> to_uint32 v 68 + | None -> 0l 69 + in 70 + if x = 0l then Int 32l 71 + else 72 + let rec count n bits = 73 + if Int32.logand n (Int32.shift_left 1l (31 - bits)) <> 0l then bits 74 + else count n (bits + 1) 75 + in 76 + Int (Int32.of_int (count x 0)) 77 + 78 + (** Math.cos(x) *) 79 + let cos _this args = 80 + let x = get_arg args 0 in 81 + Float (Float.cos x) 82 + 83 + (** Math.cosh(x) *) 84 + let cosh _this args = 85 + let x = get_arg args 0 in 86 + Float (Float.cosh x) 87 + 88 + (** Math.exp(x) *) 89 + let exp _this args = 90 + let x = get_arg args 0 in 91 + Float (Float.exp x) 92 + 93 + (** Math.expm1(x) *) 94 + let expm1 _this args = 95 + let x = get_arg args 0 in 96 + Float (Float.expm1 x) 97 + 98 + (** Math.floor(x) *) 99 + let floor _this args = 100 + let x = get_arg args 0 in 101 + Float (Float.floor x) 102 + 103 + (** Math.fround(x) *) 104 + let fround _this args = 105 + let x = get_arg args 0 in 106 + (* Convert to float32 and back *) 107 + Float (Int32.float_of_bits (Int32.bits_of_float x)) 108 + 109 + (** Math.hypot(values...) *) 110 + let hypot _this args = 111 + let values = List.map to_float args in 112 + let sum_sq = List.fold_left (fun acc x -> acc +. x *. x) 0.0 values in 113 + Float (Float.sqrt sum_sq) 114 + 115 + (** Math.imul(a, b) *) 116 + let imul _this args = 117 + let a = match List.nth_opt args 0 with Some v -> to_int32 v | None -> 0l in 118 + let b = match List.nth_opt args 1 with Some v -> to_int32 v | None -> 0l in 119 + Int (Int32.mul a b) 120 + 121 + (** Math.log(x) *) 122 + let log _this args = 123 + let x = get_arg args 0 in 124 + Float (Float.log x) 125 + 126 + (** Math.log10(x) *) 127 + let log10 _this args = 128 + let x = get_arg args 0 in 129 + Float (Float.log10 x) 130 + 131 + (** Math.log1p(x) *) 132 + let log1p _this args = 133 + let x = get_arg args 0 in 134 + Float (Float.log1p x) 135 + 136 + (** Math.log2(x) *) 137 + let log2 _this args = 138 + let x = get_arg args 0 in 139 + Float (Float.log x /. Float.log 2.0) 140 + 141 + (** Math.max(values...) *) 142 + let max _this args = 143 + if args = [] then Float Float.neg_infinity 144 + else 145 + let values = List.map to_float args in 146 + if List.exists Float.is_nan values then Float Float.nan 147 + else Float (List.fold_left Float.max Float.neg_infinity values) 148 + 149 + (** Math.min(values...) *) 150 + let min _this args = 151 + if args = [] then Float Float.infinity 152 + else 153 + let values = List.map to_float args in 154 + if List.exists Float.is_nan values then Float Float.nan 155 + else Float (List.fold_left Float.min Float.infinity values) 156 + 157 + (** Math.pow(base, exponent) *) 158 + let pow _this args = 159 + let base = get_arg args 0 in 160 + let exponent = get_arg args 1 in 161 + Float (Float.pow base exponent) 162 + 163 + (** Math.random() *) 164 + let random _this _args = 165 + Float (Random.float 1.0) 166 + 167 + (** Math.round(x) *) 168 + let round _this args = 169 + let x = get_arg args 0 in 170 + if Float.is_nan x || Float.is_infinite x then Float x 171 + else 172 + (* JavaScript round: half toward positive infinity *) 173 + let floored = Float.floor x in 174 + if x -. floored >= 0.5 then Float (floored +. 1.0) 175 + else Float floored 176 + 177 + (** Math.sign(x) *) 178 + let sign _this args = 179 + let x = get_arg args 0 in 180 + if Float.is_nan x then Float Float.nan 181 + else if x > 0.0 then Float 1.0 182 + else if x < 0.0 then Float (-1.0) 183 + else Float x (* preserves +0 and -0 *) 184 + 185 + (** Math.sin(x) *) 186 + let sin _this args = 187 + let x = get_arg args 0 in 188 + Float (Float.sin x) 189 + 190 + (** Math.sinh(x) *) 191 + let sinh _this args = 192 + let x = get_arg args 0 in 193 + Float (Float.sinh x) 194 + 195 + (** Math.sqrt(x) *) 196 + let sqrt _this args = 197 + let x = get_arg args 0 in 198 + Float (Float.sqrt x) 199 + 200 + (** Math.tan(x) *) 201 + let tan _this args = 202 + let x = get_arg args 0 in 203 + Float (Float.tan x) 204 + 205 + (** Math.tanh(x) *) 206 + let tanh _this args = 207 + let x = get_arg args 0 in 208 + Float (Float.tanh x) 209 + 210 + (** Math.trunc(x) *) 211 + let trunc _this args = 212 + let x = get_arg args 0 in 213 + Float (Float.trunc x) 214 + 215 + (** Create the Math object with all methods and constants *) 216 + let create () = 217 + let math = make_object () in 218 + 219 + (* Constants *) 220 + let add_const name value = 221 + Hashtbl.add math.properties name 222 + { value = Float value; 223 + flags = { writable = false; enumerable = false; configurable = false }; 224 + getter = None; setter = None } 225 + in 226 + add_const "E" (Float.exp 1.0); 227 + add_const "LN10" (Float.log 10.0); 228 + add_const "LN2" (Float.log 2.0); 229 + add_const "LOG10E" (1.0 /. Float.log 10.0); 230 + add_const "LOG2E" (1.0 /. Float.log 2.0); 231 + add_const "PI" Float.pi; 232 + add_const "SQRT1_2" (Float.sqrt 0.5); 233 + add_const "SQRT2" (Float.sqrt 2.0); 234 + 235 + (* Methods *) 236 + let add_method name length func = 237 + let fn = make_native_function name length func in 238 + match fn with 239 + | Object obj -> 240 + Hashtbl.add math.properties name 241 + { value = Object obj; 242 + flags = { writable = true; enumerable = false; configurable = true }; 243 + getter = None; setter = None } 244 + | _ -> () 245 + in 246 + 247 + add_method "abs" 1 abs; 248 + add_method "acos" 1 acos; 249 + add_method "acosh" 1 acosh; 250 + add_method "asin" 1 asin; 251 + add_method "asinh" 1 asinh; 252 + add_method "atan" 1 atan; 253 + add_method "atan2" 2 atan2; 254 + add_method "atanh" 1 atanh; 255 + add_method "cbrt" 1 cbrt; 256 + add_method "ceil" 1 ceil; 257 + add_method "clz32" 1 clz32; 258 + add_method "cos" 1 cos; 259 + add_method "cosh" 1 cosh; 260 + add_method "exp" 1 exp; 261 + add_method "expm1" 1 expm1; 262 + add_method "floor" 1 floor; 263 + add_method "fround" 1 fround; 264 + add_method "hypot" 2 hypot; 265 + add_method "imul" 2 imul; 266 + add_method "log" 1 log; 267 + add_method "log10" 1 log10; 268 + add_method "log1p" 1 log1p; 269 + add_method "log2" 1 log2; 270 + add_method "max" 2 max; 271 + add_method "min" 2 min; 272 + add_method "pow" 2 pow; 273 + add_method "random" 0 random; 274 + add_method "round" 1 round; 275 + add_method "sign" 1 sign; 276 + add_method "sin" 1 sin; 277 + add_method "sinh" 1 sinh; 278 + add_method "sqrt" 1 sqrt; 279 + add_method "tan" 1 tan; 280 + add_method "tanh" 1 tanh; 281 + add_method "trunc" 1 trunc; 282 + 283 + (* Add @@toStringTag *) 284 + Hashtbl.add math.properties "@@toStringTag" 285 + { value = String "Math"; 286 + flags = { writable = false; enumerable = false; configurable = true }; 287 + getter = None; setter = None }; 288 + 289 + Object math
+4
lib/quickjs/runtime/interpreter.ml
··· 198 198 let all_args = Array.to_list bound.bound_args @ args in 199 199 call_function ctx bound.target bound.this_arg all_args new_target 200 200 201 + | Object { data = Data_native_function { func; _ }; _ } -> 202 + (* Call native function directly *) 203 + func this_val args 204 + 201 205 | _ -> 202 206 Context.type_error ctx "Value is not callable"; 203 207 Undefined
+18
lib/quickjs/runtime/value.ml
··· 68 68 | Class_bigint64array 69 69 | Class_biguint64array 70 70 71 + (** Native function type - takes this value, args list, returns value *) 72 + and native_function = value -> value list -> value 73 + 71 74 (** Object-specific data *) 72 75 and object_data = 73 76 | Data_none 74 77 | Data_array of value array ref 75 78 | Data_function of js_function 76 79 | Data_bound_function of bound_function 80 + | Data_native_function of { name : string; func : native_function; length : int } 77 81 | Data_generator of generator_state 78 82 | Data_error of { message : string; name : string; stack : string } 79 83 | Data_regexp of { pattern : string; flags : string; regexp : Str.regexp option } ··· 339 343 home_object = Undefined; 340 344 } in 341 345 let obj = make_object ~class_id:Class_function ~data:(Data_function func) () in 346 + Object obj 347 + 348 + (** Create a native function object *) 349 + let make_native_function name length func = 350 + let obj = make_object ~class_id:Class_function 351 + ~data:(Data_native_function { name; func; length }) () in 352 + Hashtbl.add obj.properties "name" 353 + { value = String name; 354 + flags = { writable = false; enumerable = false; configurable = true }; 355 + getter = None; setter = None }; 356 + Hashtbl.add obj.properties "length" 357 + { value = Int (Int32.of_int length); 358 + flags = { writable = false; enumerable = false; configurable = true }; 359 + getter = None; setter = None }; 342 360 Object obj 343 361 344 362 (** Get object property *)