Created
January 20, 2019 09:31
-
-
Save zerobias/fc692dfb897eda16e2cd9e1c5798a6eb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generated by BUCKLESCRIPT VERSION 4.0.6, PLEASE EDIT WITH CARE | |
'use strict'; | |
var $$Map = require("./stdlib/map.js"); | |
var Sys = require("./stdlib/sys.js"); | |
var List = require("./stdlib/list.js"); | |
var $$Array = require("./stdlib/array.js"); | |
var Curry = require("./stdlib/curry.js"); | |
var Caml_oo = require("./stdlib/caml_oo.js"); | |
var Caml_obj = require("./stdlib/caml_obj.js"); | |
var Caml_array = require("./stdlib/caml_array.js"); | |
var Caml_int32 = require("./stdlib/caml_int32.js"); | |
var Pervasives = require("./stdlib/pervasives.js"); | |
var Caml_string = require("./stdlib/caml_string.js"); | |
var Js_primitive = require("./stdlib/js_primitive.js"); | |
var Caml_primitive = require("./stdlib/caml_primitive.js"); | |
var Caml_exceptions = require("./stdlib/caml_exceptions.js"); | |
var Caml_builtin_exceptions = require("./stdlib/caml_builtin_exceptions.js"); | |
function is_block(a) { | |
return typeof a !== "number"; | |
} | |
function extension_constructor(x) { | |
var slot = typeof x !== "number" && (x.tag | 0) !== 248 && x.length >= 1 ? x[0] : x; | |
var name = typeof slot !== "number" && slot.tag === 248 ? slot[0] : Pervasives.invalid_arg("Obj.extension_constructor"); | |
if (name.tag === 252) { | |
return slot; | |
} else { | |
return Pervasives.invalid_arg("Obj.extension_constructor"); | |
} | |
} | |
function extension_name(slot) { | |
return slot[0]; | |
} | |
function extension_id(slot) { | |
return slot[1]; | |
} | |
var Obj = /* module */[ | |
/* is_block */is_block, | |
/* first_non_constant_constructor_tag */0, | |
/* last_non_constant_constructor_tag */245, | |
/* lazy_tag */246, | |
/* closure_tag */247, | |
/* object_tag */248, | |
/* infix_tag */249, | |
/* forward_tag */250, | |
/* no_scan_tag */251, | |
/* abstract_tag */251, | |
/* string_tag */252, | |
/* double_tag */253, | |
/* double_array_tag */254, | |
/* custom_tag */255, | |
/* final_tag */255, | |
/* int_tag */1000, | |
/* out_of_heap_tag */1001, | |
/* unaligned_tag */1002, | |
/* extension_constructor */extension_constructor, | |
/* extension_name */extension_name, | |
/* extension_id */extension_id | |
]; | |
function copy(o) { | |
return Caml_exceptions.caml_set_oo_id(Caml_obj.caml_obj_dup(o)); | |
} | |
var params = /* record */[ | |
/* compact_table */true, | |
/* copy_parent */true, | |
/* clean_when_copying */true, | |
/* retry_count */3, | |
/* bucket_small_size */16 | |
]; | |
function public_method_label(s) { | |
var accu = 0; | |
for(var i = 0 ,i_finish = s.length - 1 | 0; i <= i_finish; ++i){ | |
accu = Caml_int32.imul(223, accu) + Caml_string.get(s, i) | 0; | |
} | |
accu = accu & 2147483647; | |
if (accu > 1073741823) { | |
return accu - -2147483648 | 0; | |
} else { | |
return accu; | |
} | |
} | |
var compare = Caml_primitive.caml_string_compare; | |
var Vars = $$Map.Make(/* module */[/* compare */compare]); | |
var compare$1 = Caml_primitive.caml_string_compare; | |
var Meths = $$Map.Make(/* module */[/* compare */compare$1]); | |
var compare$2 = Caml_primitive.caml_int_compare; | |
var Labs = $$Map.Make(/* module */[/* compare */compare$2]); | |
var dummy_table = /* record */[ | |
/* size */0, | |
/* methods : array */[/* () */0], | |
/* methods_by_name */Meths[/* empty */0], | |
/* methods_by_label */Labs[/* empty */0], | |
/* previous_states : [] */0, | |
/* hidden_meths : [] */0, | |
/* vars */Vars[/* empty */0], | |
/* initializers : [] */0 | |
]; | |
var table_count = /* record */[/* contents */0]; | |
var dummy_met = []; | |
function fit_size(n) { | |
if (n <= 2) { | |
return n; | |
} else { | |
return (fit_size((n + 1 | 0) / 2 | 0) << 1); | |
} | |
} | |
function new_table(pub_labels) { | |
table_count[0] = table_count[0] + 1 | 0; | |
var len = pub_labels.length; | |
var methods = Caml_array.caml_make_vect((len << 1) + 2 | 0, dummy_met); | |
Caml_array.caml_array_set(methods, 0, len); | |
Caml_array.caml_array_set(methods, 1, (Caml_int32.imul(fit_size(len), Sys.word_size) / 8 | 0) - 1 | 0); | |
for(var i = 0 ,i_finish = len - 1 | 0; i <= i_finish; ++i){ | |
Caml_array.caml_array_set(methods, (i << 1) + 3 | 0, Caml_array.caml_array_get(pub_labels, i)); | |
} | |
return /* record */[ | |
/* size */2, | |
/* methods */methods, | |
/* methods_by_name */Meths[/* empty */0], | |
/* methods_by_label */Labs[/* empty */0], | |
/* previous_states : [] */0, | |
/* hidden_meths : [] */0, | |
/* vars */Vars[/* empty */0], | |
/* initializers : [] */0 | |
]; | |
} | |
function resize(array, new_size) { | |
var old_size = array[/* methods */1].length; | |
if (new_size > old_size) { | |
var new_buck = Caml_array.caml_make_vect(new_size, dummy_met); | |
$$Array.blit(array[/* methods */1], 0, new_buck, 0, old_size); | |
array[/* methods */1] = new_buck; | |
return /* () */0; | |
} else { | |
return 0; | |
} | |
} | |
var method_count = /* record */[/* contents */0]; | |
var inst_var_count = /* record */[/* contents */0]; | |
function new_method(table) { | |
var index = table[/* methods */1].length; | |
resize(table, index + 1 | 0); | |
return index; | |
} | |
function get_method_label(table, name) { | |
try { | |
return Curry._2(Meths[/* find */21], name, table[/* methods_by_name */2]); | |
} | |
catch (exn){ | |
if (exn === Caml_builtin_exceptions.not_found) { | |
var label = new_method(table); | |
table[/* methods_by_name */2] = Curry._3(Meths[/* add */3], name, label, table[/* methods_by_name */2]); | |
table[/* methods_by_label */3] = Curry._3(Labs[/* add */3], label, true, table[/* methods_by_label */3]); | |
return label; | |
} else { | |
throw exn; | |
} | |
} | |
} | |
function get_method_labels(table, names) { | |
return $$Array.map((function (param) { | |
return get_method_label(table, param); | |
}), names); | |
} | |
function set_method(table, label, element) { | |
method_count[0] = method_count[0] + 1 | 0; | |
if (Curry._2(Labs[/* find */21], label, table[/* methods_by_label */3])) { | |
var array = table; | |
var label$1 = label; | |
var element$1 = element; | |
resize(array, label$1 + 1 | 0); | |
return Caml_array.caml_array_set(array[/* methods */1], label$1, element$1); | |
} else { | |
table[/* hidden_meths */5] = /* :: */[ | |
/* tuple */[ | |
label, | |
element | |
], | |
table[/* hidden_meths */5] | |
]; | |
return /* () */0; | |
} | |
} | |
function get_method(table, label) { | |
try { | |
return List.assoc(label, table[/* hidden_meths */5]); | |
} | |
catch (exn){ | |
if (exn === Caml_builtin_exceptions.not_found) { | |
return Caml_array.caml_array_get(table[/* methods */1], label); | |
} else { | |
throw exn; | |
} | |
} | |
} | |
function to_list(arr) { | |
if (arr === 0) { | |
return /* [] */0; | |
} else { | |
return $$Array.to_list(arr); | |
} | |
} | |
function narrow(table, vars, virt_meths, concr_meths) { | |
var vars$1 = to_list(vars); | |
var virt_meths$1 = to_list(virt_meths); | |
var concr_meths$1 = to_list(concr_meths); | |
var virt_meth_labs = List.map((function (param) { | |
return get_method_label(table, param); | |
}), virt_meths$1); | |
var concr_meth_labs = List.map((function (param) { | |
return get_method_label(table, param); | |
}), concr_meths$1); | |
table[/* previous_states */4] = /* :: */[ | |
/* tuple */[ | |
table[/* methods_by_name */2], | |
table[/* methods_by_label */3], | |
table[/* hidden_meths */5], | |
table[/* vars */6], | |
virt_meth_labs, | |
vars$1 | |
], | |
table[/* previous_states */4] | |
]; | |
table[/* vars */6] = Curry._3(Vars[/* fold */10], (function (lab, info, tvars) { | |
if (List.mem(lab, vars$1)) { | |
return Curry._3(Vars[/* add */3], lab, info, tvars); | |
} else { | |
return tvars; | |
} | |
}), table[/* vars */6], Vars[/* empty */0]); | |
var by_name = /* record */[/* contents */Meths[/* empty */0]]; | |
var by_label = /* record */[/* contents */Labs[/* empty */0]]; | |
List.iter2((function (met, label) { | |
by_name[0] = Curry._3(Meths[/* add */3], met, label, by_name[0]); | |
var tmp; | |
try { | |
tmp = Curry._2(Labs[/* find */21], label, table[/* methods_by_label */3]); | |
} | |
catch (exn){ | |
if (exn === Caml_builtin_exceptions.not_found) { | |
tmp = true; | |
} else { | |
throw exn; | |
} | |
} | |
by_label[0] = Curry._3(Labs[/* add */3], label, tmp, by_label[0]); | |
return /* () */0; | |
}), concr_meths$1, concr_meth_labs); | |
List.iter2((function (met, label) { | |
by_name[0] = Curry._3(Meths[/* add */3], met, label, by_name[0]); | |
by_label[0] = Curry._3(Labs[/* add */3], label, false, by_label[0]); | |
return /* () */0; | |
}), virt_meths$1, virt_meth_labs); | |
table[/* methods_by_name */2] = by_name[0]; | |
table[/* methods_by_label */3] = by_label[0]; | |
table[/* hidden_meths */5] = List.fold_right((function (met, hm) { | |
if (List.mem(met[0], virt_meth_labs)) { | |
return hm; | |
} else { | |
return /* :: */[ | |
met, | |
hm | |
]; | |
} | |
}), table[/* hidden_meths */5], /* [] */0); | |
return /* () */0; | |
} | |
function widen(table) { | |
var match = List.hd(table[/* previous_states */4]); | |
var virt_meths = match[4]; | |
table[/* previous_states */4] = List.tl(table[/* previous_states */4]); | |
table[/* vars */6] = List.fold_left((function (s, v) { | |
return Curry._3(Vars[/* add */3], v, Curry._2(Vars[/* find */21], v, table[/* vars */6]), s); | |
}), match[3], match[5]); | |
table[/* methods_by_name */2] = match[0]; | |
table[/* methods_by_label */3] = match[1]; | |
table[/* hidden_meths */5] = List.fold_right((function (met, hm) { | |
if (List.mem(met[0], virt_meths)) { | |
return hm; | |
} else { | |
return /* :: */[ | |
met, | |
hm | |
]; | |
} | |
}), table[/* hidden_meths */5], match[2]); | |
return /* () */0; | |
} | |
function new_slot(table) { | |
var index = table[/* size */0]; | |
table[/* size */0] = index + 1 | 0; | |
return index; | |
} | |
function new_variable(table, name) { | |
try { | |
return Curry._2(Vars[/* find */21], name, table[/* vars */6]); | |
} | |
catch (exn){ | |
if (exn === Caml_builtin_exceptions.not_found) { | |
var index = new_slot(table); | |
if (name !== "") { | |
table[/* vars */6] = Curry._3(Vars[/* add */3], name, index, table[/* vars */6]); | |
} | |
return index; | |
} else { | |
throw exn; | |
} | |
} | |
} | |
function to_array(arr) { | |
if (Caml_obj.caml_equal(arr, 0)) { | |
return /* array */[]; | |
} else { | |
return arr; | |
} | |
} | |
function new_methods_variables(table, meths, vals) { | |
var meths$1 = to_array(meths); | |
var nmeths = meths$1.length; | |
var nvals = vals.length; | |
var res = Caml_array.caml_make_vect(nmeths + nvals | 0, 0); | |
for(var i = 0 ,i_finish = nmeths - 1 | 0; i <= i_finish; ++i){ | |
Caml_array.caml_array_set(res, i, get_method_label(table, Caml_array.caml_array_get(meths$1, i))); | |
} | |
for(var i$1 = 0 ,i_finish$1 = nvals - 1 | 0; i$1 <= i_finish$1; ++i$1){ | |
Caml_array.caml_array_set(res, i$1 + nmeths | 0, new_variable(table, Caml_array.caml_array_get(vals, i$1))); | |
} | |
return res; | |
} | |
function get_variable(table, name) { | |
try { | |
return Curry._2(Vars[/* find */21], name, table[/* vars */6]); | |
} | |
catch (exn){ | |
if (exn === Caml_builtin_exceptions.not_found) { | |
throw [ | |
Caml_builtin_exceptions.assert_failure, | |
/* tuple */[ | |
".", | |
453, | |
57 | |
] | |
]; | |
} else { | |
throw exn; | |
} | |
} | |
} | |
function get_variables(table, names) { | |
return $$Array.map((function (param) { | |
return get_variable(table, param); | |
}), names); | |
} | |
function add_initializer(table, f) { | |
table[/* initializers */7] = /* :: */[ | |
f, | |
table[/* initializers */7] | |
]; | |
return /* () */0; | |
} | |
function create_table(public_methods) { | |
if (public_methods === 0) { | |
return new_table(/* array */[]); | |
} else { | |
var tags = $$Array.map(public_method_label, public_methods); | |
var table = new_table(tags); | |
$$Array.iteri((function (i, met) { | |
var lab = (i << 1) + 2 | 0; | |
table[/* methods_by_name */2] = Curry._3(Meths[/* add */3], met, lab, table[/* methods_by_name */2]); | |
table[/* methods_by_label */3] = Curry._3(Labs[/* add */3], lab, true, table[/* methods_by_label */3]); | |
return /* () */0; | |
}), public_methods); | |
return table; | |
} | |
} | |
function init_class(table) { | |
inst_var_count[0] = (inst_var_count[0] + table[/* size */0] | 0) - 1 | 0; | |
table[/* initializers */7] = List.rev(table[/* initializers */7]); | |
return resize(table, 3 + Caml_int32.div((Caml_array.caml_array_get(table[/* methods */1], 1) << 4), Sys.word_size) | 0); | |
} | |
function inherits(cla, vals, virt_meths, concr_meths, param, top) { | |
var $$super = param[1]; | |
narrow(cla, vals, virt_meths, concr_meths); | |
var init = top ? Curry._2($$super, cla, param[3]) : Curry._1($$super, cla); | |
widen(cla); | |
return $$Array.concat(/* :: */[ | |
/* array */[init], | |
/* :: */[ | |
$$Array.map((function (param) { | |
return get_variable(cla, param); | |
}), to_array(vals)), | |
/* :: */[ | |
$$Array.map((function (nm) { | |
return get_method(cla, get_method_label(cla, nm)); | |
}), to_array(concr_meths)), | |
/* [] */0 | |
] | |
] | |
]); | |
} | |
function make_class(pub_meths, class_init) { | |
var table = create_table(pub_meths); | |
var env_init = Curry._1(class_init, table); | |
init_class(table); | |
return /* tuple */[ | |
Curry._1(env_init, 0), | |
class_init, | |
env_init, | |
0 | |
]; | |
} | |
function make_class_store(pub_meths, class_init, init_table) { | |
var table = create_table(pub_meths); | |
var env_init = Curry._1(class_init, table); | |
init_class(table); | |
init_table[/* class_init */1] = class_init; | |
init_table[/* env_init */0] = env_init; | |
return /* () */0; | |
} | |
function dummy_class(loc) { | |
var undef = function () { | |
throw [ | |
Caml_builtin_exceptions.undefined_recursive_module, | |
loc | |
]; | |
}; | |
return /* tuple */[ | |
undef, | |
undef, | |
undef, | |
0 | |
]; | |
} | |
function create_object(table) { | |
var obj = Caml_obj.caml_obj_block(248, table[/* size */0]); | |
obj[0] = table[/* methods */1]; | |
return Caml_exceptions.caml_set_oo_id(obj); | |
} | |
function create_object_opt(obj_0, table) { | |
if (obj_0) { | |
return obj_0; | |
} else { | |
var obj = Caml_obj.caml_obj_block(248, table[/* size */0]); | |
obj[0] = table[/* methods */1]; | |
return Caml_exceptions.caml_set_oo_id(obj); | |
} | |
} | |
function iter_f(obj, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
Curry._1(param[0], obj); | |
_param = param[1]; | |
continue ; | |
} else { | |
return /* () */0; | |
} | |
}; | |
} | |
function run_initializers(obj, table) { | |
var inits = table[/* initializers */7]; | |
if (inits !== /* [] */0) { | |
return iter_f(obj, inits); | |
} else { | |
return 0; | |
} | |
} | |
function run_initializers_opt(obj_0, obj, table) { | |
if (obj_0) { | |
return obj; | |
} else { | |
var inits = table[/* initializers */7]; | |
if (inits !== /* [] */0) { | |
iter_f(obj, inits); | |
} | |
return obj; | |
} | |
} | |
function create_object_and_run_initializers(obj_0, table) { | |
if (obj_0) { | |
return obj_0; | |
} else { | |
var obj = create_object(table); | |
run_initializers(obj, table); | |
return obj; | |
} | |
} | |
function set_data(tables, v) { | |
if (tables) { | |
tables[0][/* data */1] = v; | |
return /* () */0; | |
} else { | |
throw [ | |
Caml_builtin_exceptions.assert_failure, | |
/* tuple */[ | |
".", | |
542, | |
18 | |
] | |
]; | |
} | |
} | |
function set_next(tables, v) { | |
if (tables) { | |
tables[0][/* next */2] = v; | |
return /* () */0; | |
} else { | |
throw [ | |
Caml_builtin_exceptions.assert_failure, | |
/* tuple */[ | |
".", | |
546, | |
18 | |
] | |
]; | |
} | |
} | |
function get_key(param) { | |
if (param) { | |
return param[0][/* key */0]; | |
} else { | |
throw [ | |
Caml_builtin_exceptions.assert_failure, | |
/* tuple */[ | |
".", | |
550, | |
18 | |
] | |
]; | |
} | |
} | |
function get_data(param) { | |
if (param) { | |
return param[0][/* data */1]; | |
} else { | |
throw [ | |
Caml_builtin_exceptions.assert_failure, | |
/* tuple */[ | |
".", | |
554, | |
18 | |
] | |
]; | |
} | |
} | |
function get_next(param) { | |
if (param) { | |
return param[0][/* next */2]; | |
} else { | |
throw [ | |
Caml_builtin_exceptions.assert_failure, | |
/* tuple */[ | |
".", | |
558, | |
18 | |
] | |
]; | |
} | |
} | |
function build_path(n, keys, tables) { | |
var res = /* Cons */[/* record */[ | |
/* key */0, | |
/* data : Empty */0, | |
/* next : Empty */0 | |
]]; | |
var r = res; | |
for(var i = 0; i <= n; ++i){ | |
r = /* Cons */[/* record */[ | |
/* key */Caml_array.caml_array_get(keys, i), | |
/* data */r, | |
/* next : Empty */0 | |
]]; | |
} | |
set_data(tables, r); | |
return res; | |
} | |
function lookup_keys(i, keys, tables) { | |
if (i < 0) { | |
return tables; | |
} else { | |
var key = Caml_array.caml_array_get(keys, i); | |
var _tables = tables; | |
while(true) { | |
var tables$1 = _tables; | |
if (get_key(tables$1) === key) { | |
var tables_data = get_data(tables$1); | |
if (tables_data) { | |
return lookup_keys(i - 1 | 0, keys, tables_data); | |
} else { | |
throw [ | |
Caml_builtin_exceptions.assert_failure, | |
/* tuple */[ | |
".", | |
581, | |
25 | |
] | |
]; | |
} | |
} else { | |
var next = get_next(tables$1); | |
if (next) { | |
_tables = next; | |
continue ; | |
} else { | |
var next$1 = /* Cons */[/* record */[ | |
/* key */key, | |
/* data : Empty */0, | |
/* next : Empty */0 | |
]]; | |
set_next(tables$1, next$1); | |
return build_path(i - 1 | 0, keys, next$1); | |
} | |
} | |
}; | |
} | |
} | |
function lookup_tables(root, keys) { | |
var root_data = get_data(root); | |
if (root_data) { | |
return lookup_keys(keys.length - 1 | 0, keys, root_data); | |
} else { | |
return build_path(keys.length - 1 | 0, keys, root); | |
} | |
} | |
function get_const(x) { | |
return (function () { | |
return x; | |
}); | |
} | |
function get_var(n) { | |
return (function (obj) { | |
return obj[n]; | |
}); | |
} | |
function get_env(e, n) { | |
return (function (obj) { | |
return obj[e][n]; | |
}); | |
} | |
function get_meth(n) { | |
return (function (obj) { | |
return Curry._1(obj[0][n], obj); | |
}); | |
} | |
function set_var(n) { | |
return (function (obj, x) { | |
obj[n] = x; | |
return /* () */0; | |
}); | |
} | |
function app_const(f, x) { | |
return (function () { | |
return Curry._1(f, x); | |
}); | |
} | |
function app_var(f, n) { | |
return (function (obj) { | |
return Curry._1(f, obj[n]); | |
}); | |
} | |
function app_env(f, e, n) { | |
return (function (obj) { | |
return Curry._1(f, obj[e][n]); | |
}); | |
} | |
function app_meth(f, n) { | |
return (function (obj) { | |
return Curry._1(f, Curry._1(obj[0][n], obj)); | |
}); | |
} | |
function app_const_const(f, x, y) { | |
return (function () { | |
return Curry._2(f, x, y); | |
}); | |
} | |
function app_const_var(f, x, n) { | |
return (function (obj) { | |
return Curry._2(f, x, obj[n]); | |
}); | |
} | |
function app_const_meth(f, x, n) { | |
return (function (obj) { | |
return Curry._2(f, x, Curry._1(obj[0][n], obj)); | |
}); | |
} | |
function app_var_const(f, n, x) { | |
return (function (obj) { | |
return Curry._2(f, obj[n], x); | |
}); | |
} | |
function app_meth_const(f, n, x) { | |
return (function (obj) { | |
return Curry._2(f, Curry._1(obj[0][n], obj), x); | |
}); | |
} | |
function app_const_env(f, x, e, n) { | |
return (function (obj) { | |
return Curry._2(f, x, obj[e][n]); | |
}); | |
} | |
function app_env_const(f, e, n, x) { | |
return (function (obj) { | |
return Curry._2(f, obj[e][n], x); | |
}); | |
} | |
function meth_app_const(n, x) { | |
return (function (obj) { | |
return Curry._2(obj[0][n], obj, x); | |
}); | |
} | |
function meth_app_var(n, m) { | |
return (function (obj) { | |
return Curry._2(obj[0][n], obj, obj[m]); | |
}); | |
} | |
function meth_app_env(n, e, m) { | |
return (function (obj) { | |
return Curry._2(obj[0][n], obj, obj[e][m]); | |
}); | |
} | |
function meth_app_meth(n, m) { | |
return (function (obj) { | |
return Curry._2(obj[0][n], obj, Curry._1(obj[0][m], obj)); | |
}); | |
} | |
function send_const(m, x, _) { | |
return (function () { | |
return Curry._1(Curry._3(Caml_oo.caml_get_public_method, x, m, 13), x); | |
}); | |
} | |
function send_var(m, n, _) { | |
return (function (obj) { | |
var tmp = obj[n]; | |
return Curry._1(Curry._3(Caml_oo.caml_get_public_method, tmp, m, 14), tmp); | |
}); | |
} | |
function send_env(m, e, n, _) { | |
return (function (obj) { | |
var tmp = obj[e][n]; | |
return Curry._1(Curry._3(Caml_oo.caml_get_public_method, tmp, m, 15), tmp); | |
}); | |
} | |
function send_meth(m, n, _) { | |
return (function (obj) { | |
var tmp = Curry._1(obj[0][n], obj); | |
return Curry._1(Curry._3(Caml_oo.caml_get_public_method, tmp, m, 16), tmp); | |
}); | |
} | |
function new_cache(table) { | |
var n = new_method(table); | |
var n$1 = n % 2 === 0 || n > (2 + Caml_int32.div((Caml_array.caml_array_get(table[/* methods */1], 1) << 4), Sys.word_size) | 0) ? n : new_method(table); | |
Caml_array.caml_array_set(table[/* methods */1], n$1, 0); | |
return n$1; | |
} | |
function method_impl(table, i, arr) { | |
var next = function () { | |
i[0] = i[0] + 1 | 0; | |
return Caml_array.caml_array_get(arr, i[0]); | |
}; | |
var clo = next(/* () */0); | |
if (typeof clo === "number") { | |
switch (clo) { | |
case 0 : | |
var x = next(/* () */0); | |
return (function () { | |
return x; | |
}); | |
case 1 : | |
var n = next(/* () */0); | |
return (function (obj) { | |
return obj[n]; | |
}); | |
case 2 : | |
var e = next(/* () */0); | |
var n$1 = next(/* () */0); | |
return get_env(e, n$1); | |
case 3 : | |
return get_meth(next(/* () */0)); | |
case 4 : | |
var n$2 = next(/* () */0); | |
return (function (obj, x) { | |
obj[n$2] = x; | |
return /* () */0; | |
}); | |
case 5 : | |
var f = next(/* () */0); | |
var x$1 = next(/* () */0); | |
return (function () { | |
return Curry._1(f, x$1); | |
}); | |
case 6 : | |
var f$1 = next(/* () */0); | |
var n$3 = next(/* () */0); | |
return (function (obj) { | |
return Curry._1(f$1, obj[n$3]); | |
}); | |
case 7 : | |
var f$2 = next(/* () */0); | |
var e$1 = next(/* () */0); | |
var n$4 = next(/* () */0); | |
return app_env(f$2, e$1, n$4); | |
case 8 : | |
var f$3 = next(/* () */0); | |
var n$5 = next(/* () */0); | |
return app_meth(f$3, n$5); | |
case 9 : | |
var f$4 = next(/* () */0); | |
var x$2 = next(/* () */0); | |
var y = next(/* () */0); | |
return (function () { | |
return Curry._2(f$4, x$2, y); | |
}); | |
case 10 : | |
var f$5 = next(/* () */0); | |
var x$3 = next(/* () */0); | |
var n$6 = next(/* () */0); | |
return app_const_var(f$5, x$3, n$6); | |
case 11 : | |
var f$6 = next(/* () */0); | |
var x$4 = next(/* () */0); | |
var e$2 = next(/* () */0); | |
var n$7 = next(/* () */0); | |
return app_const_env(f$6, x$4, e$2, n$7); | |
case 12 : | |
var f$7 = next(/* () */0); | |
var x$5 = next(/* () */0); | |
var n$8 = next(/* () */0); | |
return app_const_meth(f$7, x$5, n$8); | |
case 13 : | |
var f$8 = next(/* () */0); | |
var n$9 = next(/* () */0); | |
var x$6 = next(/* () */0); | |
return app_var_const(f$8, n$9, x$6); | |
case 14 : | |
var f$9 = next(/* () */0); | |
var e$3 = next(/* () */0); | |
var n$10 = next(/* () */0); | |
var x$7 = next(/* () */0); | |
return app_env_const(f$9, e$3, n$10, x$7); | |
case 15 : | |
var f$10 = next(/* () */0); | |
var n$11 = next(/* () */0); | |
var x$8 = next(/* () */0); | |
return app_meth_const(f$10, n$11, x$8); | |
case 16 : | |
var n$12 = next(/* () */0); | |
var x$9 = next(/* () */0); | |
return meth_app_const(n$12, x$9); | |
case 17 : | |
var n$13 = next(/* () */0); | |
var m = next(/* () */0); | |
return meth_app_var(n$13, m); | |
case 18 : | |
var n$14 = next(/* () */0); | |
var e$4 = next(/* () */0); | |
var m$1 = next(/* () */0); | |
return meth_app_env(n$14, e$4, m$1); | |
case 19 : | |
var n$15 = next(/* () */0); | |
var m$2 = next(/* () */0); | |
return meth_app_meth(n$15, m$2); | |
case 20 : | |
var m$3 = next(/* () */0); | |
var x$10 = next(/* () */0); | |
return send_const(m$3, x$10, new_cache(table)); | |
case 21 : | |
var m$4 = next(/* () */0); | |
var n$16 = next(/* () */0); | |
return send_var(m$4, n$16, new_cache(table)); | |
case 22 : | |
var m$5 = next(/* () */0); | |
var e$5 = next(/* () */0); | |
var n$17 = next(/* () */0); | |
return send_env(m$5, e$5, n$17, new_cache(table)); | |
case 23 : | |
var m$6 = next(/* () */0); | |
var n$18 = next(/* () */0); | |
return send_meth(m$6, n$18, new_cache(table)); | |
} | |
} else { | |
return clo; | |
} | |
} | |
function set_methods(table, methods) { | |
var len = methods.length; | |
var i = /* record */[/* contents */0]; | |
while(i[0] < len) { | |
var label = Caml_array.caml_array_get(methods, i[0]); | |
var clo = method_impl(table, i, methods); | |
set_method(table, label, clo); | |
i[0] = i[0] + 1 | 0; | |
}; | |
return /* () */0; | |
} | |
function stats() { | |
return /* record */[ | |
/* classes */table_count[0], | |
/* methods */method_count[0], | |
/* inst_vars */inst_var_count[0] | |
]; | |
} | |
var Coo = /* module */[ | |
/* public_method_label */public_method_label, | |
/* new_method */new_method, | |
/* new_variable */new_variable, | |
/* new_methods_variables */new_methods_variables, | |
/* get_variable */get_variable, | |
/* get_variables */get_variables, | |
/* get_method_label */get_method_label, | |
/* get_method_labels */get_method_labels, | |
/* get_method */get_method, | |
/* set_method */set_method, | |
/* set_methods */set_methods, | |
/* narrow */narrow, | |
/* widen */widen, | |
/* add_initializer */add_initializer, | |
/* dummy_table */dummy_table, | |
/* create_table */create_table, | |
/* init_class */init_class, | |
/* inherits */inherits, | |
/* make_class */make_class, | |
/* make_class_store */make_class_store, | |
/* dummy_class */dummy_class, | |
/* copy */copy, | |
/* create_object */create_object, | |
/* create_object_opt */create_object_opt, | |
/* run_initializers */run_initializers, | |
/* run_initializers_opt */run_initializers_opt, | |
/* create_object_and_run_initializers */create_object_and_run_initializers, | |
/* lookup_tables */lookup_tables, | |
/* get_const */get_const, | |
/* get_var */get_var, | |
/* get_env */get_env, | |
/* get_meth */get_meth, | |
/* set_var */set_var, | |
/* app_const */app_const, | |
/* app_var */app_var, | |
/* app_env */app_env, | |
/* app_meth */app_meth, | |
/* app_const_const */app_const_const, | |
/* app_const_var */app_const_var, | |
/* app_const_env */app_const_env, | |
/* app_const_meth */app_const_meth, | |
/* app_var_const */app_var_const, | |
/* app_env_const */app_env_const, | |
/* app_meth_const */app_meth_const, | |
/* meth_app_const */meth_app_const, | |
/* meth_app_var */meth_app_var, | |
/* meth_app_env */meth_app_env, | |
/* meth_app_meth */meth_app_meth, | |
/* send_const */send_const, | |
/* send_var */send_var, | |
/* send_env */send_env, | |
/* send_meth */send_meth, | |
/* params */params, | |
/* stats */stats | |
]; | |
function Make(Ord) { | |
var height = function (param) { | |
if (param) { | |
return param[0][/* h */3]; | |
} else { | |
return 0; | |
} | |
}; | |
var create = function (l, v, r) { | |
var hl = l ? l[0][/* h */3] : 0; | |
var hr = r ? r[0][/* h */3] : 0; | |
return /* Node */[/* record */[ | |
/* l */l, | |
/* v */v, | |
/* r */r, | |
/* h */hl >= hr ? hl + 1 | 0 : hr + 1 | 0 | |
]]; | |
}; | |
var bal = function (l, v, r) { | |
var hl = l ? l[0][/* h */3] : 0; | |
var hr = r ? r[0][/* h */3] : 0; | |
if (hl > (hr + 2 | 0)) { | |
if (l) { | |
var match = l[0]; | |
var lr = match[/* r */2]; | |
var lv = match[/* v */1]; | |
var ll = match[/* l */0]; | |
if (height(ll) >= height(lr)) { | |
return create(ll, lv, create(lr, v, r)); | |
} else if (lr) { | |
var match$1 = lr[0]; | |
return create(create(ll, lv, match$1[/* l */0]), match$1[/* v */1], create(match$1[/* r */2], v, r)); | |
} else { | |
return Pervasives.invalid_arg("Set.bal"); | |
} | |
} else { | |
return Pervasives.invalid_arg("Set.bal"); | |
} | |
} else if (hr > (hl + 2 | 0)) { | |
if (r) { | |
var match$2 = r[0]; | |
var rr = match$2[/* r */2]; | |
var rv = match$2[/* v */1]; | |
var rl = match$2[/* l */0]; | |
if (height(rr) >= height(rl)) { | |
return create(create(l, v, rl), rv, rr); | |
} else if (rl) { | |
var match$3 = rl[0]; | |
return create(create(l, v, match$3[/* l */0]), match$3[/* v */1], create(match$3[/* r */2], rv, rr)); | |
} else { | |
return Pervasives.invalid_arg("Set.bal"); | |
} | |
} else { | |
return Pervasives.invalid_arg("Set.bal"); | |
} | |
} else { | |
return /* Node */[/* record */[ | |
/* l */l, | |
/* v */v, | |
/* r */r, | |
/* h */hl >= hr ? hl + 1 | 0 : hr + 1 | 0 | |
]]; | |
} | |
}; | |
var add = function (x, t) { | |
if (t) { | |
var match = t[0]; | |
var r = match[/* r */2]; | |
var v = match[/* v */1]; | |
var l = match[/* l */0]; | |
var c = Curry._2(Ord[/* compare */0], x, v); | |
if (c === 0) { | |
return t; | |
} else if (c < 0) { | |
var ll = add(x, l); | |
if (l === ll) { | |
return t; | |
} else { | |
return bal(ll, v, r); | |
} | |
} else { | |
var rr = add(x, r); | |
if (r === rr) { | |
return t; | |
} else { | |
return bal(l, v, rr); | |
} | |
} | |
} else { | |
return /* Node */[/* record */[ | |
/* l : Empty */0, | |
/* v */x, | |
/* r : Empty */0, | |
/* h */1 | |
]]; | |
} | |
}; | |
var singleton = function (x) { | |
return /* Node */[/* record */[ | |
/* l : Empty */0, | |
/* v */x, | |
/* r : Empty */0, | |
/* h */1 | |
]]; | |
}; | |
var add_min_element = function (x, param) { | |
if (param) { | |
var match = param[0]; | |
return bal(add_min_element(x, match[/* l */0]), match[/* v */1], match[/* r */2]); | |
} else { | |
return singleton(x); | |
} | |
}; | |
var add_max_element = function (x, param) { | |
if (param) { | |
var match = param[0]; | |
return bal(match[/* l */0], match[/* v */1], add_max_element(x, match[/* r */2])); | |
} else { | |
return singleton(x); | |
} | |
}; | |
var join = function (l, v, r) { | |
if (l) { | |
if (r) { | |
var match = r[0]; | |
var rh = match[/* h */3]; | |
var match$1 = l[0]; | |
var lh = match$1[/* h */3]; | |
if (lh > (rh + 2 | 0)) { | |
return bal(match$1[/* l */0], match$1[/* v */1], join(match$1[/* r */2], v, r)); | |
} else if (rh > (lh + 2 | 0)) { | |
return bal(join(l, v, match[/* l */0]), match[/* v */1], match[/* r */2]); | |
} else { | |
return create(l, v, r); | |
} | |
} else { | |
return add_max_element(v, l); | |
} | |
} else { | |
return add_min_element(v, r); | |
} | |
}; | |
var min_elt = function (_param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var l = match[/* l */0]; | |
if (l) { | |
_param = l; | |
continue ; | |
} else { | |
return match[/* v */1]; | |
} | |
} else { | |
throw Caml_builtin_exceptions.not_found; | |
} | |
}; | |
}; | |
var min_elt_opt = function (_param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var l = match[/* l */0]; | |
if (l) { | |
_param = l; | |
continue ; | |
} else { | |
return Js_primitive.some(match[/* v */1]); | |
} | |
} else { | |
return undefined; | |
} | |
}; | |
}; | |
var max_elt = function (_param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var r = match[/* r */2]; | |
if (r) { | |
_param = r; | |
continue ; | |
} else { | |
return match[/* v */1]; | |
} | |
} else { | |
throw Caml_builtin_exceptions.not_found; | |
} | |
}; | |
}; | |
var max_elt_opt = function (_param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var r = match[/* r */2]; | |
if (r) { | |
_param = r; | |
continue ; | |
} else { | |
return Js_primitive.some(match[/* v */1]); | |
} | |
} else { | |
return undefined; | |
} | |
}; | |
}; | |
var remove_min_elt = function (param) { | |
if (param) { | |
var match = param[0]; | |
var l = match[/* l */0]; | |
if (l) { | |
return bal(remove_min_elt(l), match[/* v */1], match[/* r */2]); | |
} else { | |
return match[/* r */2]; | |
} | |
} else { | |
return Pervasives.invalid_arg("Set.remove_min_elt"); | |
} | |
}; | |
var concat = function (t1, t2) { | |
if (t1) { | |
if (t2) { | |
return join(t1, min_elt(t2), remove_min_elt(t2)); | |
} else { | |
return t1; | |
} | |
} else { | |
return t2; | |
} | |
}; | |
var split = function (x, param) { | |
if (param) { | |
var match = param[0]; | |
var r = match[/* r */2]; | |
var v = match[/* v */1]; | |
var l = match[/* l */0]; | |
var c = Curry._2(Ord[/* compare */0], x, v); | |
if (c === 0) { | |
return /* tuple */[ | |
l, | |
true, | |
r | |
]; | |
} else if (c < 0) { | |
var match$1 = split(x, l); | |
return /* tuple */[ | |
match$1[0], | |
match$1[1], | |
join(match$1[2], v, r) | |
]; | |
} else { | |
var match$2 = split(x, r); | |
return /* tuple */[ | |
join(l, v, match$2[0]), | |
match$2[1], | |
match$2[2] | |
]; | |
} | |
} else { | |
return /* tuple */[ | |
/* Empty */0, | |
false, | |
/* Empty */0 | |
]; | |
} | |
}; | |
var is_empty = function (param) { | |
if (param) { | |
return false; | |
} else { | |
return true; | |
} | |
}; | |
var mem = function (x, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var c = Curry._2(Ord[/* compare */0], x, match[/* v */1]); | |
if (c === 0) { | |
return true; | |
} else { | |
_param = c < 0 ? match[/* l */0] : match[/* r */2]; | |
continue ; | |
} | |
} else { | |
return false; | |
} | |
}; | |
}; | |
var remove = function (x, t) { | |
if (t) { | |
var match = t[0]; | |
var r = match[/* r */2]; | |
var v = match[/* v */1]; | |
var l = match[/* l */0]; | |
var c = Curry._2(Ord[/* compare */0], x, v); | |
if (c === 0) { | |
var t1 = l; | |
var t2 = r; | |
if (t1) { | |
if (t2) { | |
return bal(t1, min_elt(t2), remove_min_elt(t2)); | |
} else { | |
return t1; | |
} | |
} else { | |
return t2; | |
} | |
} else if (c < 0) { | |
var ll = remove(x, l); | |
if (l === ll) { | |
return t; | |
} else { | |
return bal(ll, v, r); | |
} | |
} else { | |
var rr = remove(x, r); | |
if (r === rr) { | |
return t; | |
} else { | |
return bal(l, v, rr); | |
} | |
} | |
} else { | |
return /* Empty */0; | |
} | |
}; | |
var union = function (s1, s2) { | |
if (s1) { | |
if (s2) { | |
var match = s2[0]; | |
var h2 = match[/* h */3]; | |
var v2 = match[/* v */1]; | |
var match$1 = s1[0]; | |
var h1 = match$1[/* h */3]; | |
var v1 = match$1[/* v */1]; | |
if (h1 >= h2) { | |
if (h2 === 1) { | |
return add(v2, s1); | |
} else { | |
var match$2 = split(v1, s2); | |
return join(union(match$1[/* l */0], match$2[0]), v1, union(match$1[/* r */2], match$2[2])); | |
} | |
} else if (h1 === 1) { | |
return add(v1, s2); | |
} else { | |
var match$3 = split(v2, s1); | |
return join(union(match$3[0], match[/* l */0]), v2, union(match$3[2], match[/* r */2])); | |
} | |
} else { | |
return s1; | |
} | |
} else { | |
return s2; | |
} | |
}; | |
var inter = function (s1, s2) { | |
if (s1 && s2) { | |
var match = s1[0]; | |
var r1 = match[/* r */2]; | |
var v1 = match[/* v */1]; | |
var l1 = match[/* l */0]; | |
var match$1 = split(v1, s2); | |
var l2 = match$1[0]; | |
if (match$1[1]) { | |
return join(inter(l1, l2), v1, inter(r1, match$1[2])); | |
} else { | |
return concat(inter(l1, l2), inter(r1, match$1[2])); | |
} | |
} else { | |
return /* Empty */0; | |
} | |
}; | |
var diff = function (s1, s2) { | |
if (s1) { | |
if (s2) { | |
var match = s1[0]; | |
var r1 = match[/* r */2]; | |
var v1 = match[/* v */1]; | |
var l1 = match[/* l */0]; | |
var match$1 = split(v1, s2); | |
var l2 = match$1[0]; | |
if (match$1[1]) { | |
return concat(diff(l1, l2), diff(r1, match$1[2])); | |
} else { | |
return join(diff(l1, l2), v1, diff(r1, match$1[2])); | |
} | |
} else { | |
return s1; | |
} | |
} else { | |
return /* Empty */0; | |
} | |
}; | |
var cons_enum = function (_s, _e) { | |
while(true) { | |
var e = _e; | |
var s = _s; | |
if (s) { | |
var match = s[0]; | |
_e = /* More */[ | |
match[/* v */1], | |
match[/* r */2], | |
e | |
]; | |
_s = match[/* l */0]; | |
continue ; | |
} else { | |
return e; | |
} | |
}; | |
}; | |
var compare = function (s1, s2) { | |
var _e1 = cons_enum(s1, /* End */0); | |
var _e2 = cons_enum(s2, /* End */0); | |
while(true) { | |
var e2 = _e2; | |
var e1 = _e1; | |
if (e1) { | |
if (e2) { | |
var c = Curry._2(Ord[/* compare */0], e1[0], e2[0]); | |
if (c !== 0) { | |
return c; | |
} else { | |
_e2 = cons_enum(e2[1], e2[2]); | |
_e1 = cons_enum(e1[1], e1[2]); | |
continue ; | |
} | |
} else { | |
return 1; | |
} | |
} else if (e2) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}; | |
}; | |
var equal = function (s1, s2) { | |
return compare(s1, s2) === 0; | |
}; | |
var subset = function (_s1, _s2) { | |
while(true) { | |
var s2 = _s2; | |
var s1 = _s1; | |
if (s1) { | |
if (s2) { | |
var match = s2[0]; | |
var r2 = match[/* r */2]; | |
var l2 = match[/* l */0]; | |
var match$1 = s1[0]; | |
var r1 = match$1[/* r */2]; | |
var v1 = match$1[/* v */1]; | |
var l1 = match$1[/* l */0]; | |
var c = Curry._2(Ord[/* compare */0], v1, match[/* v */1]); | |
if (c === 0) { | |
if (subset(l1, l2)) { | |
_s2 = r2; | |
_s1 = r1; | |
continue ; | |
} else { | |
return false; | |
} | |
} else if (c < 0) { | |
if (subset(/* Node */[/* record */[ | |
/* l */l1, | |
/* v */v1, | |
/* r : Empty */0, | |
/* h */0 | |
]], l2)) { | |
_s1 = r1; | |
continue ; | |
} else { | |
return false; | |
} | |
} else if (subset(/* Node */[/* record */[ | |
/* l : Empty */0, | |
/* v */v1, | |
/* r */r1, | |
/* h */0 | |
]], r2)) { | |
_s1 = l1; | |
continue ; | |
} else { | |
return false; | |
} | |
} else { | |
return false; | |
} | |
} else { | |
return true; | |
} | |
}; | |
}; | |
var iter = function (f, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
iter(f, match[/* l */0]); | |
Curry._1(f, match[/* v */1]); | |
_param = match[/* r */2]; | |
continue ; | |
} else { | |
return /* () */0; | |
} | |
}; | |
}; | |
var fold = function (f, _s, _accu) { | |
while(true) { | |
var accu = _accu; | |
var s = _s; | |
if (s) { | |
var match = s[0]; | |
_accu = Curry._2(f, match[/* v */1], fold(f, match[/* l */0], accu)); | |
_s = match[/* r */2]; | |
continue ; | |
} else { | |
return accu; | |
} | |
}; | |
}; | |
var for_all = function (p, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
if (Curry._1(p, match[/* v */1]) && for_all(p, match[/* l */0])) { | |
_param = match[/* r */2]; | |
continue ; | |
} else { | |
return false; | |
} | |
} else { | |
return true; | |
} | |
}; | |
}; | |
var exists = function (p, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
if (Curry._1(p, match[/* v */1]) || exists(p, match[/* l */0])) { | |
return true; | |
} else { | |
_param = match[/* r */2]; | |
continue ; | |
} | |
} else { | |
return false; | |
} | |
}; | |
}; | |
var filter = function (p, t) { | |
if (t) { | |
var match = t[0]; | |
var r = match[/* r */2]; | |
var v = match[/* v */1]; | |
var l = match[/* l */0]; | |
var l$prime = filter(p, l); | |
var pv = Curry._1(p, v); | |
var r$prime = filter(p, r); | |
if (pv) { | |
if (l === l$prime && r === r$prime) { | |
return t; | |
} else { | |
return join(l$prime, v, r$prime); | |
} | |
} else { | |
return concat(l$prime, r$prime); | |
} | |
} else { | |
return /* Empty */0; | |
} | |
}; | |
var partition = function (p, param) { | |
if (param) { | |
var match = param[0]; | |
var v = match[/* v */1]; | |
var match$1 = partition(p, match[/* l */0]); | |
var lf = match$1[1]; | |
var lt = match$1[0]; | |
var pv = Curry._1(p, v); | |
var match$2 = partition(p, match[/* r */2]); | |
var rf = match$2[1]; | |
var rt = match$2[0]; | |
if (pv) { | |
return /* tuple */[ | |
join(lt, v, rt), | |
concat(lf, rf) | |
]; | |
} else { | |
return /* tuple */[ | |
concat(lt, rt), | |
join(lf, v, rf) | |
]; | |
} | |
} else { | |
return /* tuple */[ | |
/* Empty */0, | |
/* Empty */0 | |
]; | |
} | |
}; | |
var cardinal = function (param) { | |
if (param) { | |
var match = param[0]; | |
return (cardinal(match[/* l */0]) + 1 | 0) + cardinal(match[/* r */2]) | 0; | |
} else { | |
return 0; | |
} | |
}; | |
var elements_aux = function (_accu, _param) { | |
while(true) { | |
var param = _param; | |
var accu = _accu; | |
if (param) { | |
var match = param[0]; | |
_param = match[/* l */0]; | |
_accu = /* :: */[ | |
match[/* v */1], | |
elements_aux(accu, match[/* r */2]) | |
]; | |
continue ; | |
} else { | |
return accu; | |
} | |
}; | |
}; | |
var elements = function (s) { | |
return elements_aux(/* [] */0, s); | |
}; | |
var find = function (x, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var v = match[/* v */1]; | |
var c = Curry._2(Ord[/* compare */0], x, v); | |
if (c === 0) { | |
return v; | |
} else { | |
_param = c < 0 ? match[/* l */0] : match[/* r */2]; | |
continue ; | |
} | |
} else { | |
throw Caml_builtin_exceptions.not_found; | |
} | |
}; | |
}; | |
var find_first = function (f, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var v = match[/* v */1]; | |
if (Curry._1(f, v)) { | |
var _v0 = v; | |
var f$1 = f; | |
var _param$1 = match[/* l */0]; | |
while(true) { | |
var param$1 = _param$1; | |
var v0 = _v0; | |
if (param$1) { | |
var match$1 = param$1[0]; | |
var v$1 = match$1[/* v */1]; | |
if (Curry._1(f$1, v$1)) { | |
_param$1 = match$1[/* l */0]; | |
_v0 = v$1; | |
continue ; | |
} else { | |
_param$1 = match$1[/* r */2]; | |
continue ; | |
} | |
} else { | |
return v0; | |
} | |
}; | |
} else { | |
_param = match[/* r */2]; | |
continue ; | |
} | |
} else { | |
throw Caml_builtin_exceptions.not_found; | |
} | |
}; | |
}; | |
var find_first_opt = function (f, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var v = match[/* v */1]; | |
if (Curry._1(f, v)) { | |
var _v0 = v; | |
var f$1 = f; | |
var _param$1 = match[/* l */0]; | |
while(true) { | |
var param$1 = _param$1; | |
var v0 = _v0; | |
if (param$1) { | |
var match$1 = param$1[0]; | |
var v$1 = match$1[/* v */1]; | |
if (Curry._1(f$1, v$1)) { | |
_param$1 = match$1[/* l */0]; | |
_v0 = v$1; | |
continue ; | |
} else { | |
_param$1 = match$1[/* r */2]; | |
continue ; | |
} | |
} else { | |
return Js_primitive.some(v0); | |
} | |
}; | |
} else { | |
_param = match[/* r */2]; | |
continue ; | |
} | |
} else { | |
return undefined; | |
} | |
}; | |
}; | |
var find_last = function (f, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var v = match[/* v */1]; | |
if (Curry._1(f, v)) { | |
var _v0 = v; | |
var f$1 = f; | |
var _param$1 = match[/* r */2]; | |
while(true) { | |
var param$1 = _param$1; | |
var v0 = _v0; | |
if (param$1) { | |
var match$1 = param$1[0]; | |
var v$1 = match$1[/* v */1]; | |
if (Curry._1(f$1, v$1)) { | |
_param$1 = match$1[/* r */2]; | |
_v0 = v$1; | |
continue ; | |
} else { | |
_param$1 = match$1[/* l */0]; | |
continue ; | |
} | |
} else { | |
return v0; | |
} | |
}; | |
} else { | |
_param = match[/* l */0]; | |
continue ; | |
} | |
} else { | |
throw Caml_builtin_exceptions.not_found; | |
} | |
}; | |
}; | |
var find_last_opt = function (f, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var v = match[/* v */1]; | |
if (Curry._1(f, v)) { | |
var _v0 = v; | |
var f$1 = f; | |
var _param$1 = match[/* r */2]; | |
while(true) { | |
var param$1 = _param$1; | |
var v0 = _v0; | |
if (param$1) { | |
var match$1 = param$1[0]; | |
var v$1 = match$1[/* v */1]; | |
if (Curry._1(f$1, v$1)) { | |
_param$1 = match$1[/* r */2]; | |
_v0 = v$1; | |
continue ; | |
} else { | |
_param$1 = match$1[/* l */0]; | |
continue ; | |
} | |
} else { | |
return Js_primitive.some(v0); | |
} | |
}; | |
} else { | |
_param = match[/* l */0]; | |
continue ; | |
} | |
} else { | |
return undefined; | |
} | |
}; | |
}; | |
var find_opt = function (x, _param) { | |
while(true) { | |
var param = _param; | |
if (param) { | |
var match = param[0]; | |
var v = match[/* v */1]; | |
var c = Curry._2(Ord[/* compare */0], x, v); | |
if (c === 0) { | |
return Js_primitive.some(v); | |
} else { | |
_param = c < 0 ? match[/* l */0] : match[/* r */2]; | |
continue ; | |
} | |
} else { | |
return undefined; | |
} | |
}; | |
}; | |
var map = function (f, t) { | |
if (t) { | |
var match = t[0]; | |
var r = match[/* r */2]; | |
var v = match[/* v */1]; | |
var l = match[/* l */0]; | |
var l$prime = map(f, l); | |
var v$prime = Curry._1(f, v); | |
var r$prime = map(f, r); | |
if (l === l$prime && v === v$prime && r === r$prime) { | |
return t; | |
} else { | |
var l$1 = l$prime; | |
var v$1 = v$prime; | |
var r$1 = r$prime; | |
if ((l$1 === /* Empty */0 || Curry._2(Ord[/* compare */0], max_elt(l$1), v$1) < 0) && (r$1 === /* Empty */0 || Curry._2(Ord[/* compare */0], v$1, min_elt(r$1)) < 0)) { | |
return join(l$1, v$1, r$1); | |
} else { | |
return union(l$1, add(v$1, r$1)); | |
} | |
} | |
} else { | |
return /* Empty */0; | |
} | |
}; | |
var of_list = function (l) { | |
if (l) { | |
var match = l[1]; | |
var x0 = l[0]; | |
if (match) { | |
var match$1 = match[1]; | |
var x1 = match[0]; | |
if (match$1) { | |
var match$2 = match$1[1]; | |
var x2 = match$1[0]; | |
if (match$2) { | |
var match$3 = match$2[1]; | |
var x3 = match$2[0]; | |
if (match$3) { | |
if (match$3[1]) { | |
var l$1 = List.sort_uniq(Ord[/* compare */0], l); | |
var sub = function (n, l) { | |
var exit = 0; | |
if (n > 3 || n < 0) { | |
exit = 1; | |
} else { | |
switch (n) { | |
case 0 : | |
return /* tuple */[ | |
/* Empty */0, | |
l | |
]; | |
case 1 : | |
if (l) { | |
return /* tuple */[ | |
/* Node */[/* record */[ | |
/* l : Empty */0, | |
/* v */l[0], | |
/* r : Empty */0, | |
/* h */1 | |
]], | |
l[1] | |
]; | |
} else { | |
exit = 1; | |
} | |
break; | |
case 2 : | |
if (l) { | |
var match = l[1]; | |
if (match) { | |
return /* tuple */[ | |
/* Node */[/* record */[ | |
/* l : Node */[/* record */[ | |
/* l : Empty */0, | |
/* v */l[0], | |
/* r : Empty */0, | |
/* h */1 | |
]], | |
/* v */match[0], | |
/* r : Empty */0, | |
/* h */2 | |
]], | |
match[1] | |
]; | |
} else { | |
exit = 1; | |
} | |
} else { | |
exit = 1; | |
} | |
break; | |
case 3 : | |
if (l) { | |
var match$1 = l[1]; | |
if (match$1) { | |
var match$2 = match$1[1]; | |
if (match$2) { | |
return /* tuple */[ | |
/* Node */[/* record */[ | |
/* l : Node */[/* record */[ | |
/* l : Empty */0, | |
/* v */l[0], | |
/* r : Empty */0, | |
/* h */1 | |
]], | |
/* v */match$1[0], | |
/* r : Node */[/* record */[ | |
/* l : Empty */0, | |
/* v */match$2[0], | |
/* r : Empty */0, | |
/* h */1 | |
]], | |
/* h */2 | |
]], | |
match$2[1] | |
]; | |
} else { | |
exit = 1; | |
} | |
} else { | |
exit = 1; | |
} | |
} else { | |
exit = 1; | |
} | |
break; | |
} | |
} | |
if (exit === 1) { | |
var nl = n / 2 | 0; | |
var match$3 = sub(nl, l); | |
var l$1 = match$3[1]; | |
if (l$1) { | |
var match$4 = sub((n - nl | 0) - 1 | 0, l$1[1]); | |
return /* tuple */[ | |
create(match$3[0], l$1[0], match$4[0]), | |
match$4[1] | |
]; | |
} else { | |
throw [ | |
Caml_builtin_exceptions.assert_failure, | |
/* tuple */[ | |
".", | |
1251, | |
22 | |
] | |
]; | |
} | |
} | |
}; | |
return sub(List.length(l$1), l$1)[0]; | |
} else { | |
return add(match$3[0], add(x3, add(x2, add(x1, singleton(x0))))); | |
} | |
} else { | |
return add(x3, add(x2, add(x1, singleton(x0)))); | |
} | |
} else { | |
return add(x2, add(x1, singleton(x0))); | |
} | |
} else { | |
return add(x1, singleton(x0)); | |
} | |
} else { | |
return singleton(x0); | |
} | |
} else { | |
return /* Empty */0; | |
} | |
}; | |
return /* module */[ | |
/* empty : Empty */0, | |
/* is_empty */is_empty, | |
/* mem */mem, | |
/* add */add, | |
/* singleton */singleton, | |
/* remove */remove, | |
/* union */union, | |
/* inter */inter, | |
/* diff */diff, | |
/* compare */compare, | |
/* equal */equal, | |
/* subset */subset, | |
/* iter */iter, | |
/* map */map, | |
/* fold */fold, | |
/* for_all */for_all, | |
/* exists */exists, | |
/* filter */filter, | |
/* partition */partition, | |
/* cardinal */cardinal, | |
/* elements */elements, | |
/* min_elt */min_elt, | |
/* min_elt_opt */min_elt_opt, | |
/* max_elt */max_elt, | |
/* max_elt_opt */max_elt_opt, | |
/* choose */min_elt, | |
/* choose_opt */min_elt_opt, | |
/* split */split, | |
/* find */find, | |
/* find_opt */find_opt, | |
/* find_first */find_first, | |
/* find_first_opt */find_first_opt, | |
/* find_last */find_last, | |
/* find_last_opt */find_last_opt, | |
/* of_list */of_list | |
]; | |
} | |
var Empty = Caml_exceptions.create("Test.Stack.Empty"); | |
function create() { | |
return /* record */[ | |
/* c : [] */0, | |
/* len */0 | |
]; | |
} | |
function clear(s) { | |
s[/* c */0] = /* [] */0; | |
s[/* len */1] = 0; | |
return /* () */0; | |
} | |
function copy$1(s) { | |
return /* record */[ | |
/* c */s[/* c */0], | |
/* len */s[/* len */1] | |
]; | |
} | |
function push(x, s) { | |
s[/* c */0] = /* :: */[ | |
x, | |
s[/* c */0] | |
]; | |
s[/* len */1] = s[/* len */1] + 1 | 0; | |
return /* () */0; | |
} | |
function pop(s) { | |
var match = s[/* c */0]; | |
if (match) { | |
s[/* c */0] = match[1]; | |
s[/* len */1] = s[/* len */1] - 1 | 0; | |
return match[0]; | |
} else { | |
throw Empty; | |
} | |
} | |
function top(s) { | |
var match = s[/* c */0]; | |
if (match) { | |
return match[0]; | |
} else { | |
throw Empty; | |
} | |
} | |
function is_empty(s) { | |
return s[/* c */0] === /* [] */0; | |
} | |
function length(s) { | |
return s[/* len */1]; | |
} | |
function iter(f, s) { | |
return List.iter(f, s[/* c */0]); | |
} | |
function fold(f, acc, s) { | |
return List.fold_left(f, acc, s[/* c */0]); | |
} | |
var Stack = /* module */[ | |
/* Empty */Empty, | |
/* create */create, | |
/* push */push, | |
/* pop */pop, | |
/* top */top, | |
/* clear */clear, | |
/* copy */copy$1, | |
/* is_empty */is_empty, | |
/* length */length, | |
/* iter */iter, | |
/* fold */fold | |
]; | |
exports.Obj = Obj; | |
exports.Coo = Coo; | |
exports.Make = Make; | |
exports.Stack = Stack; | |
/* Vars Not a pure module */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module type OBJ = { | |
/** Operations on internal representations of values. | |
Not for the casual user. | |
*/; | |
type t; | |
external repr: 'a => t = "%identity"; | |
external obj: t => 'a = "%identity"; | |
external magic: 'a => 'b = "%identity"; | |
let is_block: t => bool; | |
external is_int: t => bool = "%obj_is_int"; | |
external tag: t => int = "caml_obj_tag"; | |
external size: t => int = "%obj_size"; | |
/** | |
Computes the total size (in words, including the headers) of all | |
heap blocks accessible from the argument. Statically | |
allocated blocks are excluded. | |
@Since 4.04 | |
*/ | |
external reachable_words: t => int = "caml_obj_reachable_words"; | |
external field: (t, int) => t = "%obj_field"; | |
/** When using flambda: | |
[set_field] MUST NOT be called on immutable blocks. (Blocks allocated | |
in C stubs, or with [new_block] below, are always considered mutable.) | |
The same goes for [set_tag]. However, for | |
[set_tag], in the case of immutable blocks where the middle-end optimizers | |
never see code that discriminates on their tag (for example records), the | |
operation should be safe. Such uses are nonetheless discouraged. | |
For experts only: | |
[set_field] et al can be made safe by first wrapping the block in | |
{!Sys.opaque_identity}, so any information about its contents will not | |
be propagated. | |
*/ | |
external set_field: (t, int, t) => unit = "%obj_set_field"; | |
external set_tag: (t, int) => unit = "caml_obj_set_tag"; | |
external new_block: (int, int) => t = "caml_obj_block"; | |
external dup: t => t = "caml_obj_dup"; | |
external truncate: (t, int) => unit = "caml_obj_truncate"; | |
external add_offset: (t, Int32.t) => t = "caml_obj_add_offset"; | |
let first_non_constant_constructor_tag: int; | |
let last_non_constant_constructor_tag: int; | |
let lazy_tag: int; | |
let closure_tag: int; | |
let object_tag: int; | |
let infix_tag: int; | |
let forward_tag: int; | |
let no_scan_tag: int; | |
let abstract_tag: int; | |
let string_tag: int; | |
let double_tag: int; | |
let double_array_tag: int; | |
let custom_tag: int; | |
[@ocaml.deprecated "Replaced by custom_tag."] | |
let final_tag: int; | |
let int_tag: int; | |
let out_of_heap_tag: int; | |
let unaligned_tag: int; | |
type extension_constructor; | |
[@inline always]; | |
let extension_constructor: 'a => extension_constructor; | |
let extension_name: extension_constructor => string; | |
let extension_id: extension_constructor => int; | |
}; | |
module Obj: OBJ = { | |
type t; | |
external repr: 'a => t = "%identity"; | |
external obj: t => 'a = "%identity"; | |
external magic: 'a => 'b = "%identity"; | |
external is_int: t => bool = "%obj_is_int"; | |
let is_block = a => !is_int(a); | |
external tag: t => int = "caml_obj_tag"; | |
external set_tag: (t, int) => unit = "caml_obj_set_tag"; | |
external size: t => int = "%obj_size"; | |
external reachable_words: t => int = "caml_obj_reachable_words"; | |
external field: (t, int) => t = "%obj_field"; | |
external set_field: (t, int, t) => unit = "%obj_set_field"; | |
external new_block: (int, int) => t = "caml_obj_block"; | |
external dup: t => t = "caml_obj_dup"; | |
external truncate: (t, int) => unit = "caml_obj_truncate"; | |
external add_offset: (t, Int32.t) => t = "caml_obj_add_offset"; | |
let first_non_constant_constructor_tag = 0; | |
let last_non_constant_constructor_tag = 245; | |
let lazy_tag = 246; | |
let closure_tag = 247; | |
let object_tag = 248; | |
let infix_tag = 249; | |
let forward_tag = 250; | |
let no_scan_tag = 251; | |
let abstract_tag = 251; | |
let string_tag = 252; | |
let double_tag = 253; | |
let double_array_tag = 254; | |
let custom_tag = 255; | |
let final_tag = custom_tag; | |
let int_tag = 1000; | |
let out_of_heap_tag = 1001; | |
let unaligned_tag = 1002; | |
type extension_constructor; | |
let extension_constructor = x => { | |
let x = repr(x); | |
let slot = | |
if (is_block(x) && tag(x) != object_tag && size(x) >= 1) { | |
field(x, 0); | |
} else { | |
x; | |
}; | |
let name = | |
if (is_block(slot) && tag(slot) == object_tag) { | |
field(slot, 0); | |
} else { | |
invalid_arg("Obj.extension_constructor"); | |
}; | |
if (tag(name) == string_tag) { | |
(obj(slot): extension_constructor); | |
} else { | |
invalid_arg("Obj.extension_constructor"); | |
}; | |
}; | |
let extension_name = (slot: extension_constructor): string => | |
obj(field(repr(slot), 0)); | |
let extension_id = (slot: extension_constructor): int => | |
obj(field(repr(slot), 1)); | |
}; | |
module type COO = { | |
/** Run-time support for objects and classes. | |
All functions in this module are for system use only, not for the | |
casual user. */; | |
/** {1 Classes} */; | |
type tag; | |
type label; | |
type table; | |
type meth; | |
type t; | |
type obj; | |
type closure; | |
let public_method_label: string => tag; | |
let new_method: table => label; | |
let new_variable: (table, string) => int; | |
let new_methods_variables: | |
(table, array(string), array(string)) => array(label); | |
let get_variable: (table, string) => int; | |
let get_variables: (table, array(string)) => array(int); | |
let get_method_label: (table, string) => label; | |
let get_method_labels: (table, array(string)) => array(label); | |
let get_method: (table, label) => meth; | |
let set_method: (table, label, meth) => unit; | |
let set_methods: (table, array(label)) => unit; | |
let narrow: (table, array(string), array(string), array(string)) => unit; | |
let widen: table => unit; | |
let add_initializer: (table, obj => unit) => unit; | |
let dummy_table: table; | |
let create_table: array(string) => table; | |
let init_class: table => unit; | |
let inherits: | |
( | |
table, | |
array(string), | |
array(string), | |
array(string), | |
(t, (table, obj) => Obj.t, t, obj), | |
bool | |
) => | |
array(Obj.t); | |
let make_class: | |
(array(string), (table, Obj.t) => t) => | |
(t, (table, Obj.t) => t, Obj.t => t, Obj.t); | |
type init_table; | |
let make_class_store: (array(string), table => t, init_table) => unit; | |
let dummy_class: | |
((string, int, int)) => (t, (table, Obj.t) => t, Obj.t => t, Obj.t); | |
/** {1 Objects} */; | |
let copy: ({..} as 'a) => 'a; | |
let create_object: table => obj; | |
let create_object_opt: (obj, table) => obj; | |
let run_initializers: (obj, table) => unit; | |
let run_initializers_opt: (obj, obj, table) => obj; | |
let create_object_and_run_initializers: (obj, table) => obj; | |
external send: (obj, tag) => t = "%send"; | |
external sendcache: (obj, tag, t, int) => t = "%sendcache"; | |
external sendself: (obj, label) => t = "%sendself"; | |
[@noalloc] | |
external get_public_method: (obj, tag) => closure = "caml_get_public_method"; | |
/** {1 Table cache} */; | |
type tables; | |
let lookup_tables: (tables, array(closure)) => tables; | |
/** {1 Builtins to reduce code size} */; | |
let get_const: t => closure; | |
let get_var: int => closure; | |
let get_env: (int, int) => closure; | |
let get_meth: label => closure; | |
let set_var: int => closure; | |
let app_const: (t => t, t) => closure; | |
let app_var: (t => t, int) => closure; | |
let app_env: (t => t, int, int) => closure; | |
let app_meth: (t => t, label) => closure; | |
let app_const_const: ((t, t) => t, t, t) => closure; | |
let app_const_var: ((t, t) => t, t, int) => closure; | |
let app_const_env: ((t, t) => t, t, int, int) => closure; | |
let app_const_meth: ((t, t) => t, t, label) => closure; | |
let app_var_const: ((t, t) => t, int, t) => closure; | |
let app_env_const: ((t, t) => t, int, int, t) => closure; | |
let app_meth_const: ((t, t) => t, label, t) => closure; | |
let meth_app_const: (label, t) => closure; | |
let meth_app_var: (label, int) => closure; | |
let meth_app_env: (label, int, int) => closure; | |
let meth_app_meth: (label, label) => closure; | |
let send_const: (tag, obj, int) => closure; | |
let send_var: (tag, int, int) => closure; | |
let send_env: (tag, int, int, int) => closure; | |
let send_meth: (tag, label, int) => closure; | |
type impl = | |
| GetConst | |
| GetVar | |
| GetEnv | |
| GetMeth | |
| SetVar | |
| AppConst | |
| AppVar | |
| AppEnv | |
| AppMeth | |
| AppConstConst | |
| AppConstVar | |
| AppConstEnv | |
| AppConstMeth | |
| AppVarConst | |
| AppEnvConst | |
| AppMethConst | |
| MethAppConst | |
| MethAppVar | |
| MethAppEnv | |
| MethAppMeth | |
| SendConst | |
| SendVar | |
| SendEnv | |
| SendMeth | |
| Closure(closure); | |
/** {1 Parameters} */; | |
type params = { | |
mutable compact_table: bool, | |
mutable copy_parent: bool, | |
mutable clean_when_copying: bool, | |
mutable retry_count: int, | |
mutable bucket_small_size: int, | |
}; | |
let params: params; | |
/** {1 Statistics} */; | |
type stats = { | |
classes: int, | |
methods: int, | |
inst_vars: int, | |
}; | |
let stats: unit => stats; | |
}; | |
module Coo: COO = { | |
open Obj; | |
/**** Object representation ****/ | |
[@noalloc] external set_id: 'a => 'a = "caml_set_oo_id"; | |
/**** Object copy ****/ | |
let copy = o => { | |
let o = Obj.obj(Obj.dup(Obj.repr(o))); | |
set_id(o); | |
}; | |
/**** Compression options ****/ | |
/* Parameters */ | |
type params = { | |
mutable compact_table: bool, | |
mutable copy_parent: bool, | |
mutable clean_when_copying: bool, | |
mutable retry_count: int, | |
mutable bucket_small_size: int, | |
}; | |
let params = { | |
compact_table: true, | |
copy_parent: true, | |
clean_when_copying: true, | |
retry_count: 3, | |
bucket_small_size: 16, | |
}; | |
/**** Parameters ****/ | |
let initial_object_size = 2; | |
/**** Items ****/ | |
type item = | |
| DummyA | |
| DummyB | |
| DummyC(int); | |
[DummyA, DummyB, DummyC(0)]; /* to avoid warnings */ | |
let dummy_item: item = magic(); | |
/**** Types ****/ | |
type tag; | |
type label = int; | |
type closure = item; | |
type t = | |
| DummyA | |
| DummyB | |
| DummyC(int); | |
[DummyA, DummyB, DummyC(0)]; /* to avoid warnings */ | |
type obj = array(t); | |
external ret: (obj => 'a) => closure = "%identity"; | |
/**** Labels ****/ | |
let public_method_label = s: tag => { | |
let accu = ref(0); | |
for (i in 0 to String.length(s) - 1) { | |
accu := 223 * accu^ + Char.code(s.[i]); | |
}; | |
/* reduce to 31 bits */ | |
accu := accu^ land (1 lsl 31 - 1); | |
/* make it signed for 64 bits architectures */ | |
let tag = | |
if (accu^ > 1073741823) { | |
accu^ - 1 lsl 31; | |
} else { | |
accu^; | |
}; | |
/* Printf.eprintf "%s = %d\n" s tag; flush stderr; */ | |
magic(tag); | |
}; | |
/**** Sparse array ****/ | |
module Vars = | |
Map.Make({ | |
type t = string; | |
let compare = (x: t, y) => compare(x, y); | |
}); | |
type vars = Vars.t(int); | |
module Meths = | |
Map.Make({ | |
type t = string; | |
let compare = (x: t, y) => compare(x, y); | |
}); | |
type meths = Meths.t(label); | |
module Labs = | |
Map.Make({ | |
type t = label; | |
let compare = (x: t, y) => compare(x, y); | |
}); | |
type labs = Labs.t(bool); | |
/* The compiler assumes that the first field of this structure is [size]. */ | |
type table = { | |
mutable size: int, | |
mutable methods: array(closure), | |
mutable methods_by_name: meths, | |
mutable methods_by_label: labs, | |
mutable previous_states: | |
list( | |
( | |
meths, | |
labs, | |
list((label, item)), | |
vars, | |
list(label), | |
list(string), | |
), | |
), | |
mutable hidden_meths: list((label, item)), | |
mutable vars, | |
mutable initializers: list(obj => unit), | |
}; | |
let dummy_table = { | |
methods: [|dummy_item|], | |
methods_by_name: Meths.empty, | |
methods_by_label: Labs.empty, | |
previous_states: [], | |
hidden_meths: [], | |
vars: Vars.empty, | |
initializers: [], | |
size: 0, | |
}; | |
let table_count = ref(0); | |
/* dummy_met should be a pointer, so use an atom */ | |
let dummy_met: item = obj(Obj.new_block(0, 0)); | |
/* if debugging is needed, this could be a good idea: */ | |
/* let dummy_met () = failwith "Undefined method" */ | |
let rec fit_size = n => | |
if (n <= 2) { | |
n; | |
} else { | |
fit_size((n + 1) / 2) * 2; | |
}; | |
let new_table = pub_labels => { | |
incr(table_count); | |
let len = Array.length(pub_labels); | |
let methods = Array.make(len * 2 + 2, dummy_met); | |
methods[0] = magic(len); | |
methods[1] = magic(fit_size(len) * Sys.word_size / 8 - 1); | |
for (i in 0 to len - 1) { | |
methods[i * 2 + 3] = magic(pub_labels[i]); | |
}; | |
{ | |
methods, | |
methods_by_name: Meths.empty, | |
methods_by_label: Labs.empty, | |
previous_states: [], | |
hidden_meths: [], | |
vars: Vars.empty, | |
initializers: [], | |
size: initial_object_size, | |
}; | |
}; | |
let resize = (array, new_size) => { | |
let old_size = Array.length(array.methods); | |
if (new_size > old_size) { | |
let new_buck = Array.make(new_size, dummy_met); | |
Array.blit(array.methods, 0, new_buck, 0, old_size); | |
array.methods = new_buck; | |
}; | |
}; | |
let put = (array, label, element) => { | |
resize(array, label + 1); | |
array.methods[label] = element; | |
}; | |
/**** Classes ****/ | |
let method_count = ref(0); | |
let inst_var_count = ref(0); | |
/* type t */ | |
type meth = item; | |
let new_method = table => { | |
let index = Array.length(table.methods); | |
resize(table, index + 1); | |
index; | |
}; | |
let get_method_label = (table, name) => | |
try (Meths.find(name, table.methods_by_name)) { | |
| Not_found => | |
let label = new_method(table); | |
table.methods_by_name = Meths.add(name, label, table.methods_by_name); | |
table.methods_by_label = Labs.add(label, true, table.methods_by_label); | |
label; | |
}; | |
let get_method_labels = (table, names) => | |
Array.map(get_method_label(table), names); | |
let set_method = (table, label, element) => { | |
incr(method_count); | |
if (Labs.find(label, table.methods_by_label)) { | |
put(table, label, element); | |
} else { | |
table.hidden_meths = [(label, element), ...table.hidden_meths]; | |
}; | |
}; | |
let get_method = (table, label) => | |
try (List.assoc(label, table.hidden_meths)) { | |
| Not_found => table.methods[label] | |
}; | |
let to_list = arr => | |
if (arr === magic(0)) { | |
[]; | |
} else { | |
Array.to_list(arr); | |
}; | |
let narrow = (table, vars, virt_meths, concr_meths) => { | |
let vars = to_list(vars) | |
and virt_meths = to_list(virt_meths) | |
and concr_meths = to_list(concr_meths); | |
let virt_meth_labs = List.map(get_method_label(table), virt_meths); | |
let concr_meth_labs = List.map(get_method_label(table), concr_meths); | |
table.previous_states = [ | |
( | |
table.methods_by_name, | |
table.methods_by_label, | |
table.hidden_meths, | |
table.vars, | |
virt_meth_labs, | |
vars, | |
), | |
...table.previous_states, | |
]; | |
table.vars = | |
Vars.fold( | |
(lab, info, tvars) => | |
if (List.mem(lab, vars)) { | |
Vars.add(lab, info, tvars); | |
} else { | |
tvars; | |
}, | |
table.vars, | |
Vars.empty, | |
); | |
let by_name = ref(Meths.empty); | |
let by_label = ref(Labs.empty); | |
List.iter2( | |
(met, label) => { | |
by_name := Meths.add(met, label, by_name^); | |
by_label := | |
Labs.add( | |
label, | |
try (Labs.find(label, table.methods_by_label)) { | |
| Not_found => true | |
}, | |
by_label^, | |
); | |
}, | |
concr_meths, | |
concr_meth_labs, | |
); | |
List.iter2( | |
(met, label) => { | |
by_name := Meths.add(met, label, by_name^); | |
by_label := Labs.add(label, false, by_label^); | |
}, | |
virt_meths, | |
virt_meth_labs, | |
); | |
table.methods_by_name = by_name^; | |
table.methods_by_label = by_label^; | |
table.hidden_meths = | |
List.fold_right( | |
((lab, _) as met, hm) => | |
if (List.mem(lab, virt_meth_labs)) { | |
hm; | |
} else { | |
[met, ...hm]; | |
}, | |
table.hidden_meths, | |
[], | |
); | |
}; | |
let widen = table => { | |
let (by_name, by_label, saved_hidden_meths, saved_vars, virt_meths, vars) = | |
List.hd(table.previous_states); | |
table.previous_states = List.tl(table.previous_states); | |
table.vars = | |
List.fold_left( | |
(s, v) => Vars.add(v, Vars.find(v, table.vars), s), | |
saved_vars, | |
vars, | |
); | |
table.methods_by_name = by_name; | |
table.methods_by_label = by_label; | |
table.hidden_meths = | |
List.fold_right( | |
((lab, _) as met, hm) => | |
if (List.mem(lab, virt_meths)) { | |
hm; | |
} else { | |
[met, ...hm]; | |
}, | |
table.hidden_meths, | |
saved_hidden_meths, | |
); | |
}; | |
let new_slot = table => { | |
let index = table.size; | |
table.size = index + 1; | |
index; | |
}; | |
let new_variable = (table, name) => | |
try (Vars.find(name, table.vars)) { | |
| Not_found => | |
let index = new_slot(table); | |
if (name != "") { | |
table.vars = Vars.add(name, index, table.vars); | |
}; | |
index; | |
}; | |
let to_array = arr => | |
if (arr == Obj.magic(0)) { | |
[||]; | |
} else { | |
arr; | |
}; | |
let new_methods_variables = (table, meths, vals) => { | |
let meths = to_array(meths); | |
let nmeths = Array.length(meths) | |
and nvals = Array.length(vals); | |
let res = Array.make(nmeths + nvals, 0); | |
for (i in 0 to nmeths - 1) { | |
res[i] = get_method_label(table, meths[i]); | |
}; | |
for (i in 0 to nvals - 1) { | |
res[i + nmeths] = new_variable(table, vals[i]); | |
}; | |
res; | |
}; | |
let get_variable = (table, name) => | |
try (Vars.find(name, table.vars)) { | |
| Not_found => assert(false) | |
}; | |
let get_variables = (table, names) => | |
Array.map(get_variable(table), names); | |
let add_initializer = (table, f) => | |
table.initializers = [f, ...table.initializers]; | |
/* | |
module Keys = | |
Map.Make(struct type t = tag array let compare (x:t) y = compare x y end) | |
let key_map = ref Keys.empty | |
let get_key tags : item = | |
try magic (Keys.find tags !key_map : tag array) | |
with Not_found -> | |
key_map := Keys.add tags tags !key_map; | |
magic tags | |
*/ | |
let create_table = public_methods => | |
if (public_methods === magic(0)) { | |
new_table([||]); | |
} else { | |
/* [public_methods] must be in ascending order for bytecode */ | |
let tags = Array.map(public_method_label, public_methods); | |
let table = new_table(tags); | |
Array.iteri( | |
(i, met) => { | |
let lab = i * 2 + 2; | |
table.methods_by_name = Meths.add(met, lab, table.methods_by_name); | |
table.methods_by_label = | |
Labs.add(lab, true, table.methods_by_label); | |
}, | |
public_methods, | |
); | |
table; | |
}; | |
let init_class = table => { | |
inst_var_count := inst_var_count^ + table.size - 1; | |
table.initializers = List.rev(table.initializers); | |
resize(table, 3 + magic(table.methods[1]) * 16 / Sys.word_size); | |
}; | |
let inherits = | |
(cla, vals, virt_meths, concr_meths, (_, super, _, env), top) => { | |
narrow(cla, vals, virt_meths, concr_meths); | |
let init = | |
if (top) { | |
super(cla, env); | |
} else { | |
Obj.repr(super(cla)); | |
}; | |
widen(cla); | |
Array.concat([ | |
[|repr(init)|], | |
magic(Array.map(get_variable(cla), to_array(vals)): array(int)), | |
Array.map( | |
nm => repr(get_method(cla, get_method_label(cla, nm)): closure), | |
to_array(concr_meths), | |
), | |
]); | |
}; | |
let make_class = (pub_meths, class_init) => { | |
let table = create_table(pub_meths); | |
let env_init = class_init(table); | |
init_class(table); | |
(env_init(Obj.repr(0)), class_init, env_init, Obj.repr(0)); | |
}; | |
type init_table = { | |
mutable env_init: t, | |
mutable class_init: table => t, | |
}; | |
let make_class_store = (pub_meths, class_init, init_table) => { | |
let table = create_table(pub_meths); | |
let env_init = class_init(table); | |
init_class(table); | |
init_table.class_init = class_init; | |
init_table.env_init = env_init; | |
}; | |
let dummy_class = loc => { | |
let undef = _ => raise(Undefined_recursive_module(loc)); | |
(Obj.magic(undef), undef, undef, Obj.repr(0)); | |
}; | |
/**** Objects ****/ | |
let create_object = table => { | |
/* XXX Appel de [obj_block] | Call to [obj_block] */ | |
let obj = Obj.new_block(Obj.object_tag, table.size); | |
/* XXX Appel de [caml_modify] | Call to [caml_modify] */ | |
Obj.set_field(obj, 0, Obj.repr(table.methods)); | |
Obj.obj(set_id(obj)); | |
}; | |
let create_object_opt = (obj_0, table) => | |
if ((Obj.magic(obj_0): bool)) { | |
obj_0; | |
} else { | |
/* XXX Appel de [obj_block] | Call to [obj_block] */ | |
let obj = Obj.new_block(Obj.object_tag, table.size); | |
/* XXX Appel de [caml_modify] | Call to [caml_modify] */ | |
Obj.set_field(obj, 0, Obj.repr(table.methods)); | |
Obj.obj(set_id(obj)); | |
}; | |
let rec iter_f = obj => | |
fun | |
| [] => () | |
| [f, ...l] => { | |
f(obj); | |
iter_f(obj, l); | |
}; | |
let run_initializers = (obj, table) => { | |
let inits = table.initializers; | |
if (inits != []) { | |
iter_f(obj, inits); | |
}; | |
}; | |
let run_initializers_opt = (obj_0, obj, table) => | |
if ((Obj.magic(obj_0): bool)) { | |
obj; | |
} else { | |
let inits = table.initializers; | |
if (inits != []) { | |
iter_f(obj, inits); | |
}; | |
obj; | |
}; | |
let create_object_and_run_initializers = (obj_0, table) => | |
if ((Obj.magic(obj_0): bool)) { | |
obj_0; | |
} else { | |
let obj = create_object(table); | |
run_initializers(obj, table); | |
obj; | |
}; | |
/* Equivalent primitive below | |
let sendself obj lab = | |
(magic obj : (obj -> t) array array).(0).(lab) obj | |
*/ | |
external send: (obj, tag) => 'a = "%send"; | |
external sendcache: (obj, tag, t, int) => 'a = "%sendcache"; | |
external sendself: (obj, label) => 'a = "%sendself"; | |
[@noalloc] | |
external get_public_method: (obj, tag) => closure = "caml_get_public_method"; | |
/**** table collection access ****/ | |
type tbls = { | |
key: closure, | |
mutable data: tables, | |
mutable next: tables, | |
} | |
and tables = | |
| Empty | |
| Cons(tbls); | |
let set_data = (tables, v) => | |
switch (tables) { | |
| Empty => assert(false) | |
| Cons(tables) => tables.data = v | |
}; | |
let set_next = (tables, v) => | |
switch (tables) { | |
| Empty => assert(false) | |
| Cons(tables) => tables.next = v | |
}; | |
let get_key = | |
fun | |
| Empty => assert(false) | |
| Cons(tables) => tables.key; | |
let get_data = | |
fun | |
| Empty => assert(false) | |
| Cons(tables) => tables.data; | |
let get_next = | |
fun | |
| Empty => assert(false) | |
| Cons(tables) => tables.next; | |
let build_path = (n, keys, tables) => { | |
let res = Cons({key: Obj.magic(0), data: Empty, next: Empty}); | |
let r = ref(res); | |
for (i in 0 to n) { | |
r := Cons({key: keys[i], data: r^, next: Empty}); | |
}; | |
set_data(tables, r^); | |
res; | |
}; | |
let rec lookup_keys = (i, keys, tables) => | |
if (i < 0) { | |
tables; | |
} else { | |
let key = keys[i]; | |
let rec lookup_key = (tables: tables) => | |
if (get_key(tables) === key) { | |
switch (get_data(tables)) { | |
| Empty => assert(false) | |
| Cons(_) as tables_data => lookup_keys(i - 1, keys, tables_data) | |
}; | |
} else { | |
switch (get_next(tables)) { | |
| Cons(_) as next => lookup_key(next) | |
| Empty => | |
let next: tables = Cons({key, data: Empty, next: Empty}); | |
set_next(tables, next); | |
build_path(i - 1, keys, next); | |
}; | |
}; | |
lookup_key(tables); | |
}; | |
let lookup_tables = (root, keys) => | |
switch (get_data(root)) { | |
| Cons(_) as root_data => | |
lookup_keys(Array.length(keys) - 1, keys, root_data) | |
| Empty => build_path(Array.length(keys) - 1, keys, root) | |
}; | |
/**** builtin methods ****/ | |
let get_const = x => ret(_obj => x); | |
let get_var = n => ret(obj => Array.unsafe_get(obj, n)); | |
let get_env = (e, n) => | |
ret(obj => | |
Array.unsafe_get(Obj.magic(Array.unsafe_get(obj, e)): obj, n) | |
); | |
let get_meth = n => ret(obj => sendself(obj, n)); | |
let set_var = n => ret((obj, x) => Array.unsafe_set(obj, n, x)); | |
let app_const = (f, x) => ret(_obj => f(x)); | |
let app_var = (f, n) => ret(obj => f(Array.unsafe_get(obj, n))); | |
let app_env = (f, e, n) => | |
ret(obj => | |
f(Array.unsafe_get(Obj.magic(Array.unsafe_get(obj, e)): obj, n)) | |
); | |
let app_meth = (f, n) => ret(obj => f(sendself(obj, n))); | |
let app_const_const = (f, x, y) => ret(_obj => f(x, y)); | |
let app_const_var = (f, x, n) => | |
ret(obj => f(x, Array.unsafe_get(obj, n))); | |
let app_const_meth = (f, x, n) => ret(obj => f(x, sendself(obj, n))); | |
let app_var_const = (f, n, x) => | |
ret(obj => f(Array.unsafe_get(obj, n), x)); | |
let app_meth_const = (f, n, x) => ret(obj => f(sendself(obj, n), x)); | |
let app_const_env = (f, x, e, n) => | |
ret(obj => | |
f(x, Array.unsafe_get(Obj.magic(Array.unsafe_get(obj, e)): obj, n)) | |
); | |
let app_env_const = (f, e, n, x) => | |
ret(obj => | |
f(Array.unsafe_get(Obj.magic(Array.unsafe_get(obj, e)): obj, n), x) | |
); | |
let meth_app_const = (n, x) => ret(obj => (sendself(obj, n): _ => _)(x)); | |
let meth_app_var = (n, m) => | |
ret(obj => (sendself(obj, n): _ => _)(Array.unsafe_get(obj, m))); | |
let meth_app_env = (n, e, m) => | |
ret(obj => | |
(sendself(obj, n): _ => _)( | |
Array.unsafe_get(Obj.magic(Array.unsafe_get(obj, e)): obj, m), | |
) | |
); | |
let meth_app_meth = (n, m) => | |
ret(obj => (sendself(obj, n): _ => _)(sendself(obj, m))); | |
let send_const = (m, x, c) => | |
ret(obj => sendcache(x, m, Array.unsafe_get(obj, 0), c)); | |
let send_var = (m, n, c) => | |
ret(obj => | |
sendcache( | |
Obj.magic(Array.unsafe_get(obj, n)): obj, | |
m, | |
Array.unsafe_get(obj, 0), | |
c, | |
) | |
); | |
let send_env = (m, e, n, c) => | |
ret(obj => | |
sendcache( | |
Obj.magic( | |
Array.unsafe_get(Obj.magic(Array.unsafe_get(obj, e)): obj, n), | |
): obj, | |
m, | |
Array.unsafe_get(obj, 0), | |
c, | |
) | |
); | |
let send_meth = (m, n, c) => | |
ret(obj => sendcache(sendself(obj, n), m, Array.unsafe_get(obj, 0), c)); | |
let new_cache = table => { | |
let n = new_method(table); | |
let n = | |
if (n mod 2 == 0 || n > 2 + magic(table.methods[1]) * 16 / Sys.word_size) { | |
n; | |
} else { | |
new_method(table); | |
}; | |
table.methods[n] = Obj.magic(0); | |
n; | |
}; | |
type impl = | |
| GetConst | |
| GetVar | |
| GetEnv | |
| GetMeth | |
| SetVar | |
| AppConst | |
| AppVar | |
| AppEnv | |
| AppMeth | |
| AppConstConst | |
| AppConstVar | |
| AppConstEnv | |
| AppConstMeth | |
| AppVarConst | |
| AppEnvConst | |
| AppMethConst | |
| MethAppConst | |
| MethAppVar | |
| MethAppEnv | |
| MethAppMeth | |
| SendConst | |
| SendVar | |
| SendEnv | |
| SendMeth | |
| Closure(closure); | |
let method_impl = (table, i, arr) => { | |
let next = () => { | |
incr(i); | |
magic(arr[i^]); | |
}; | |
switch (next()) { | |
| GetConst => | |
let x: t = next(); | |
get_const(x); | |
| GetVar => | |
let n = next(); | |
get_var(n); | |
| GetEnv => | |
let e = next(); | |
let n = next(); | |
get_env(e, n); | |
| GetMeth => | |
let n = next(); | |
get_meth(n); | |
| SetVar => | |
let n = next(); | |
set_var(n); | |
| AppConst => | |
let f = next(); | |
let x = next(); | |
app_const(f, x); | |
| AppVar => | |
let f = next(); | |
let n = next(); | |
app_var(f, n); | |
| AppEnv => | |
let f = next(); | |
let e = next(); | |
let n = next(); | |
app_env(f, e, n); | |
| AppMeth => | |
let f = next(); | |
let n = next(); | |
app_meth(f, n); | |
| AppConstConst => | |
let f = next(); | |
let x = next(); | |
let y = next(); | |
app_const_const(f, x, y); | |
| AppConstVar => | |
let f = next(); | |
let x = next(); | |
let n = next(); | |
app_const_var(f, x, n); | |
| AppConstEnv => | |
let f = next(); | |
let x = next(); | |
let e = next(); | |
let n = next(); | |
app_const_env(f, x, e, n); | |
| AppConstMeth => | |
let f = next(); | |
let x = next(); | |
let n = next(); | |
app_const_meth(f, x, n); | |
| AppVarConst => | |
let f = next(); | |
let n = next(); | |
let x = next(); | |
app_var_const(f, n, x); | |
| AppEnvConst => | |
let f = next(); | |
let e = next(); | |
let n = next(); | |
let x = next(); | |
app_env_const(f, e, n, x); | |
| AppMethConst => | |
let f = next(); | |
let n = next(); | |
let x = next(); | |
app_meth_const(f, n, x); | |
| MethAppConst => | |
let n = next(); | |
let x = next(); | |
meth_app_const(n, x); | |
| MethAppVar => | |
let n = next(); | |
let m = next(); | |
meth_app_var(n, m); | |
| MethAppEnv => | |
let n = next(); | |
let e = next(); | |
let m = next(); | |
meth_app_env(n, e, m); | |
| MethAppMeth => | |
let n = next(); | |
let m = next(); | |
meth_app_meth(n, m); | |
| SendConst => | |
let m = next(); | |
let x = next(); | |
send_const(m, x, new_cache(table)); | |
| SendVar => | |
let m = next(); | |
let n = next(); | |
send_var(m, n, new_cache(table)); | |
| SendEnv => | |
let m = next(); | |
let e = next(); | |
let n = next(); | |
send_env(m, e, n, new_cache(table)); | |
| SendMeth => | |
let m = next(); | |
let n = next(); | |
send_meth(m, n, new_cache(table)); | |
| Closure(_) as clo => magic(clo) | |
}; | |
}; | |
let set_methods = (table, methods) => { | |
let len = Array.length(methods); | |
let i = ref(0); | |
while (i^ < len) { | |
let label = methods[i^]; | |
let clo = method_impl(table, i, methods); | |
set_method(table, label, clo); | |
incr(i); | |
}; | |
}; | |
/**** Statistics ****/ | |
type stats = { | |
classes: int, | |
methods: int, | |
inst_vars: int, | |
}; | |
let stats = () => { | |
classes: table_count^, | |
methods: method_count^, | |
inst_vars: inst_var_count^, | |
}; | |
}; | |
/** Sets over ordered types. | |
This module implements the set data structure, given a total ordering | |
function over the set elements. All operations over sets | |
are purely applicative (no side-effects). | |
The implementation uses balanced binary trees, and is therefore | |
reasonably efficient: insertion and membership take time | |
logarithmic in the size of the set, for instance. | |
The {!Make} functor constructs implementations for any type, given a | |
[compare] function. | |
For instance: | |
{[ | |
module IntPairs = | |
struct | |
type t = int * int | |
let compare (x0,y0) (x1,y1) = | |
match Pervasives.compare x0 x1 with | |
0 -> Pervasives.compare y0 y1 | |
| c -> c | |
end | |
module PairsSet = Set.Make(IntPairs) | |
let m = PairsSet.(empty |> add (2,3) |> add (5,7) |> add (11,13)) | |
]} | |
This creates a new module [PairsSet], with a new type [PairsSet.t] | |
of sets of [int * int]. | |
*/; | |
/** Input signature of the functor {!Set.Make}. */ | |
module type OrderedType = { | |
/** The type of the set elements. */ | |
type t; | |
/** A total ordering function over the set elements. | |
This is a two-argument function [f] such that | |
[f e1 e2] is zero if the elements [e1] and [e2] are equal, | |
[f e1 e2] is strictly negative if [e1] is smaller than [e2], | |
and [f e1 e2] is strictly positive if [e1] is greater than [e2]. | |
Example: a suitable ordering function is the generic structural | |
comparison function {!Pervasives.compare}. */ | |
let compare: (t, t) => int; | |
}; | |
/** Output signature of the functor {!Set.Make}. */ | |
module type S = { | |
/** The type of the set elements. */ | |
type elt; | |
/** The type of sets. */ | |
type t; | |
/** The empty set. */ | |
let empty: t; | |
/** Test whether a set is empty or not. */ | |
let is_empty: t => bool; | |
/** [mem x s] tests whether [x] belongs to the set [s]. */ | |
let mem: (elt, t) => bool; | |
/** [add x s] returns a set containing all elements of [s], | |
plus [x]. If [x] was already in [s], [s] is returned unchanged | |
(the result of the function is then physically equal to [s]). | |
@before 4.03 Physical equality was not ensured. */ | |
let add: (elt, t) => t; | |
/** [singleton x] returns the one-element set containing only [x]. */ | |
let singleton: elt => t; | |
/** [remove x s] returns a set containing all elements of [s], | |
except [x]. If [x] was not in [s], [s] is returned unchanged | |
(the result of the function is then physically equal to [s]). | |
@before 4.03 Physical equality was not ensured. */ | |
let remove: (elt, t) => t; | |
/** Set union. */ | |
let union: (t, t) => t; | |
/** Set intersection. */ | |
let inter: (t, t) => t; | |
/** Set difference. */ | |
let diff: (t, t) => t; | |
/** Total ordering between sets. Can be used as the ordering function | |
for doing sets of sets. */ | |
let compare: (t, t) => int; | |
/** [equal s1 s2] tests whether the sets [s1] and [s2] are | |
equal, that is, contain equal elements. */ | |
let equal: (t, t) => bool; | |
/** [subset s1 s2] tests whether the set [s1] is a subset of | |
the set [s2]. */ | |
let subset: (t, t) => bool; | |
/** [iter f s] applies [f] in turn to all elements of [s]. | |
The elements of [s] are presented to [f] in increasing order | |
with respect to the ordering over the type of the elements. */ | |
let iter: (elt => unit, t) => unit; | |
/** [map f s] is the set whose elements are [f a0],[f a1]... [f | |
aN], where [a0],[a1]...[aN] are the elements of [s]. | |
The elements are passed to [f] in increasing order | |
with respect to the ordering over the type of the elements. | |
If no element of [s] is changed by [f], [s] is returned | |
unchanged. (If each output of [f] is physically equal to its | |
input, the returned set is physically equal to [s].) | |
@since 4.04.0 */ | |
let map: (elt => elt, t) => t; | |
/** [fold f s a] computes [(f xN ... (f x2 (f x1 a))...)], | |
where [x1 ... xN] are the elements of [s], in increasing order. */ | |
let fold: ((elt, 'a) => 'a, t, 'a) => 'a; | |
/** [for_all p s] checks if all elements of the set | |
satisfy the predicate [p]. */ | |
let for_all: (elt => bool, t) => bool; | |
/** [exists p s] checks if at least one element of | |
the set satisfies the predicate [p]. */ | |
let exists: (elt => bool, t) => bool; | |
/** [filter p s] returns the set of all elements in [s] | |
that satisfy predicate [p]. If [p] satisfies every element in [s], | |
[s] is returned unchanged (the result of the function is then | |
physically equal to [s]). | |
@before 4.03 Physical equality was not ensured.*/ | |
let filter: (elt => bool, t) => t; | |
/** [partition p s] returns a pair of sets [(s1, s2)], where | |
[s1] is the set of all the elements of [s] that satisfy the | |
predicate [p], and [s2] is the set of all the elements of | |
[s] that do not satisfy [p]. */ | |
let partition: (elt => bool, t) => (t, t); | |
/** Return the number of elements of a set. */ | |
let cardinal: t => int; | |
/** Return the list of all elements of the given set. | |
The returned list is sorted in increasing order with respect | |
to the ordering [Ord.compare], where [Ord] is the argument | |
given to {!Set.Make}. */ | |
let elements: t => list(elt); | |
/** Return the smallest element of the given set | |
(with respect to the [Ord.compare] ordering), or raise | |
[Not_found] if the set is empty. */ | |
let min_elt: t => elt; | |
/** Return the smallest element of the given set | |
(with respect to the [Ord.compare] ordering), or [None] | |
if the set is empty. | |
@since 4.05 | |
*/ | |
let min_elt_opt: t => option(elt); | |
/** Same as {!Set.S.min_elt}, but returns the largest element of the | |
given set. */ | |
let max_elt: t => elt; | |
/** Same as {!Set.S.min_elt_opt}, but returns the largest element of the | |
given set. | |
@since 4.05 | |
*/ | |
let max_elt_opt: t => option(elt); | |
/** Return one element of the given set, or raise [Not_found] if | |
the set is empty. Which element is chosen is unspecified, | |
but equal elements will be chosen for equal sets. */ | |
let choose: t => elt; | |
/** Return one element of the given set, or [None] if | |
the set is empty. Which element is chosen is unspecified, | |
but equal elements will be chosen for equal sets. | |
@since 4.05 | |
*/ | |
let choose_opt: t => option(elt); | |
/** [split x s] returns a triple [(l, present, r)], where | |
[l] is the set of elements of [s] that are | |
strictly less than [x]; | |
[r] is the set of elements of [s] that are | |
strictly greater than [x]; | |
[present] is [false] if [s] contains no element equal to [x], | |
or [true] if [s] contains an element equal to [x]. */ | |
let split: (elt, t) => (t, bool, t); | |
/** [find x s] returns the element of [s] equal to [x] (according | |
to [Ord.compare]), or raise [Not_found] if no such element | |
exists. | |
@since 4.01.0 */ | |
let find: (elt, t) => elt; | |
/** [find_opt x s] returns the element of [s] equal to [x] (according | |
to [Ord.compare]), or [None] if no such element | |
exists. | |
@since 4.05 */ | |
let find_opt: (elt, t) => option(elt); | |
/** [find_first f s], where [f] is a monotonically increasing function, | |
returns the lowest element [e] of [s] such that [f e], | |
or raises [Not_found] if no such element exists. | |
For example, [find_first (fun e -> Ord.compare e x >= 0) s] will return | |
the first element [e] of [s] where [Ord.compare e x >= 0] (intuitively: | |
[e >= x]), or raise [Not_found] if [x] is greater than any element of | |
[s]. | |
@since 4.05 | |
*/ | |
let find_first: (elt => bool, t) => elt; | |
/** [find_first_opt f s], where [f] is a monotonically increasing function, | |
returns an option containing the lowest element [e] of [s] such that | |
[f e], or [None] if no such element exists. | |
@since 4.05 | |
*/ | |
let find_first_opt: (elt => bool, t) => option(elt); | |
/** [find_last f s], where [f] is a monotonically decreasing function, | |
returns the highest element [e] of [s] such that [f e], | |
or raises [Not_found] if no such element exists. | |
@since 4.05 | |
*/ | |
let find_last: (elt => bool, t) => elt; | |
/** [find_last_opt f s], where [f] is a monotonically decreasing function, | |
returns an option containing the highest element [e] of [s] such that | |
[f e], or [None] if no such element exists. | |
@since 4.05 | |
*/ | |
let find_last_opt: (elt => bool, t) => option(elt); | |
/** [of_list l] creates a set from a list of elements. | |
This is usually more efficient than folding [add] over the list, | |
except perhaps for lists with many duplicated elements. | |
@since 4.02.0 */ | |
let of_list: list(elt) => t; | |
}; | |
module Make = (Ord: OrderedType) : (S with type elt = Ord.t) => { | |
type elt = Ord.t; | |
type rc = { | |
l: t, | |
v: elt, | |
r: t, | |
h: int, | |
} | |
and t = | |
| Empty | |
| Node(rc); | |
let height = | |
fun | |
| Empty => 0 | |
| Node({h, _}) => h; | |
let create = (l, v, r) => { | |
let hl = | |
switch (l) { | |
| Empty => 0 | |
| Node({h, _}) => h | |
}; | |
let hr = | |
switch (r) { | |
| Empty => 0 | |
| Node({h, _}) => h | |
}; | |
Node({ | |
l, | |
v, | |
r, | |
h: | |
if (hl >= hr) { | |
hl + 1; | |
} else { | |
hr + 1; | |
}, | |
}); | |
}; | |
let bal = (l, v, r) => { | |
let hl = | |
switch (l) { | |
| Empty => 0 | |
| Node({h, _}) => h | |
}; | |
let hr = | |
switch (r) { | |
| Empty => 0 | |
| Node({h, _}) => h | |
}; | |
if (hl > hr + 2) { | |
switch (l) { | |
| Empty => invalid_arg("Set.bal") | |
| Node({l: ll, v: lv, r: lr, _}) => | |
if (height(ll) >= height(lr)) { | |
create(ll, lv, create(lr, v, r)); | |
} else { | |
switch (lr) { | |
| Empty => invalid_arg("Set.bal") | |
| Node({l: lrl, v: lrv, r: lrr, _}) => | |
create(create(ll, lv, lrl), lrv, create(lrr, v, r)) | |
}; | |
} | |
}; | |
} else if (hr > hl + 2) { | |
switch (r) { | |
| Empty => invalid_arg("Set.bal") | |
| Node({l: rl, v: rv, r: rr, _}) => | |
if (height(rr) >= height(rl)) { | |
create(create(l, v, rl), rv, rr); | |
} else { | |
switch (rl) { | |
| Empty => invalid_arg("Set.bal") | |
| Node({l: rll, v: rlv, r: rlr, _}) => | |
create(create(l, v, rll), rlv, create(rlr, rv, rr)) | |
}; | |
} | |
}; | |
} else { | |
Node({ | |
l, | |
v, | |
r, | |
h: | |
if (hl >= hr) { | |
hl + 1; | |
} else { | |
hr + 1; | |
}, | |
}); | |
}; | |
}; | |
let rec add = x => | |
fun | |
| Empty => Node({l: Empty, v: x, r: Empty, h: 1}) | |
| Node({l, v, r, _}) as t => { | |
let c = Ord.compare(x, v); | |
if (c == 0) { | |
t; | |
} else if (c < 0) { | |
let ll = add(x, l); | |
if (l === ll) { | |
t; | |
} else { | |
bal(ll, v, r); | |
}; | |
} else { | |
let rr = add(x, r); | |
if (r === rr) { | |
t; | |
} else { | |
bal(l, v, rr); | |
}; | |
}; | |
}; | |
let singleton = x => Node({l: Empty, v: x, r: Empty, h: 1}); | |
let rec add_min_element = x => | |
fun | |
| Empty => singleton(x) | |
| Node({l, v, r, _}) => bal(add_min_element(x, l), v, r); | |
let rec add_max_element = x => | |
fun | |
| Empty => singleton(x) | |
| Node({l, v, r, _}) => bal(l, v, add_max_element(x, r)); | |
let rec join = (l, v, r) => | |
switch (l, r) { | |
| (Empty, _) => add_min_element(v, r) | |
| (_, Empty) => add_max_element(v, l) | |
| ( | |
Node({l: ll, v: lv, r: lr, h: lh}), | |
Node({l: rl, v: rv, r: rr, h: rh}), | |
) => | |
if (lh > rh + 2) { | |
bal(ll, lv, join(lr, v, r)); | |
} else if (rh > lh + 2) { | |
bal(join(l, v, rl), rv, rr); | |
} else { | |
create(l, v, r); | |
} | |
}; | |
let rec min_elt = | |
fun | |
| Empty => raise(Not_found) | |
| Node({l: Empty, v, _}) => v | |
| Node({l, _}) => min_elt(l); | |
let rec min_elt_opt = | |
fun | |
| Empty => None | |
| Node({l: Empty, v, _}) => Some(v) | |
| Node({l, _}) => min_elt_opt(l); | |
let rec max_elt = | |
fun | |
| Empty => raise(Not_found) | |
| Node({v, r: Empty, _}) => v | |
| Node({r, _}) => max_elt(r); | |
let rec max_elt_opt = | |
fun | |
| Empty => None | |
| Node({v, r: Empty, _}) => Some(v) | |
| Node({r, _}) => max_elt_opt(r); | |
let rec remove_min_elt = | |
fun | |
| Empty => invalid_arg("Set.remove_min_elt") | |
| Node({l: Empty, r, _}) => r | |
| Node({l, v, r, _}) => bal(remove_min_elt(l), v, r); | |
let merge = (t1, t2) => | |
switch (t1, t2) { | |
| (Empty, t) => t | |
| (t, Empty) => t | |
| (Node(_), Node(_)) => bal(t1, min_elt(t2), remove_min_elt(t2)) | |
}; | |
let concat = (t1, t2) => | |
switch (t1, t2) { | |
| (Empty, t) => t | |
| (t, Empty) => t | |
| (Node(_), Node(_)) => join(t1, min_elt(t2), remove_min_elt(t2)) | |
}; | |
let rec split = x => | |
fun | |
| Empty => (Empty, false, Empty) | |
| Node({l, v, r, _}) => { | |
let c = Ord.compare(x, v); | |
if (c == 0) { | |
(l, true, r); | |
} else if (c < 0) { | |
let (ll, pres, rl) = split(x, l); | |
(ll, pres, join(rl, v, r)); | |
} else { | |
let (lr, pres, rr) = split(x, r); | |
(join(l, v, lr), pres, rr); | |
}; | |
}; | |
let empty = Empty; | |
let is_empty = | |
fun | |
| Empty => true | |
| Node(_) => false; | |
let rec mem = x => | |
fun | |
| Empty => false | |
| Node({l, v, r, _}) => { | |
let c = Ord.compare(x, v); | |
c == 0 | |
|| mem( | |
x, | |
if (c < 0) { | |
l; | |
} else { | |
r; | |
}, | |
); | |
}; | |
let rec remove = x => | |
fun | |
| Empty => Empty | |
| Node({l, v, r, _}) as t => { | |
let c = Ord.compare(x, v); | |
if (c == 0) { | |
merge(l, r); | |
} else if (c < 0) { | |
let ll = remove(x, l); | |
if (l === ll) { | |
t; | |
} else { | |
bal(ll, v, r); | |
}; | |
} else { | |
let rr = remove(x, r); | |
if (r === rr) { | |
t; | |
} else { | |
bal(l, v, rr); | |
}; | |
}; | |
}; | |
let rec union = (s1, s2) => | |
switch (s1, s2) { | |
| (Empty, t2) => t2 | |
| (t1, Empty) => t1 | |
| ( | |
Node({l: l1, v: v1, r: r1, h: h1}), | |
Node({l: l2, v: v2, r: r2, h: h2}), | |
) => | |
if (h1 >= h2) { | |
if (h2 == 1) { | |
add(v2, s1); | |
} else { | |
let (l2, _, r2) = split(v1, s2); | |
join(union(l1, l2), v1, union(r1, r2)); | |
}; | |
} else if (h1 == 1) { | |
add(v1, s2); | |
} else { | |
let (l1, _, r1) = split(v2, s1); | |
join(union(l1, l2), v2, union(r1, r2)); | |
} | |
}; | |
let rec inter = (s1, s2) => | |
switch (s1, s2) { | |
| (Empty, _) => Empty | |
| (_, Empty) => Empty | |
| (Node({l: l1, v: v1, r: r1, _}), t2) => | |
switch (split(v1, t2)) { | |
| (l2, false, r2) => concat(inter(l1, l2), inter(r1, r2)) | |
| (l2, true, r2) => join(inter(l1, l2), v1, inter(r1, r2)) | |
} | |
}; | |
let rec diff = (s1, s2) => | |
switch (s1, s2) { | |
| (Empty, _) => Empty | |
| (t1, Empty) => t1 | |
| (Node({l: l1, v: v1, r: r1, _}), t2) => | |
switch (split(v1, t2)) { | |
| (l2, false, r2) => join(diff(l1, l2), v1, diff(r1, r2)) | |
| (l2, true, r2) => concat(diff(l1, l2), diff(r1, r2)) | |
} | |
}; | |
type enumeration = | |
| End | |
| More(elt, t, enumeration); | |
let rec cons_enum = (s, e) => | |
switch (s) { | |
| Empty => e | |
| Node({l, v, r, _}) => cons_enum(l, [@implicit_arity] More(v, r, e)) | |
}; | |
let rec compare_aux = (e1, e2) => | |
switch (e1, e2) { | |
| (End, End) => 0 | |
| (End, _) => (-1) | |
| (_, End) => 1 | |
| ( | |
[@implicit_arity] More(v1, r1, e1), | |
[@implicit_arity] More(v2, r2, e2), | |
) => | |
let c = Ord.compare(v1, v2); | |
if (c != 0) { | |
c; | |
} else { | |
compare_aux(cons_enum(r1, e1), cons_enum(r2, e2)); | |
}; | |
}; | |
let compare = (s1, s2) => | |
compare_aux(cons_enum(s1, End), cons_enum(s2, End)); | |
let equal = (s1, s2) => compare(s1, s2) == 0; | |
let rec subset = (s1, s2) => | |
switch (s1, s2) { | |
| (Empty, _) => true | |
| (_, Empty) => false | |
| (Node({l: l1, v: v1, r: r1, _}), Node({l: l2, v: v2, r: r2, _}) as t2) => | |
let c = Ord.compare(v1, v2); | |
if (c == 0) { | |
subset(l1, l2) && subset(r1, r2); | |
} else if (c < 0) { | |
subset(Node({l: l1, v: v1, r: Empty, h: 0}), l2) && subset(r1, t2); | |
} else { | |
subset(Node({l: Empty, v: v1, r: r1, h: 0}), r2) && subset(l1, t2); | |
}; | |
}; | |
let rec iter = f => | |
fun | |
| Empty => () | |
| Node({l, v, r, _}) => { | |
iter(f, l); | |
f(v); | |
iter(f, r); | |
}; | |
let rec fold = (f, s, accu) => | |
switch (s) { | |
| Empty => accu | |
| Node({l, v, r, _}) => fold(f, r, f(v, fold(f, l, accu))) | |
}; | |
let rec for_all = p => | |
fun | |
| Empty => true | |
| Node({l, v, r, _}) => p(v) && for_all(p, l) && for_all(p, r); | |
let rec exists = p => | |
fun | |
| Empty => false | |
| Node({l, v, r, _}) => p(v) || exists(p, l) || exists(p, r); | |
let rec filter = p => | |
fun | |
| Empty => Empty | |
| Node({l, v, r, _}) as t => { | |
let l' = filter(p, l); | |
let pv = p(v); | |
let r' = filter(p, r); | |
if (pv) { | |
if (l === l' && r === r') { | |
t; | |
} else { | |
join(l', v, r'); | |
}; | |
} else { | |
concat(l', r'); | |
}; | |
}; | |
let rec partition = p => | |
fun | |
| Empty => (Empty, Empty) | |
| Node({l, v, r, _}) => { | |
let (lt, lf) = partition(p, l); | |
let pv = p(v); | |
let (rt, rf) = partition(p, r); | |
if (pv) { | |
(join(lt, v, rt), concat(lf, rf)); | |
} else { | |
(concat(lt, rt), join(lf, v, rf)); | |
}; | |
}; | |
let rec cardinal = | |
fun | |
| Empty => 0 | |
| Node({l, r, _}) => cardinal(l) + 1 + cardinal(r); | |
let rec elements_aux = accu => | |
fun | |
| Empty => accu | |
| Node({l, v, r, _}) => elements_aux([v, ...elements_aux(accu, r)], l); | |
let elements = s => elements_aux([], s); | |
let choose = min_elt; | |
let choose_opt = min_elt_opt; | |
let rec find = x => | |
fun | |
| Empty => raise(Not_found) | |
| Node({l, v, r, _}) => { | |
let c = Ord.compare(x, v); | |
if (c == 0) { | |
v; | |
} else { | |
find( | |
x, | |
if (c < 0) { | |
l; | |
} else { | |
r; | |
}, | |
); | |
}; | |
}; | |
let rec find_first_aux = (v0, f) => | |
fun | |
| Empty => v0 | |
| Node({l, v, r, _}) => | |
if (f(v)) { | |
find_first_aux(v, f, l); | |
} else { | |
find_first_aux(v0, f, r); | |
}; | |
let rec find_first = f => | |
fun | |
| Empty => raise(Not_found) | |
| Node({l, v, r, _}) => | |
if (f(v)) { | |
find_first_aux(v, f, l); | |
} else { | |
find_first(f, r); | |
}; | |
let rec find_first_opt_aux = (v0, f) => | |
fun | |
| Empty => Some(v0) | |
| Node({l, v, r, _}) => | |
if (f(v)) { | |
find_first_opt_aux(v, f, l); | |
} else { | |
find_first_opt_aux(v0, f, r); | |
}; | |
let rec find_first_opt = f => | |
fun | |
| Empty => None | |
| Node({l, v, r, _}) => | |
if (f(v)) { | |
find_first_opt_aux(v, f, l); | |
} else { | |
find_first_opt(f, r); | |
}; | |
let rec find_last_aux = (v0, f) => | |
fun | |
| Empty => v0 | |
| Node({l, v, r, _}) => | |
if (f(v)) { | |
find_last_aux(v, f, r); | |
} else { | |
find_last_aux(v0, f, l); | |
}; | |
let rec find_last = f => | |
fun | |
| Empty => raise(Not_found) | |
| Node({l, v, r, _}) => | |
if (f(v)) { | |
find_last_aux(v, f, r); | |
} else { | |
find_last(f, l); | |
}; | |
let rec find_last_opt_aux = (v0, f) => | |
fun | |
| Empty => Some(v0) | |
| Node({l, v, r, _}) => | |
if (f(v)) { | |
find_last_opt_aux(v, f, r); | |
} else { | |
find_last_opt_aux(v0, f, l); | |
}; | |
let rec find_last_opt = f => | |
fun | |
| Empty => None | |
| Node({l, v, r, _}) => | |
if (f(v)) { | |
find_last_opt_aux(v, f, r); | |
} else { | |
find_last_opt(f, l); | |
}; | |
let rec find_opt = x => | |
fun | |
| Empty => None | |
| Node({l, v, r, _}) => { | |
let c = Ord.compare(x, v); | |
if (c == 0) { | |
Some(v); | |
} else { | |
find_opt( | |
x, | |
if (c < 0) { | |
l; | |
} else { | |
r; | |
}, | |
); | |
}; | |
}; | |
let try_join = (l, v, r) => | |
if ((l == Empty || Ord.compare(max_elt(l), v) < 0) | |
&& (r == Empty || Ord.compare(v, min_elt(r)) < 0)) { | |
join(l, v, r); | |
} else { | |
union(l, add(v, r)); | |
}; | |
let rec map = f => | |
fun | |
| Empty => Empty | |
| Node({l, v, r, _}) as t => { | |
let l' = map(f, l); | |
let v' = f(v); | |
let r' = map(f, r); | |
if (l === l' && v === v' && r === r') { | |
t; | |
} else { | |
try_join(l', v', r'); | |
}; | |
}; | |
let of_sorted_list = l => { | |
let rec sub = (n, l) => | |
switch (n, l) { | |
| (0, l) => (Empty, l) | |
| (1, [x0, ...l]) => (Node({l: Empty, v: x0, r: Empty, h: 1}), l) | |
| (2, [x0, x1, ...l]) => ( | |
Node({ | |
l: Node({l: Empty, v: x0, r: Empty, h: 1}), | |
v: x1, | |
r: Empty, | |
h: 2, | |
}), | |
l, | |
) | |
| (3, [x0, x1, x2, ...l]) => ( | |
Node({ | |
l: Node({l: Empty, v: x0, r: Empty, h: 1}), | |
v: x1, | |
r: Node({l: Empty, v: x2, r: Empty, h: 1}), | |
h: 2, | |
}), | |
l, | |
) | |
| (n, l) => | |
let nl = n / 2; | |
let (left, l) = sub(nl, l); | |
switch (l) { | |
| [] => assert(false) | |
| [mid, ...l] => | |
let (right, l) = sub(n - nl - 1, l); | |
(create(left, mid, right), l); | |
}; | |
}; | |
fst(sub(List.length(l), l)); | |
}; | |
let of_list = l => | |
switch (l) { | |
| [] => empty | |
| [x0] => singleton(x0) | |
| [x0, x1] => add(x1, singleton(x0)) | |
| [x0, x1, x2] => add(x2, add(x1, singleton(x0))) | |
| [x0, x1, x2, x3] => add(x3, add(x2, add(x1, singleton(x0)))) | |
| [x0, x1, x2, x3, x4] => | |
add(x4, add(x3, add(x2, add(x1, singleton(x0))))) | |
| _ => of_sorted_list(List.sort_uniq(Ord.compare, l)) | |
}; | |
}; | |
module type STACK = { | |
/** The type of stacks containing elements of type ['a]. */ | |
type t('a); | |
/** Raised when {!Stack.pop} or {!Stack.top} is applied to an empty stack. */ | |
exception Empty; | |
/** Return a new stack, initially empty. */ | |
let create: unit => t('a); | |
/** [push x s] adds the element [x] at the top of stack [s]. */ | |
let push: ('a, t('a)) => unit; | |
/** [pop s] removes and returns the topmost element in stack [s], | |
or raises {!Empty} if the stack is empty. */ | |
let pop: t('a) => 'a; | |
/** [top s] returns the topmost element in stack [s], | |
or raises {!Empty} if the stack is empty. */ | |
let top: t('a) => 'a; | |
/** Discard all elements from a stack. */ | |
let clear: t('a) => unit; | |
/** Return a copy of the given stack. */ | |
let copy: t('a) => t('a); | |
/** Return [true] if the given stack is empty, [false] otherwise. */ | |
let is_empty: t('a) => bool; | |
/** Return the number of elements in a stack. Time complexity O(1) */ | |
let length: t('a) => int; | |
/** [iter f s] applies [f] in turn to all elements of [s], | |
from the element at the top of the stack to the element at the | |
bottom of the stack. The stack itself is unchanged. */ | |
let iter: ('a => unit, t('a)) => unit; | |
/** [fold f accu s] is [(f (... (f (f accu x1) x2) ...) xn)] | |
where [x1] is the top of the stack, [x2] the second element, | |
and [xn] the bottom element. The stack is unchanged. | |
@since 4.03 */ | |
let fold: (('b, 'a) => 'b, 'b, t('a)) => 'b; | |
}; | |
module Stack: STACK = { | |
type t('a) = { | |
mutable c: list('a), | |
mutable len: int, | |
}; | |
exception Empty; | |
let create = () => {c: [], len: 0}; | |
let clear = s => { | |
s.c = []; | |
s.len = 0; | |
}; | |
let copy = s => {c: s.c, len: s.len}; | |
let push = (x, s) => { | |
s.c = [x, ...s.c]; | |
s.len = s.len + 1; | |
}; | |
let pop = s => | |
switch (s.c) { | |
| [hd, ...tl] => | |
s.c = tl; | |
s.len = s.len - 1; | |
hd; | |
| [] => raise(Empty) | |
}; | |
let top = s => | |
switch (s.c) { | |
| [hd, ..._] => hd | |
| [] => raise(Empty) | |
}; | |
let is_empty = s => s.c == []; | |
let length = s => s.len; | |
let iter = (f, s) => List.iter(f, s.c); | |
let fold = (f, acc, s) => List.fold_left(f, acc, s.c); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment