1 // Js_of_ocaml runtime support
2 // http://www.ocsigen.org/js_of_ocaml/
3 // Copyright (C) 2010 Jérôme Vouillon
4 // Laboratoire PPS - CNRS Université Paris Diderot
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU Lesser General Public License as published by
8 // the Free Software Foundation, with linking exception;
9 // either version 2.1 of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 //Provides: caml_call_gen
22 function caml_call_gen(f
, args
) {
24 return caml_call_gen(f
.fun
, args
);
26 var d
= n
- args
.length
;
28 return f
.apply(null, args
);
30 return caml_call_gen(f
.apply(null, args
.slice(0,n
)), args
.slice(n
));
32 return function (x
){ return caml_call_gen(f
, args
.concat([x
])); };
35 //Provides: caml_named_values
36 var caml_named_values
= {};
38 //Provides: caml_register_named_value
39 //Requires: caml_named_values
40 function caml_register_named_value(nm
,v
) {
41 caml_named_values
[nm
] = v
; return 0;
44 //Provides: caml_global_data
45 var caml_global_data
= [0];
47 //Provides: caml_register_global
48 //Requires: caml_global_data
49 function caml_register_global (n
, v
) { caml_global_data
[n
+ 1] = v
; }
51 //Provides: caml_raise_constant
52 function caml_raise_constant (tag
) { throw [0, tag
]; }
54 //Provides: caml_raise_with_arg
55 function caml_raise_with_arg (tag
, arg
) { throw [0, tag
, arg
]; }
57 //Provides: caml_raise_with_string
58 //Requires: caml_raise_with_arg, MlString
59 function caml_raise_with_string (tag
, msg
) {
60 caml_raise_with_arg (tag
, new MlWrappedString (msg
));
63 //Provides: caml_invalid_argument
64 //Requires: caml_raise_with_string
65 function caml_invalid_argument (msg
) {
66 caml_raise_with_string(caml_global_data
[4], msg
);
69 //Provides: caml_failwith
70 //Requires: caml_raise_with_string, caml_global_data
71 function caml_failwith (msg
) {
72 caml_raise_with_string(caml_global_data
[3], msg
);
75 //Provides: caml_array_bound_error
76 //Requires: caml_invalid_argument
77 function caml_array_bound_error () {
78 caml_invalid_argument("index out of bounds");
81 //Provides: caml_raise_zero_divide
82 //Requires: caml_raise_constant, caml_global_data
83 function caml_raise_zero_divide () {
84 caml_raise_constant(caml_global_data
[6]);
87 //Provides: caml_update_dummy
88 function caml_update_dummy (x
, y
) {
89 if( typeof y
==="function" ) { x
.fun
= y
; return 0; }
90 if( y
.fun
) { x
.fun
= y
.fun
; return 0; }
91 var i
= y
.length
; while (i
--) x
[i
] = y
[i
]; return 0;
94 //Provides: caml_obj_is_block const
95 function caml_obj_is_block (x
) { return +(x
instanceof Array
); }
96 //Provides: caml_obj_tag const
97 function caml_obj_tag (x
) { return (x
instanceof Array
)?x
[0]:1000; }
98 //Provides: caml_obj_set_tag
99 function caml_obj_set_tag (x
, tag
) { x
[0] = tag
; return 0; }
100 //Provides: caml_obj_block const
101 function caml_obj_block (tag
, size
) {
103 for (var i
= 1; i
<= size
; i
++) o
[i
] = 0;
106 //Provides: caml_obj_dup mutable
107 function caml_obj_dup (x
) { return x
.slice(); }
108 //Provides: caml_obj_truncate
109 function caml_obj_truncate (x
, s
) { x
.length
= s
+ 1; return 0; }
111 //Provides: caml_lazy_make_forward
112 function caml_lazy_make_forward (v
) { return [250, v
]; }
114 //Provides: caml_mul const
115 function caml_mul(x
,y
) {
116 return ((((x
>> 16) * y
) << 16) + (x
& 0xffff) * y
)|0;
120 // function mul32(x,y) {
121 // var xlo = x & 0xffff;
122 // var xhi = x - xlo;
123 // return (((xhi * y) |0) + xlo * y)|0;
126 //Provides: caml_div const
127 //Requires: caml_raise_zero_divide
128 function caml_div(x
,y
) {
129 if (y
== 0) caml_raise_zero_divide ();
133 //Provides: caml_mod const
134 //Requires: caml_raise_zero_divide
135 function caml_mod(x
,y
) {
136 if (y
== 0) caml_raise_zero_divide ();
140 ///////////// Pervasive
141 //Provides: caml_array_set
142 //Requires: caml_array_bound_error
143 function caml_array_set (array
, index
, newval
) {
144 if ((index
< 0) || (index
>= array
.length
- 1)) caml_array_bound_error();
145 array
[index
+1]=newval
; return 0;
148 //Provides: caml_array_get mutable
149 //Requires: caml_array_bound_error
150 function caml_array_get (array
, index
) {
151 if ((index
< 0) || (index
>= array
.length
- 1)) caml_array_bound_error();
152 return array
[index
+1];
155 //Provides: caml_make_vect const
156 function caml_make_vect (len
, init
) {
157 var b
= [0]; for (var i
= 1; i
<= len
; i
++) b
[i
] = init
; return b
;
160 //Provides: caml_compare_val
161 //Requires: MlString, caml_int64_compare, caml_int_compare
162 function caml_compare_val (a
, b
, total
) {
165 if (!(total
&& a
=== b
)) {
166 if (a
instanceof MlString
) {
167 if (b
instanceof MlString
) {
168 if (a
!= b
) return a
.compare(b
);
172 } else if (a
instanceof Array
&& a
[0] == (a
[0]|0)) {
178 } else if (b
instanceof Array
&& b
[0] == (b
[0]|0)) {
184 } else if (ta
!= tb
) {
185 return (ta
< tb
)?-1:1;
190 return caml_int_compare(a
[2], b
[2]);
193 return caml_int64_compare(a
, b
);
195 if (a
.length
!= b
.length
) return (a
.length
< b
.length
)?-1:1;
196 if (a
.length
> 1) stack
.push(a
, b
, 1);
201 } else if (b
instanceof MlString
||
202 (b
instanceof Array
&& b
[0] == (b
[0]|0))) {
205 if (a
< b
) return -1;
207 if (total
&& a
!= b
) {
208 if (a
== a
) return 1;
209 if (b
== b
) return -1;
213 if (stack
.length
== 0) return 0;
217 if (i
+ 1 < a
.length
) stack
.push(a
, b
, i
+ 1);
222 //Provides: caml_compare
223 //Requires: caml_compare_val
224 function caml_compare (a
, b
) { return caml_compare_val (a
, b
, true); }
225 //Provides: caml_int_compare mutable
226 function caml_int_compare (a
, b
) {
227 if (a
< b
) return (-1); if (a
== b
) return 0; return 1;
229 //Provides: caml_equal mutable
230 //Requires: caml_compare_val
231 function caml_equal (x
, y
) { return +(caml_compare_val(x
,y
,false) == 0); }
232 //Provides: caml_notequal mutable
233 //Requires: caml_compare
234 function caml_notequal (x
, y
) { return +(caml_compare_val(x
,y
,false) != 0); }
235 //Provides: caml_greaterequal mutable
236 //Requires: caml_compare
237 function caml_greaterequal (x
, y
) { return +(caml_compare(x
,y
,false) >= 0); }
238 //Provides: caml_greaterthan mutable
239 //Requires: caml_compare
240 function caml_greaterthan (x
, y
) { return +(caml_compare(x
,y
,false) > 0); }
241 //Provides: caml_lessequal mutable
242 //Requires: caml_compare
243 function caml_lessequal (x
, y
) { return +(caml_compare(x
,y
,false) <= 0); }
244 //Provides: caml_lessthan mutable
245 //Requires: caml_compare
246 function caml_lessthan (x
, y
) { return +(caml_compare(x
,y
,false) < 0); }
248 //Provides: caml_parse_sign_and_base
250 function caml_parse_sign_and_base (s
) {
251 var i
= 0, base
= 10, sign
= s
.get(0) == 45?(i
++,-1):1;
253 switch (s
.get(i
+ 1)) {
254 case 120: case 88: base
= 16; i
+= 2; break;
255 case 111: case 79: base
= 8; i
+= 2; break;
256 case 98: case 66: base
= 2; i
+= 2; break;
258 return [i
, sign
, base
];
261 //Provides: caml_parse_digit
262 function caml_parse_digit(c
) {
263 if (c
>= 48 && c
<= 57) return c
- 48;
264 if (c
>= 65 && c
<= 90) return c
- 55;
265 if (c
>= 97 && c
<= 122) return c
- 87;
269 //Provides: caml_int_of_string
270 //Requires: caml_parse_sign_and_base, caml_parse_digit, MlString, caml_failwith
271 function caml_int_of_string (s
) {
272 var r
= caml_parse_sign_and_base (s
);
273 var i
= r
[0], sign
= r
[1], base
= r
[2];
274 var threshold
= -1 >>> 0;
276 var d
= caml_parse_digit(c
);
277 if (d
< 0 || d
>= base
) caml_failwith("int_of_string");
282 if (c
== 95) continue;
283 d
= caml_parse_digit(c
);
284 if (d
< 0 || d
>= base
) break;
285 res
= base
* res
+ d
;
286 if (res
> threshold
) caml_failwith("int_of_string");
288 if (i
!= s
.getLen()) caml_failwith("int_of_string");
290 if ((res
| 0) != res
) caml_failwith("int_of_string");
294 //Provides: caml_is_printable const
295 function caml_is_printable(c
) { return +(c
> 31 && c
< 127); }
298 //Provides: caml_parse_format
299 //Requires: caml_invalid_argument
300 function caml_parse_format (fmt
) {
301 fmt
= fmt
.toString ();
302 var len
= fmt
.length
;
303 if (len
> 31) caml_invalid_argument("format_int: format too long");
305 { justify
:'+', signstyle
:'-', filler
:' ', alternate
:false,
306 base
:0, signedconv
:false, width
:0, uppercase
:false,
307 sign
:1, prec
:6, conv
:'f' };
308 for (var i
= 0; i
< len
; i
++) {
309 var c
= fmt
.charAt(i
);
312 f
.justify
= '-'; break;
314 f
.signstyle
= c
; break;
316 f
.filler
= '0'; break;
318 f
.alternate
= true; break;
319 case '1': case '2': case '3': case '4': case '5':
320 case '6': case '7': case '8': case '9':
322 while (c
=fmt
.charCodeAt(i
) - 48, c
>= 0 && c
<= 9) {
323 f
.width
= f
.width
* 10 + c
; i
++
330 while (c
=fmt
.charCodeAt(i
) - 48, c
>= 0 && c
<= 9) {
331 f
.prec
= f
.prec
* 10 + c
; i
++
335 f
.signedconv
= true; /* fallthrough */
341 f
.base
= 16; f
.uppercase
= true; break;
344 case 'e': case 'f': case 'g':
345 f
.signedconv
= true; f
.conv
= c
; break;
346 case 'E': case 'F': case 'G':
347 f
.signedconv
= true; f
.uppercase
= true;
348 f
.conv
= c
.toLowerCase (); break;
354 //Provides: caml_finish_formatting
356 function caml_finish_formatting(f
, rawbuffer
) {
357 if (f
.uppercase
) rawbuffer
= rawbuffer
.toUpperCase();
358 var len
= rawbuffer
.length
;
359 /* Adjust len to reflect additional chars (sign, etc) */
360 if (f
.signedconv
&& (f
.sign
< 0 || f
.signstyle
!= '-')) len
++;
362 if (f
.base
== 8) len
+= 1;
363 if (f
.base
== 16) len
+= 2;
365 /* Do the formatting */
367 if (f
.justify
== '+' && f
.filler
== ' ')
368 for (var i
= len
; i
< f
.width
; i
++) buffer
+= ' ';
370 if (f
.sign
< 0) buffer
+= '-';
371 else if (f
.signstyle
!= '-') buffer
+= f
.signstyle
;
373 if (f
.alternate
&& f
.base
== 8) buffer
+= '0';
374 if (f
.alternate
&& f
.base
== 16) buffer
+= "0x";
375 if (f
.justify
== '+' && f
.filler
== '0')
376 for (var i
= len
; i
< f
.width
; i
++) buffer
+= '0';
378 if (f
.justify
== '-')
379 for (var i
= len
; i
< f
.width
; i
++) buffer
+= ' ';
380 return new MlWrappedString (buffer
);
383 //Provides: caml_format_int const
384 //Requires: caml_parse_format, caml_finish_formatting
385 function caml_format_int(fmt
, i
) {
386 if (fmt
.toString() == "%d") return new MlWrappedString(""+i
);
387 var f
= caml_parse_format(fmt
);
388 if (i
< 0) { if (f
.signedconv
) { f
.sign
= -1; i
= -i
; } else i
>>>= 0; }
389 var s
= i
.toString(f
.base
);
390 return caml_finish_formatting(f
, s
);
393 //Provides: caml_format_float const
394 //Requires: caml_parse_format, caml_finish_formatting
395 function caml_format_float (fmt
, x
) {
396 var s
, f
= caml_parse_format(fmt
);
397 if (x
< 0) { f
.sign
= -1; x
= -x
; }
398 if (isNaN(x
)) { s
= "nan"; f
.filler
= ' '; }
399 else if (!isFinite(x
)) { s
= "inf"; f
.filler
= ' '; }
403 var s
= x
.toExponential(f
.prec
);
404 // exponent should be at least two digits
406 if (s
.charAt(i
- 3) == 'e')
407 s
= s
.slice (0, i
- 1) + '0' + s
.slice (i
- 1);
410 s
= x
.toFixed(f
.prec
); break;
412 var prec
= f
.prec
?f
.prec
:1;
413 s
= x
.toExponential(prec
- 1);
414 var j
= s
.indexOf('e');
415 var exp
= +s
.slice(j
+ 1);
416 if (exp
< -4 || x
.toFixed(0).length
> prec
) {
417 // remove trailing zeroes
418 var i
= j
- 1; while (s
.charAt(i
) == '0') i
--;
419 if (s
.charAt(i
) == '.') i
--;
420 s
= s
.slice(0, i
+ 1) + s
.slice(j
);
422 if (s
.charAt(i
- 3) == 'e')
423 s
= s
.slice (0, i
- 1) + '0' + s
.slice (i
- 1);
427 if (exp
< 0) { p
-= exp
+ 1; s
= x
.toFixed(p
); }
428 else while (s
= x
.toFixed(p
), s
.length
> prec
+ 1) p
--;
430 // remove trailing zeroes
431 var i
= s
.length
- 1; while (s
.charAt(i
) == '0') i
--;
432 if (s
.charAt(i
) == '.') i
--;
433 s
= s
.slice(0, i
+ 1);
438 return caml_finish_formatting(f
, s
);
441 ///////////// Hashtbl
442 //Provides: caml_hash_univ_param mutable
444 function caml_hash_univ_param (count
, limit
, obj
) {
446 function hash_aux (obj
) {
448 if (count
< 0 || limit
< 0) return;
449 if (obj
instanceof Array
&& obj
[0] == (obj
[0]|0)) {
454 hash_accu
= (hash_accu
* 65599 + obj
[2]) | 0;
458 limit
++; hash_aux(obj
); break;
462 hash_accu
= (hash_accu
* 65599 + obj
[1] + (obj
[2] << 24)) | 0;
466 hash_accu
= (hash_accu
* 19 + obj
[0]) | 0;
467 for (var i
= obj
.length
- 1; i
> 0; i
--) hash_aux (obj
[i
]);
469 } else if (obj
instanceof MlString
) {
471 var a
= obj
.array
, l
= obj
.getLen ();
473 for (var i
= 0; i
< l
; i
++) hash_accu
= (hash_accu
* 19 + a
[i
]) | 0;
475 var b
= obj
.getFullBytes ();
476 for (var i
= 0; i
< l
; i
++)
477 hash_accu
= (hash_accu
* 19 + b
.charCodeAt(i
)) | 0;
479 } else if (obj
== (obj
|0)) {
482 hash_accu
= (hash_accu
* 65599 + obj
) | 0;
483 } else if (obj
== +obj
) {
486 var p
= caml_int64_to_bytes (caml_int64_bits_of_float (obj
));
487 for (var i
= 7; i
>= 0; i
--) hash_accu
= (hash_accu
* 19 + p
[i
]) | 0;
491 return hash_accu
& 0x3FFFFFFF;
495 //Provides: caml_sys_time mutable
496 var caml_initial_time
= new Date() * 0.001;
497 function caml_sys_time () { return new Date() * 0.001 - caml_initial_time
; }
498 //Provides: caml_sys_get_config const
500 function caml_sys_get_config () {
501 return [0, new MlWrappedString("Unix"), 32];
503 //Provides: caml_sys_random_seed mutable
504 function caml_sys_random_seed () {
505 return new Date()^0xffffffff*Math
.random();
508 ///////////// CamlinternalOO
509 //Provides: caml_get_public_method const
510 function caml_get_public_method (obj
, tag
) {
512 var li
= 3, hi
= meths
[1] * 2 + 1, mi
;
514 mi
= ((li
+hi
) >> 1) | 1;
515 if (tag
< meths
[mi
+1]) hi
= mi
-2;
518 /* return 0 if tag is not there */
519 return (tag
== meths
[li
+1] ? meths
[li
] : 0);
522 /////////////////////////////
525 //Provides: caml_ml_out_channels_list const
526 function caml_ml_out_channels_list () { return 0; }
527 //Provides: caml_ml_flush const
528 function caml_ml_flush () { return 0; }
529 //Provides: caml_ml_open_descriptor_out const
530 function caml_ml_open_descriptor_out () { return 0; }
531 //Provides: caml_ml_open_descriptor_in const
532 function caml_ml_open_descriptor_in () { return 0; }
533 //Provides: caml_sys_get_argv const
535 function caml_sys_get_argv () {
536 var p
= new MlWrappedString("a.out"); return [0, p
, [0, p
]];
538 //Provides: caml_ml_output const
539 function caml_ml_output () { return 0; }
540 //Provides: caml_final_register const
541 function caml_final_register () { return 0; }
542 //Provides: caml_final_release const
543 function caml_final_release () { return 0; }