diff --git a/docs/Manual.html b/docs/Manual.html
index b1bfc4b3d7..8d04a1b833 100644
--- a/docs/Manual.html
+++ b/docs/Manual.html
@@ -679,6 +679,7 @@
A real world example of using bsb
Build using Make
+Customize rules (generators support, @since 1.7.4)
FAQ
@@ -5086,6 +5087,61 @@ Build
Now in your working directory, type watchman -j < build.json
and enjoy the lightning build speed.
+
+
Customize rules (generators support, @since 1.7.4)
+
+
It is quite common that programmers use some pre-processors to generate some bolierpolate code during developement.
+
+
+
Note pre-processors can be classified as two categories, one is system-dependent which should be delayed until running on user machines, the other is system-indepdent , lex, yacc, m4, re2c, etc, which could be executed anytime.
+
+
+
BuckleScript has built in support for conditional compilation, this section is about the second part, since it is system-indepdent, we ask users to always generate such code and check in before shipping, this would help cut the dependencies for end users.
+
+
+
A typical example would be like this
+
+
+
Bsb using ocamlyacc
+
+
{
+ "generators" : [
+ { "name" : "ocamlyacc" ,
+ "command" : "ocamlyacc $in" }
+ ],
+ ...,
+ "sources" : {
+ "dir" : "src",
+ "generators" : [
+ {
+ "name" : "ocamlyacc",
+ "edge" : ["test.ml", "test.mli", ":", "test.mly"]
+ }
+ ]
+ }
+}
+
+
+
+
Note ocamlyacc
will generate in test.ml
and test.mli
in the same directory with test.mly
, user should check in generated file since then users would not need run ocamlyacc again, this would apply to menhir
as well.
+
+
+
When users are developing current project, bsb
will track the dependencies between test.ml
and test.mly
properly, when released
+as a package, bsb
will cut such dependency, so that users will
+only need the generated test.ml
, to help test such behavior in development mode, users could set it manually
+
+
+
+
{
+ ...,
+ "cut-generators" : true
+}
+
+
+
+
Then bsb
will not re-generate test.ml
whenever test.mly
changes.
+
+
diff --git a/docs/docson/build-schema.json b/docs/docson/build-schema.json
index 84d440727b..c417226871 100644
--- a/docs/docson/build-schema.json
+++ b/docs/docson/build-schema.json
@@ -303,6 +303,10 @@
},
"description": "(WIP) Pre defined rules"
},
+ "cut-generators" : {
+ "type": "boolean",
+ "description": "Ignore generators, cut the dependency on generator tools"
+ },
"reason": {
"$ref": "#/definitions/reason-specs",
"description": "BuckleScript comes with [Reason](http://facebook.github.io/reason/) by default. Specific configurations here."
diff --git a/jscomp/Makefile b/jscomp/Makefile
index 81920c4e0a..f471e57edf 100644
--- a/jscomp/Makefile
+++ b/jscomp/Makefile
@@ -207,6 +207,7 @@ EXT_SRCS = ext_util\
ext_sexp\
ext_json_types\
ext_json_parse\
+ ext_json_write\
ext_json\
ident_hash_set\
hash_set_poly\
diff --git a/jscomp/all.depend b/jscomp/all.depend
index 727cce921a..8f70c3f425 100644
--- a/jscomp/all.depend
+++ b/jscomp/all.depend
@@ -76,8 +76,10 @@ ext/ext_sexp.cmx : ext/ext_sexp.cmi
ext/ext_json_types.cmx : ext/string_map.cmx
ext/ext_json_parse.cmx : ext/string_map.cmx ext/ext_position.cmx \
ext/ext_json_types.cmx ext/ext_array.cmx ext/ext_json_parse.cmi
+ext/ext_json_write.cmx : ext/string_map.cmx ext/ext_json_types.cmx \
+ ext/ext_json_write.cmi
ext/ext_json.cmx : ext/string_map.cmx ext/ext_json_types.cmx \
- ext/ext_json.cmi
+ ext/ext_array.cmx ext/ext_json.cmi
ext/ident_hash_set.cmx : ext/hash_set_gen.cmx ext/ext_ident.cmx \
stubs/bs_hash_stubs.cmx ext/ident_hash_set.cmi
ext/hash_set_poly.cmx : ext/hash_set_gen.cmx ext/hash_set_poly.cmi
@@ -138,6 +140,7 @@ ext/ext_pp_scope.cmi : ext/ident_set.cmi
ext/ext_io.cmi :
ext/ext_sexp.cmi :
ext/ext_json_parse.cmi : ext/ext_json_types.cmx
+ext/ext_json_write.cmi : ext/ext_json_types.cmx
ext/ext_json.cmi : ext/string_map.cmi ext/ext_position.cmi \
ext/ext_json_types.cmx
ext/ident_hash_set.cmi : ext/hash_set_gen.cmx
@@ -154,8 +157,8 @@ common/bs_warnings.cmx : ext/literals.cmx common/js_config.cmx \
common/bs_warnings.cmi
common/lam_methname.cmx : ext/string_hash_set.cmx ext/ext_string.cmx \
common/lam_methname.cmi
-common/binary_cache.cmx : ext/string_map.cmx ext/ext_filename.cmx \
- common/binary_cache.cmi
+common/binary_cache.cmx : ext/string_map.cmx ext/ext_string.cmx \
+ ext/ext_filename.cmx common/binary_cache.cmi
common/bs_version.cmi :
common/js_config.cmi :
common/ext_log.cmi :
@@ -655,7 +658,8 @@ ounit_tests/ounit_scc_tests.cmx : ext/string_hashtbl.cmx ounit/oUnit.cmx \
ext/int_vec_vec.cmx ext/int_vec.cmx ext/ext_string.cmx ext/ext_scc.cmx
ounit_tests/ounit_hashtbl_tests.cmx : ext/string_hashtbl.cmx ounit/oUnit.cmx
ounit_tests/ounit_json_tests.cmx : ext/string_map.cmx ounit/oUnit.cmx \
- ext/ext_json_types.cmx ext/ext_json_parse.cmx ext/ext_json.cmx
+ ext/ext_pervasives.cmx ext/ext_json_write.cmx ext/ext_json_types.cmx \
+ ext/ext_json_parse.cmx ext/ext_json.cmx
ounit_tests/ounit_map_tests.cmx : ounit/oUnit.cmx ext/int_map.cmx
ounit_tests/ounit_ordered_hash_set_tests.cmx : \
ext/ordered_hash_set_string.cmx ounit/oUnit.cmx ext/ext_util.cmx \
@@ -706,8 +710,8 @@ bsb/bsb_build_schemas.cmx :
bsb/bsb_build_ui.cmx : ext/string_vec.cmx ext/string_set.cmx \
ext/string_map.cmx ext/ext_string.cmx ext/ext_json_types.cmx \
ext/ext_json.cmx ext/ext_filename.cmx ext/ext_file_pp.cmx \
- bsb/bsb_exception.cmx bsb/bsb_build_util.cmx bsb/bsb_build_schemas.cmx \
- common/binary_cache.cmx bsb/bsb_build_ui.cmi
+ ext/ext_array.cmx bsb/bsb_exception.cmx bsb/bsb_build_util.cmx \
+ bsb/bsb_build_schemas.cmx common/binary_cache.cmx bsb/bsb_build_ui.cmi
bsb/bsb_build_util.cmx : ext/string_map.cmx ext/string_hashtbl.cmx \
ext/literals.cmx ext/ext_sys.cmx ext/ext_string.cmx ext/ext_list.cmx \
ext/ext_json_types.cmx ext/ext_json_parse.cmx ext/ext_json.cmx \
@@ -720,11 +724,12 @@ bsb/bsb_config_parse.cmx : ext/string_set.cmx ext/string_map.cmx \
ext/string_hash_set.cmx ext/literals.cmx ext/ext_string.cmx \
ext/ext_json_types.cmx ext/ext_json_parse.cmx ext/ext_json.cmx \
ext/ext_filename.cmx ext/ext_file_pp.cmx ext/ext_array.cmx \
- bsb/bsb_pkg.cmx bsb/bsb_default.cmx bsb/bsb_config_types.cmx \
- bsb/bsb_config.cmx bsb/bsb_build_util.cmx bsb/bsb_build_ui.cmx \
- bsb/bsb_build_schemas.cmx common/bs_version.cmx bsb/bsb_config_parse.cmi
-bsb/bsb_config_types.cmx : ext/string_hash_set.cmx bsb/bsb_config.cmx \
- bsb/bsb_build_ui.cmx
+ bsb/bsb_pkg.cmx bsb/bsb_exception.cmx bsb/bsb_default.cmx \
+ bsb/bsb_config_types.cmx bsb/bsb_config.cmx bsb/bsb_build_util.cmx \
+ bsb/bsb_build_ui.cmx bsb/bsb_build_schemas.cmx common/bs_version.cmx \
+ bsb/bsb_config_parse.cmi
+bsb/bsb_config_types.cmx : ext/string_map.cmx ext/string_hash_set.cmx \
+ bsb/bsb_config.cmx bsb/bsb_build_ui.cmx
bsb/bsb_default.cmx : ext/string_set.cmx ext/literals.cmx \
bsb/bsb_config_types.cmx bsb/bsb_default.cmi
bsb/bsb_dep_infos.cmx : common/bs_version.cmx bsb/bsb_dep_infos.cmi
@@ -760,14 +765,15 @@ bsb/bsb_main.cmx : ext/string_hash_set.cmx ext/literals.cmx ext/ext_sys.cmx \
bsb/bsb_main.cmi
bsb/bsb_ninja.cmx : ext/string_set.cmx ext/string_map.cmx \
ext/string_hash_set.cmx ext/literals.cmx ext/ext_string.cmx \
- ext/ext_filename.cmx bsb/bsb_rule.cmx bsb/bsb_config.cmx \
- bsb/bsb_build_util.cmx bsb/bsb_build_ui.cmx bsb/bsb_build_schemas.cmx \
- common/binary_cache.cmx bsb/bsb_ninja.cmi
+ ext/ext_pervasives.cmx ext/ext_filename.cmx bsb/bsb_rule.cmx \
+ bsb/bsb_config.cmx bsb/bsb_build_util.cmx bsb/bsb_build_ui.cmx \
+ bsb/bsb_build_schemas.cmx common/binary_cache.cmx bsb/bsb_ninja.cmi
bsb/bsb_os_dependent.cmx :
bsb/bsb_pkg.cmx : ext/string_hashtbl.cmx ext/literals.cmx \
bsb/bsb_exception.cmx bsb/bsb_pkg.cmi
bsb/bsb_regex.cmx : bsb/bsb_regex.cmi
-bsb/bsb_rule.cmx : ext/string_set.cmx ext/ext_sys.cmx bsb/bsb_rule.cmi
+bsb/bsb_rule.cmx : ext/string_set.cmx ext/string_map.cmx ext/ext_sys.cmx \
+ bsb/bsb_rule.cmi
bsb/bsb_templates.cmx : bsb/oCamlRes.cmx bsb/bsb_templates.cmi
bsb/bsb_unix.cmx : ext/ext_sys.cmx ext/ext_string.cmx bsb/bsb_unix.cmi
bsb/oCamlRes.cmx :
@@ -789,11 +795,11 @@ bsb/bsb_helper_main.cmi :
bsb/bsb_helper_packer.cmi :
bsb/bsb_init.cmi :
bsb/bsb_main.cmi :
-bsb/bsb_ninja.cmi : ext/string_hash_set.cmi bsb/bsb_rule.cmi \
- bsb/bsb_config.cmi bsb/bsb_build_ui.cmi
+bsb/bsb_ninja.cmi : ext/string_map.cmi ext/string_hash_set.cmi \
+ bsb/bsb_rule.cmi bsb/bsb_config.cmi bsb/bsb_build_ui.cmi
bsb/bsb_pkg.cmi :
bsb/bsb_regex.cmi :
-bsb/bsb_rule.cmi :
+bsb/bsb_rule.cmi : ext/string_map.cmi
bsb/bsb_templates.cmi : bsb/oCamlRes.cmx
bsb/bsb_unix.cmi :
jscmj_main.cmx : common/js_config.cmx core/js_cmj_format.cmx \
diff --git a/jscomp/bin/all_ounit_tests.d b/jscomp/bin/all_ounit_tests.d
index ce254a2e26..c1f1c2b85d 100644
--- a/jscomp/bin/all_ounit_tests.d
+++ b/jscomp/bin/all_ounit_tests.d
@@ -71,11 +71,13 @@ bin/all_ounit_tests.ml : ext/resize_array.mli
bin/all_ounit_tests.ml : ounit/oUnitLogger.ml
bin/all_ounit_tests.ml : ext/ext_json_parse.ml
bin/all_ounit_tests.ml : ext/ext_json_types.ml
+bin/all_ounit_tests.ml : ext/ext_json_write.ml
bin/all_ounit_tests.ml : ext/ext_pervasives.ml
bin/all_ounit_tests.ml : ext/hash_set_poly.mli
bin/all_ounit_tests.ml : ext/string_hashtbl.ml
bin/all_ounit_tests.ml : ounit/oUnitChooser.ml
bin/all_ounit_tests.ml : ext/ext_json_parse.mli
+bin/all_ounit_tests.ml : ext/ext_json_write.mli
bin/all_ounit_tests.ml : ext/ext_pervasives.mli
bin/all_ounit_tests.ml : ext/string_hash_set.ml
bin/all_ounit_tests.ml : ext/string_hashtbl.mli
diff --git a/jscomp/bin/all_ounit_tests.i.ml b/jscomp/bin/all_ounit_tests.i.ml
index a5d13a22e9..113e1f2588 100644
--- a/jscomp/bin/all_ounit_tests.i.ml
+++ b/jscomp/bin/all_ounit_tests.i.ml
@@ -75,7 +75,7 @@ open OUnitTypes
(** Most simple heuristic, just pick the first test. *)
let simple state =
- (* 201 *) List.hd state.tests_planned
+ (* 206 *) List.hd state.tests_planned
end
module OUnitUtils
@@ -98,22 +98,22 @@ let is_success =
let is_failure =
function
| RFailure _ -> (* 0 *) true
- | RSuccess _ | RError _ | RSkip _ | RTodo _ -> (* 402 *) false
+ | RSuccess _ | RError _ | RSkip _ | RTodo _ -> (* 412 *) false
let is_error =
function
| RError _ -> (* 0 *) true
- | RSuccess _ | RFailure _ | RSkip _ | RTodo _ -> (* 402 *) false
+ | RSuccess _ | RFailure _ | RSkip _ | RTodo _ -> (* 412 *) false
let is_skip =
function
| RSkip _ -> (* 0 *) true
- | RSuccess _ | RFailure _ | RError _ | RTodo _ -> (* 402 *) false
+ | RSuccess _ | RFailure _ | RError _ | RTodo _ -> (* 412 *) false
let is_todo =
function
| RTodo _ -> (* 0 *) true
- | RSuccess _ | RFailure _ | RError _ | RSkip _ -> (* 402 *) false
+ | RSuccess _ | RFailure _ | RError _ | RSkip _ -> (* 412 *) false
let result_flavour =
function
@@ -145,7 +145,7 @@ let rec was_successful =
| [] -> (* 3 *) true
| RSuccess _::t
| RSkip _::t ->
- (* 603 *) was_successful t
+ (* 618 *) was_successful t
| RFailure _::_
| RError _::_
@@ -155,22 +155,22 @@ let rec was_successful =
let string_of_node =
function
| ListItem n ->
- (* 804 *) string_of_int n
+ (* 824 *) string_of_int n
| Label s ->
- (* 1206 *) s
+ (* 1236 *) s
(* Return the number of available tests *)
let rec test_case_count =
function
- | TestCase _ -> (* 201 *) 1
- | TestLabel (_, t) -> (* 226 *) test_case_count t
+ | TestCase _ -> (* 206 *) 1
+ | TestLabel (_, t) -> (* 231 *) test_case_count t
| TestList l ->
(* 25 *) List.fold_left
- (fun c t -> (* 225 *) c + test_case_count t)
+ (fun c t -> (* 230 *) c + test_case_count t)
0 l
let string_of_path path =
- (* 402 *) String.concat ":" (List.rev_map string_of_node path)
+ (* 412 *) String.concat ":" (List.rev_map string_of_node path)
let buff_format_printf f =
(* 0 *) let buff = Buffer.create 13 in
@@ -194,12 +194,12 @@ let mapi f l =
let fold_lefti f accu l =
(* 25 *) let rec rfold_lefti cnt accup l =
- (* 250 *) match l with
+ (* 255 *) match l with
| [] ->
(* 25 *) accup
| h::t ->
- (* 225 *) rfold_lefti (cnt + 1) (f accup h cnt) t
+ (* 230 *) rfold_lefti (cnt + 1) (f accup h cnt) t
in
rfold_lefti 0 accu l
@@ -217,7 +217,7 @@ open OUnitUtils
type event_type = GlobalEvent of global_event | TestEvent of test_event
let format_event verbose event_type =
- (* 1208 *) match event_type with
+ (* 1238 *) match event_type with
| GlobalEvent e ->
(* 2 *) begin
match e with
@@ -276,31 +276,31 @@ let format_event verbose event_type =
end
| TestEvent e ->
- (* 1206 *) begin
+ (* 1236 *) begin
let string_of_result =
if verbose then
- (* 603 *) function
- | RSuccess _ -> (* 201 *) "ok\n"
+ (* 618 *) function
+ | RSuccess _ -> (* 206 *) "ok\n"
| RFailure (_, _) -> (* 0 *) "FAIL\n"
| RError (_, _) -> (* 0 *) "ERROR\n"
| RSkip (_, _) -> (* 0 *) "SKIP\n"
| RTodo (_, _) -> (* 0 *) "TODO\n"
else
- (* 603 *) function
- | RSuccess _ -> (* 201 *) "."
+ (* 618 *) function
+ | RSuccess _ -> (* 206 *) "."
| RFailure (_, _) -> (* 0 *) "F"
| RError (_, _) -> (* 0 *) "E"
| RSkip (_, _) -> (* 0 *) "S"
| RTodo (_, _) -> (* 0 *) "T"
in
if verbose then
- (* 603 *) match e with
+ (* 618 *) match e with
| EStart p ->
- (* 201 *) Printf.sprintf "%s start\n" (string_of_path p)
+ (* 206 *) Printf.sprintf "%s start\n" (string_of_path p)
| EEnd p ->
- (* 201 *) Printf.sprintf "%s end\n" (string_of_path p)
+ (* 206 *) Printf.sprintf "%s end\n" (string_of_path p)
| EResult result ->
- (* 201 *) string_of_result result
+ (* 206 *) string_of_result result
| ELog (lvl, str) ->
(* 0 *) let prefix =
match lvl with
@@ -312,21 +312,21 @@ let format_event verbose event_type =
| ELogRaw str ->
(* 0 *) str
else
- (* 603 *) match e with
- | EStart _ | EEnd _ | ELog _ | ELogRaw _ -> (* 402 *) ""
- | EResult result -> (* 201 *) string_of_result result
+ (* 618 *) match e with
+ | EStart _ | EEnd _ | ELog _ | ELogRaw _ -> (* 412 *) ""
+ | EResult result -> (* 206 *) string_of_result result
end
let file_logger fn =
(* 1 *) let chn = open_out fn in
(fun ev ->
- (* 604 *) output_string chn (format_event true ev);
+ (* 619 *) output_string chn (format_event true ev);
flush chn),
(fun () -> (* 1 *) close_out chn)
let std_logger verbose =
(* 1 *) (fun ev ->
- (* 604 *) print_string (format_event verbose ev);
+ (* 619 *) print_string (format_event verbose ev);
flush stdout),
(fun () -> (* 1 *) ())
@@ -343,7 +343,7 @@ let create output_file_opt verbose (log,close) =
(* 0 *) null_logger
in
(fun ev ->
- (* 604 *) std_log ev; file_log ev; log ev),
+ (* 619 *) std_log ev; file_log ev; log ev),
(fun () ->
(* 1 *) std_close (); file_close (); close ())
@@ -705,13 +705,13 @@ let assert_failure msg =
(* 0 *) failwith ("OUnit: " ^ msg)
let assert_bool msg b =
- (* 2009445 *) if not b then (* 0 *) assert_failure msg
+ (* 2009455 *) if not b then (* 0 *) assert_failure msg
let assert_string str =
(* 0 *) if not (str = "") then (* 0 *) assert_failure str
let assert_equal ?(cmp = ( = )) ?printer ?pp_diff ?msg expected actual =
- (* 2001542 *) let get_error_string () =
+ (* 2001548 *) let get_error_string () =
(* 0 *) let res =
buff_format_printf
(fun fmt ->
@@ -951,7 +951,7 @@ let (@?) = assert_bool
(* Some shorthands which allows easy test construction *)
let (>:) s t = (* 0 *) TestLabel(s, t) (* infix *)
-let (>::) s f = (* 201 *) TestLabel(s, TestCase(f)) (* infix *)
+let (>::) s f = (* 206 *) TestLabel(s, TestCase(f)) (* infix *)
let (>:::) s l = (* 25 *) TestLabel(s, TestList(l)) (* infix *)
(* Utility function to manipulate test *)
@@ -1087,7 +1087,7 @@ let maybe_backtrace = ""
(* Run all tests, report starts, errors, failures, and return the results *)
let perform_test report test =
(* 1 *) let run_test_case f path =
- (* 201 *) try
+ (* 206 *) try
f ();
RSuccess path
with
@@ -1106,22 +1106,22 @@ let perform_test report test =
let rec flatten_test path acc =
function
| TestCase(f) ->
- (* 201 *) (path, f) :: acc
+ (* 206 *) (path, f) :: acc
| TestList (tests) ->
(* 25 *) fold_lefti
(fun acc t cnt ->
- (* 225 *) flatten_test
+ (* 230 *) flatten_test
((ListItem cnt)::path)
acc t)
acc tests
| TestLabel (label, t) ->
- (* 226 *) flatten_test ((Label label)::path) acc t
+ (* 231 *) flatten_test ((Label label)::path) acc t
in
let test_cases = List.rev (flatten_test [] [] test) in
let runner (path, f) =
- (* 201 *) let result =
+ (* 206 *) let result =
report (EStart path);
run_test_case f path
in
@@ -1130,18 +1130,18 @@ let perform_test report test =
result
in
let rec iter state =
- (* 202 *) match state.tests_planned with
+ (* 207 *) match state.tests_planned with
| [] ->
(* 1 *) state.results
| _ ->
- (* 201 *) let (path, f) = !global_chooser state in
+ (* 206 *) let (path, f) = !global_chooser state in
let result = runner (path, f) in
iter
{
results = result :: state.results;
tests_planned =
List.filter
- (fun (path', _) -> (* 20301 *) path <> path') state.tests_planned
+ (fun (path', _) -> (* 21321 *) path <> path') state.tests_planned
}
in
iter {results = []; tests_planned = test_cases}
@@ -1171,7 +1171,7 @@ let run_test_tt ?verbose test =
time_fun
perform_test
(fun ev ->
- (* 603 *) log (OUnitLogger.TestEvent ev))
+ (* 618 *) log (OUnitLogger.TestEvent ev))
test
in
@@ -1320,6 +1320,12 @@ val find_and_split :
val exists : ('a -> bool) -> 'a array -> bool
val is_empty : 'a array -> bool
+
+val for_all2_no_exn :
+ ('a -> 'b -> bool) ->
+ 'a array ->
+ 'b array ->
+ bool
end = struct
#1 "ext_array.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
@@ -1373,13 +1379,13 @@ let reverse a =
b
let reverse_of_list = function
- | [] -> (* 1 *) [||]
+ | [] -> (* 5 *) [||]
| hd::tl as l ->
- (* 2 *) let len = List.length l in
+ (* 14 *) let len = List.length l in
let a = Array.make len hd in
let rec fill i = function
- | [] -> (* 2 *) a
- | hd::tl -> (* 2 *) Array.unsafe_set a (len - i - 2) hd; fill (i+1) tl in
+ | [] -> (* 14 *) a
+ | hd::tl -> (* 38 *) Array.unsafe_set a (len - i - 2) hd; fill (i+1) tl in
fill 0 tl
let filter f a =
@@ -1508,6 +1514,21 @@ let exists p a =
let is_empty arr =
(* 0 *) Array.length arr = 0
+
+
+let rec unsafe_loop index len p xs ys =
+ (* 24 *) if index >= len then (* 6 *) true
+ else
+ (* 18 *) p
+ (Array.unsafe_get xs index)
+ (Array.unsafe_get ys index) &&
+ unsafe_loop (succ index) len p xs ys
+
+let for_all2_no_exn p xs ys =
+ (* 8 *) let len_xs = Array.length xs in
+ let len_ys = Array.length ys in
+ len_xs = len_ys &&
+ unsafe_loop 0 len_xs p xs ys
end
module Ext_bytes : sig
#1 "ext_bytes.mli"
@@ -1873,15 +1894,15 @@ let starts_with s beg =
end with [beg]
*)
let ends_with_index s end_ =
- (* 63 *) let s_finish = String.length s - 1 in
+ (* 53 *) let s_finish = String.length s - 1 in
let s_beg = String.length end_ - 1 in
if s_beg > s_finish then (* 0 *) -1
else
- (* 63 *) let rec aux j k =
- (* 159 *) if k < 0 then (* 27 *) (j + 1)
- else (* 132 *) if String.unsafe_get s j = String.unsafe_get end_ k then
- (* 96 *) aux (j - 1) (k - 1)
- else (* 36 *) -1 in
+ (* 53 *) let rec aux j k =
+ (* 144 *) if k < 0 then (* 26 *) (j + 1)
+ else (* 118 *) if String.unsafe_get s j = String.unsafe_get end_ k then
+ (* 91 *) aux (j - 1) (k - 1)
+ else (* 27 *) -1 in
aux s_finish s_beg
let ends_with s end_ = (* 0 *) ends_with_index s end_ >= 0
@@ -1898,13 +1919,13 @@ let check_any_suffix_case s suffixes =
(* 0 *) List.exists (fun x -> (* 0 *) check_suffix_case s x) suffixes
let check_any_suffix_case_then_chop s suffixes =
- (* 27 *) let rec aux suffixes =
- (* 62 *) match suffixes with
+ (* 26 *) let rec aux suffixes =
+ (* 52 *) match suffixes with
| [] -> (* 1 *) None
| x::xs ->
- (* 61 *) let id = ends_with_index s x in
- if id >= 0 then (* 26 *) Some (String.sub s 0 id)
- else (* 35 *) aux xs in
+ (* 51 *) let id = ends_with_index s x in
+ if id >= 0 then (* 25 *) Some (String.sub s 0 id)
+ else (* 26 *) aux xs in
aux suffixes
@@ -1931,7 +1952,7 @@ let escaped s =
*)
let rec unsafe_for_all_range s ~start ~finish p =
- (* 154 *) start > finish ||
+ (* 153 *) start > finish ||
p (String.unsafe_get s start) &&
unsafe_for_all_range s ~start:(start + 1) ~finish p
@@ -2098,12 +2119,12 @@ let rindex_opt s c =
(* 0 *) rindex_rec_opt s (String.length s - 1) c;;
let is_valid_module_file (s : string) =
- (* 26 *) let len = String.length s in
+ (* 25 *) let len = String.length s in
len > 0 &&
match String.unsafe_get s 0 with
| 'A' .. 'Z'
| 'a' .. 'z' ->
- (* 12 *) unsafe_for_all_range s ~start:1 ~finish:(len - 1)
+ (* 11 *) unsafe_for_all_range s ~start:1 ~finish:(len - 1)
(fun x ->
(* 9 *) match x with
| 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' | '\'' -> (* 7 *) true
@@ -2140,15 +2161,16 @@ type check_result =
Make {!Ext_filename} not stateful
*)
let is_valid_source_name name : check_result =
- (* 27 *) match check_any_suffix_case_then_chop name [
+ (* 26 *) match check_any_suffix_case_then_chop name [
".ml";
".re";
- ".mli"; ".mll"; ".rei"
+ ".mli";
+ ".rei"
] with
| None -> (* 1 *) Suffix_mismatch
| Some x ->
- (* 26 *) if is_valid_module_file x then
- (* 10 *) Good
+ (* 25 *) if is_valid_module_file x then
+ (* 9 *) Good
else (* 16 *) Invalid_module_name
(** TODO: can be improved to return a positive integer instead *)
@@ -2342,6 +2364,34 @@ let suites =
[|1;2;3;4;5;6|] []
=~ [2;4;6]
end;
+
+ __LOC__ >:: begin fun _ ->
+ (* 1 *) OUnit.assert_bool __LOC__
+ (Ext_array.for_all2_no_exn
+ (=)
+ [|1;2;3|]
+ [|1;2;3|]
+ )
+ end;
+ __LOC__ >:: begin fun _ ->
+ (* 1 *) OUnit.assert_bool __LOC__
+ (Ext_array.for_all2_no_exn
+ (=) [||] [||]
+ );
+ OUnit.assert_bool __LOC__
+ (not @@ Ext_array.for_all2_no_exn
+ (=) [||] [|1|]
+ )
+ end
+ ;
+ __LOC__ >:: begin fun _ ->
+ (* 1 *) OUnit.assert_bool __LOC__
+ (not (Ext_array.for_all2_no_exn
+ (=)
+ [|1;2;3|]
+ [|1;2;33|]
+ ))
+ end
]
end
module Ounit_tests_util
@@ -7944,9 +7994,9 @@ let keys s = (* 1 *) keys_aux [] s
let rec cons_enum m e =
- (* 0 *) match m with
- Empty -> (* 0 *) e
- | Node(l, v, d, r, _) -> (* 0 *) cons_enum l (More(v, d, r, e))
+ (* 30 *) match m with
+ Empty -> (* 18 *) e
+ | Node(l, v, d, r, _) -> (* 12 *) cons_enum l (More(v, d, r, e))
let height = function
@@ -7960,8 +8010,8 @@ let create l x d r =
let singleton x d = (* 0 *) Node(Empty, x, d, Empty, 1)
let bal l x d r =
- (* 27932 *) let hl = match l with Empty -> (* 5003 *) 0 | Node(_,_,_,_,h) -> (* 22929 *) h in
- let hr = match r with Empty -> (* 2 *) 0 | Node(_,_,_,_,h) -> (* 27930 *) h in
+ (* 27954 *) let hl = match l with Empty -> (* 5021 *) 0 | Node(_,_,_,_,h) -> (* 22933 *) h in
+ let hr = match r with Empty -> (* 4 *) 0 | Node(_,_,_,_,h) -> (* 27950 *) h in
if hl > hr + 2 then (* 0 *) begin
match l with
Empty -> (* 0 *) invalid_arg "Map.bal"
@@ -7974,7 +8024,7 @@ let bal l x d r =
| Node(lrl, lrv, lrd, lrr, _)->
(* 0 *) create (create ll lv ld lrl) lrv lrd (create lrr x d r)
end
- end else (* 27932 *) if hr > hl + 2 then (* 1980 *) begin
+ end else (* 27954 *) if hr > hl + 2 then (* 1980 *) begin
match r with
Empty -> (* 0 *) invalid_arg "Map.bal"
| Node(rl, rv, rd, rr, _) ->
@@ -7987,11 +8037,11 @@ let bal l x d r =
(* 0 *) create (create l x d rll) rlv rld (create rlr rv rd rr)
end
end else
- (* 25952 *) Node(l, x, d, r, (if hl >= hr then (* 6082 *) hl + 1 else (* 19870 *) hr + 1))
+ (* 25974 *) Node(l, x, d, r, (if hl >= hr then (* 6086 *) hl + 1 else (* 19888 *) hr + 1))
let empty = Empty
-let is_empty = function Empty -> (* 1 *) true | _ -> (* 0 *) false
+let is_empty = function Empty -> (* 4 *) true | _ -> (* 6 *) false
let rec min_binding_exn = function
Empty -> (* 0 *) raise Not_found
@@ -8043,10 +8093,10 @@ let rec mapi f = function
Node(l', v, d', r', h)
let rec fold f m accu =
- (* 0 *) match m with
- Empty -> (* 0 *) accu
+ (* 42 *) match m with
+ Empty -> (* 24 *) accu
| Node(l, v, d, r, _) ->
- (* 0 *) fold f r (f v d (fold f l accu))
+ (* 18 *) fold f r (f v d (fold f l accu))
let rec for_all p = function
Empty -> (* 0 *) true
@@ -8138,13 +8188,13 @@ let compare compare_key cmp_val m1 m2 =
in compare_aux (cons_enum m1 End) (cons_enum m2 End)
let equal compare_key cmp m1 m2 =
- (* 0 *) let rec equal_aux e1 e2 =
- (* 0 *) match (e1, e2) with
- (End, End) -> (* 0 *) true
+ (* 3 *) let rec equal_aux e1 e2 =
+ (* 9 *) match (e1, e2) with
+ (End, End) -> (* 3 *) true
| (End, _) -> (* 0 *) false
| (_, End) -> (* 0 *) false
| (More(v1, d1, r1, e1), More(v2, d2, r2, e2)) ->
- (* 0 *) compare_key v1 v2 = 0 && cmp d1 d2 &&
+ (* 6 *) compare_key v1 v2 = 0 && cmp d1 d2 &&
equal_aux (cons_enum r1 e1) (cons_enum r2 e2)
in equal_aux (cons_enum m1 End) (cons_enum m2 End)
@@ -8343,17 +8393,17 @@ let max_binding_exn = Map_gen.max_binding_exn
let min_binding_exn = Map_gen.min_binding_exn
-let rec add x data (tree : _ Map_gen.t as 'a) : 'a = (* 4 *) match tree with
+let rec add x data (tree : _ Map_gen.t as 'a) : 'a = (* 50 *) match tree with
| Empty ->
- (* 4 *) Node(Empty, x, data, Empty, 1)
+ (* 28 *) Node(Empty, x, data, Empty, 1)
| Node(l, v, d, r, h) ->
- (* 0 *) let c = compare_key x v in
+ (* 22 *) let c = compare_key x v in
if c = 0 then
(* 0 *) Node(l, x, data, r, h)
- else (* 0 *) if c < 0 then
- (* 0 *) bal (add x data l) v d r
+ else (* 22 *) if c < 0 then
+ (* 2 *) bal (add x data l) v d r
else
- (* 0 *) bal l v d (add x data r)
+ (* 20 *) bal l v d (add x data r)
let rec adjust x data replace (tree : _ Map_gen.t as 'a) : 'a =
@@ -8459,7 +8509,7 @@ let rec disjoint_merge (s1 : _ Map_gen.t) (s2 : _ Map_gen.t) : _ Map_gen.t =
let compare cmp m1 m2 = (* 0 *) Map_gen.compare compare_key cmp m1 m2
-let equal cmp m1 m2 = (* 0 *) Map_gen.equal compare_key cmp m1 m2
+let equal cmp m1 m2 = (* 3 *) Map_gen.equal compare_key cmp m1 m2
let add_list (xs : _ list ) init =
(* 0 *) List.fold_left (fun acc (k,v) -> (* 0 *) add k v acc) init xs
@@ -8661,9 +8711,32 @@ val query : path -> Ext_json_types.t -> status
val loc_of : Ext_json_types.t -> Ext_position.t
+val equal : Ext_json_types.t -> Ext_json_types.t -> bool
end = struct
#1 "ext_json.ml"
-
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
type callback =
[
@@ -8679,7 +8752,7 @@ type callback =
| `Id of (Ext_json_types.t -> unit )
]
-
+
type path = string list
type status =
@@ -8689,26 +8762,26 @@ type status =
let test ?(fail=(fun () -> ())) key
(cb : callback) (m : Ext_json_types.t String_map.t)
- =
- (* 2 *) begin match String_map.find_exn key m, cb with
- | exception Not_found ->
- (* 0 *) begin match cb with `Not_found f -> (* 0 *) f ()
- | _ -> (* 0 *) fail ()
- end
- | True _, `Bool cb -> (* 0 *) cb true
- | False _, `Bool cb -> (* 0 *) cb false
- | Flo {flo = s} , `Flo cb -> (* 2 *) cb s
- | Obj {map = b} , `Obj cb -> (* 0 *) cb b
- | Arr {content}, `Arr cb -> (* 0 *) cb content
- | Arr {content; loc_start ; loc_end}, `Arr_loc cb ->
- (* 0 *) cb content loc_start loc_end
- | Null _, `Null cb -> (* 0 *) cb ()
- | Str {str = s }, `Str cb -> (* 0 *) cb s
- | Str {str = s ; loc }, `Str_loc cb -> (* 0 *) cb s loc
- | any , `Id cb -> (* 0 *) cb any
- | _, _ -> (* 0 *) fail ()
- end;
- m
+ =
+ (* 2 *) begin match String_map.find_exn key m, cb with
+ | exception Not_found ->
+ (* 0 *) begin match cb with `Not_found f -> (* 0 *) f ()
+ | _ -> (* 0 *) fail ()
+ end
+ | True _, `Bool cb -> (* 0 *) cb true
+ | False _, `Bool cb -> (* 0 *) cb false
+ | Flo {flo = s} , `Flo cb -> (* 2 *) cb s
+ | Obj {map = b} , `Obj cb -> (* 0 *) cb b
+ | Arr {content}, `Arr cb -> (* 0 *) cb content
+ | Arr {content; loc_start ; loc_end}, `Arr_loc cb ->
+ (* 0 *) cb content loc_start loc_end
+ | Null _, `Null cb -> (* 0 *) cb ()
+ | Str {str = s }, `Str cb -> (* 0 *) cb s
+ | Str {str = s ; loc }, `Str_loc cb -> (* 0 *) cb s loc
+ | any , `Id cb -> (* 0 *) cb any
+ | _, _ -> (* 0 *) fail ()
+ end;
+ m
let query path (json : Ext_json_types.t ) =
(* 0 *) let rec aux acc paths json =
(* 0 *) match path with
@@ -8732,7 +8805,53 @@ let loc_of (x : Ext_json_types.t) =
| Arr p -> (* 0 *) p.loc_start
| Obj p -> (* 0 *) p.loc
| Flo p -> (* 0 *) p.loc
-
+
+
+let rec equal
+ (x : Ext_json_types.t)
+ (y : Ext_json_types.t) =
+ (* 24 *) match x with
+ | Null _ -> (* [%p? Null _ ] *)
+ (* 0 *) begin match y with
+ | Null _ -> (* 0 *) true
+ | _ -> (* 0 *) false end
+ | Str {str } ->
+ (* 4 *) begin match y with
+ | Str {str = str2} -> (* 4 *) str = str2
+ | _ -> (* 0 *) false end
+ | Flo {flo}
+ ->
+ (* 11 *) begin match y with
+ | Flo {flo = flo2} ->
+ (* 11 *) flo = flo2
+ | _ -> (* 0 *) false
+ end
+ | True _ ->
+ (* 1 *) begin match y with
+ | True _ -> (* 1 *) true
+ | _ -> (* 0 *) false
+ end
+ | False _ ->
+ (* 1 *) begin match y with
+ | False _ -> (* 1 *) true
+ | _ -> (* 0 *) false
+ end
+ | Arr {content}
+ ->
+ (* 4 *) begin match y with
+ | Arr {content = content2}
+ ->
+ (* 4 *) Ext_array.for_all2_no_exn equal content content2
+ | _ -> (* 0 *) false
+ end
+
+ | Obj {map} ->
+ (* 3 *) begin match y with
+ | Obj { map = map2} ->
+ (* 3 *) String_map.equal equal map map2
+ | _ -> (* 0 *) false
+ end
+
end
module Ext_json_parse : sig
@@ -8877,7 +8996,7 @@ let lexeme_len (x : Lexing.lexbuf) =
(* 0 *) x.lex_curr_pos - x.lex_start_pos
let update_loc ({ lex_curr_p; _ } as lexbuf : Lexing.lexbuf) diff =
- (* 0 *) lexbuf.lex_curr_p <-
+ (* 4 *) lexbuf.lex_curr_p <-
{
lex_curr_p with
pos_lnum = lex_curr_p.pos_lnum + 1;
@@ -8889,7 +9008,7 @@ let char_for_backslash = function
| 'r' -> (* 0 *) '\013'
| 'b' -> (* 0 *) '\008'
| 't' -> (* 0 *) '\009'
- | c -> (* 0 *) c
+ | c -> (* 4 *) c
let dec_code c1 c2 c3 =
(* 0 *) 100 * (Char.code c1 - 48) + 10 * (Char.code c2 - 48) + (Char.code c3 - 48)
@@ -9093,17 +9212,17 @@ let __ocaml_lex_tables = {
}
let rec lex_json buf lexbuf =
- (* 86 *) __ocaml_lex_lex_json_rec buf lexbuf 0
+ (* 500 *) __ocaml_lex_lex_json_rec buf lexbuf 0
and __ocaml_lex_lex_json_rec buf lexbuf __ocaml_lex_state =
- (* 86 *) match Lexing.engine __ocaml_lex_tables __ocaml_lex_state lexbuf with
+ (* 500 *) match Lexing.engine __ocaml_lex_tables __ocaml_lex_state lexbuf with
| 0 ->
# 152 "ext/ext_json_parse.mll"
- (* 31 *) ( lex_json buf lexbuf)
+ (* 193 *) ( lex_json buf lexbuf)
# 324 "ext/ext_json_parse.ml"
| 1 ->
# 153 "ext/ext_json_parse.mll"
- (* 0 *) (
+ (* 4 *) (
update_loc lexbuf 0;
lex_json buf lexbuf
)
@@ -9116,12 +9235,12 @@ and __ocaml_lex_lex_json_rec buf lexbuf __ocaml_lex_state =
| 3 ->
# 158 "ext/ext_json_parse.mll"
- (* 0 *) ( True)
+ (* 4 *) ( True)
# 342 "ext/ext_json_parse.ml"
| 4 ->
# 159 "ext/ext_json_parse.mll"
- (* 0 *) (False)
+ (* 4 *) (False)
# 347 "ext/ext_json_parse.ml"
| 5 ->
@@ -9131,32 +9250,32 @@ and __ocaml_lex_lex_json_rec buf lexbuf __ocaml_lex_state =
| 6 ->
# 161 "ext/ext_json_parse.mll"
- (* 5 *) (Lbracket)
+ (* 21 *) (Lbracket)
# 357 "ext/ext_json_parse.ml"
| 7 ->
# 162 "ext/ext_json_parse.mll"
- (* 3 *) (Rbracket)
+ (* 19 *) (Rbracket)
# 362 "ext/ext_json_parse.ml"
| 8 ->
# 163 "ext/ext_json_parse.mll"
- (* 6 *) (Lbrace)
+ (* 18 *) (Lbrace)
# 367 "ext/ext_json_parse.ml"
| 9 ->
# 164 "ext/ext_json_parse.mll"
- (* 3 *) (Rbrace)
+ (* 15 *) (Rbrace)
# 372 "ext/ext_json_parse.ml"
| 10 ->
# 165 "ext/ext_json_parse.mll"
- (* 13 *) (Comma)
+ (* 65 *) (Comma)
# 377 "ext/ext_json_parse.ml"
| 11 ->
# 166 "ext/ext_json_parse.mll"
- (* 4 *) (Colon)
+ (* 28 *) (Colon)
# 382 "ext/ext_json_parse.ml"
| 12 ->
@@ -9166,12 +9285,12 @@ and __ocaml_lex_lex_json_rec buf lexbuf __ocaml_lex_state =
| 13 ->
# 169 "ext/ext_json_parse.mll"
- (* 11 *) ( Number (Lexing.lexeme lexbuf))
+ (* 55 *) ( Number (Lexing.lexeme lexbuf))
# 392 "ext/ext_json_parse.ml"
| 14 ->
# 171 "ext/ext_json_parse.mll"
- (* 4 *) (
+ (* 44 *) (
let pos = Lexing.lexeme_start_p lexbuf in
scan_string buf pos lexbuf;
let content = (Buffer.contents buf) in
@@ -9182,7 +9301,7 @@ and __ocaml_lex_lex_json_rec buf lexbuf __ocaml_lex_state =
| 15 ->
# 178 "ext/ext_json_parse.mll"
- (* 6 *) (Eof )
+ (* 30 *) (Eof )
# 408 "ext/ext_json_parse.ml"
| 16 ->
@@ -9221,12 +9340,12 @@ and __ocaml_lex_comment_rec buf lexbuf __ocaml_lex_state =
__ocaml_lex_comment_rec buf lexbuf __ocaml_lex_state
and scan_string buf start lexbuf =
- (* 8 *) __ocaml_lex_scan_string_rec buf start lexbuf 45
+ (* 92 *) __ocaml_lex_scan_string_rec buf start lexbuf 45
and __ocaml_lex_scan_string_rec buf start lexbuf __ocaml_lex_state =
- (* 8 *) match Lexing.engine __ocaml_lex_tables __ocaml_lex_state lexbuf with
+ (* 92 *) match Lexing.engine __ocaml_lex_tables __ocaml_lex_state lexbuf with
| 0 ->
# 187 "ext/ext_json_parse.mll"
- (* 4 *) ( () )
+ (* 44 *) ( () )
# 452 "ext/ext_json_parse.ml"
| 1 ->
@@ -9249,7 +9368,7 @@ and __ocaml_lex_scan_string_rec buf start lexbuf __ocaml_lex_state =
# 471 "ext/ext_json_parse.ml"
| 3 ->
-(* 0 *) let
+(* 4 *) let
# 201 "ext/ext_json_parse.mll"
c
# 477 "ext/ext_json_parse.ml"
@@ -9340,7 +9459,7 @@ and
| 8 ->
# 237 "ext/ext_json_parse.mll"
- (* 4 *) (
+ (* 44 *) (
let ofs = lexbuf.lex_start_pos in
let len = lexbuf.lex_curr_pos - ofs in
Buffer.add_substring buf lexbuf.lex_buffer ofs len;
@@ -9370,26 +9489,26 @@ and
let rec parse_json lexbuf =
- (* 11 *) let buf = Buffer.create 64 in
+ (* 35 *) let buf = Buffer.create 64 in
let look_ahead = ref None in
let token () : token =
- (* 63 *) match !look_ahead with
+ (* 359 *) match !look_ahead with
| None ->
- (* 55 *) lex_json buf lexbuf
+ (* 303 *) lex_json buf lexbuf
| Some x ->
- (* 8 *) look_ahead := None ;
+ (* 56 *) look_ahead := None ;
x
in
- let push e = (* 8 *) look_ahead := Some e in
+ let push e = (* 56 *) look_ahead := Some e in
let rec json (lexbuf : Lexing.lexbuf) : Ext_json_types.t =
- (* 23 *) match token () with
- | True -> (* 0 *) True lexbuf.lex_start_p
- | False -> (* 0 *) False lexbuf.lex_start_p
+ (* 119 *) match token () with
+ | True -> (* 4 *) True lexbuf.lex_start_p
+ | False -> (* 4 *) False lexbuf.lex_start_p
| Null -> (* 0 *) Null lexbuf.lex_start_p
- | Number s -> (* 10 *) Flo {flo = s; loc = lexbuf.lex_start_p}
- | String s -> (* 0 *) Str { str = s; loc = lexbuf.lex_start_p}
- | Lbracket -> (* 5 *) parse_array lexbuf.lex_start_p lexbuf.lex_curr_p [] lexbuf
- | Lbrace -> (* 6 *) parse_map lexbuf.lex_start_p String_map.empty lexbuf
+ | Number s -> (* 54 *) Flo {flo = s; loc = lexbuf.lex_start_p}
+ | String s -> (* 16 *) Str { str = s; loc = lexbuf.lex_start_p}
+ | Lbracket -> (* 21 *) parse_array lexbuf.lex_start_p lexbuf.lex_curr_p [] lexbuf
+ | Lbrace -> (* 18 *) parse_map lexbuf.lex_start_p String_map.empty lexbuf
| _ -> (* 2 *) error lexbuf Unexpected_token
(** Note if we remove [trailing_comma] support
we should report errors (actually more work), for example
@@ -9411,35 +9530,35 @@ let rec parse_json lexbuf =
*)
and parse_array loc_start loc_finish acc lexbuf
: Ext_json_types.t =
- (* 10 *) match token () with
+ (* 62 *) match token () with
| Rbracket ->
- (* 2 *) Arr {loc_start ; content = Ext_array.reverse_of_list acc ;
+ (* 6 *) Arr {loc_start ; content = Ext_array.reverse_of_list acc ;
loc_end = lexbuf.lex_curr_p }
| x ->
- (* 8 *) push x ;
+ (* 56 *) push x ;
let new_one = json lexbuf in
begin match token () with
| Comma ->
- (* 5 *) parse_array loc_start loc_finish (new_one :: acc) lexbuf
+ (* 41 *) parse_array loc_start loc_finish (new_one :: acc) lexbuf
| Rbracket
- -> (* 1 *) Arr {content = (Ext_array.reverse_of_list (new_one::acc));
+ -> (* 13 *) Arr {content = (Ext_array.reverse_of_list (new_one::acc));
loc_start ;
loc_end = lexbuf.lex_curr_p }
| _ ->
(* 0 *) error lexbuf Expect_comma_or_rbracket
end
and parse_map loc_start acc lexbuf : Ext_json_types.t =
- (* 10 *) match token () with
+ (* 38 *) match token () with
| Rbrace ->
- (* 3 *) Obj { map = acc ; loc = loc_start}
+ (* 7 *) Obj { map = acc ; loc = loc_start}
| String key ->
- (* 4 *) begin match token () with
+ (* 28 *) begin match token () with
| Colon ->
- (* 4 *) let value = json lexbuf in
+ (* 28 *) let value = json lexbuf in
begin match token () with
- | Rbrace -> (* 0 *) Obj {map = String_map.add key value acc ; loc = loc_start}
+ | Rbrace -> (* 8 *) Obj {map = String_map.add key value acc ; loc = loc_start}
| Comma ->
- (* 4 *) parse_map loc_start (String_map.add key value acc) lexbuf
+ (* 20 *) parse_map loc_start (String_map.add key value acc) lexbuf
| _ -> (* 0 *) error lexbuf Expect_comma_or_rbrace
end
| _ -> (* 0 *) error lexbuf Expect_colon
@@ -9448,11 +9567,11 @@ let rec parse_json lexbuf =
in
let v = json lexbuf in
match token () with
- | Eof -> (* 6 *) v
+ | Eof -> (* 30 *) v
| _ -> (* 0 *) error lexbuf Expect_eof
let parse_json_from_string s =
- (* 11 *) parse_json (Lexing.from_string s )
+ (* 35 *) parse_json (Lexing.from_string s )
let parse_json_from_chan in_chan =
(* 0 *) let lexbuf = Lexing.from_channel in_chan in
@@ -9472,83 +9591,127 @@ let parse_json_from_file s =
# 694 "ext/ext_json_parse.ml"
end
-module Ounit_json_tests
-= struct
-#1 "ounit_json_tests.ml"
+module Ext_json_write : sig
+#1 "ext_json_write.mli"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-let ((>::),
- (>:::)) = OUnit.((>::),(>:::))
-open Ext_json_parse
-let (|?) m (key, cb) =
- (* 2 *) m |> Ext_json.test key cb
+val to_string : Ext_json_types.t -> string
-exception Parse_error
-let suites =
- __FILE__
- >:::
- [
- "empty_json" >:: begin fun _ ->
- (* 1 *) let v =parse_json_from_string "{}" in
- match v with
- | Obj {map = v} -> (* 1 *) OUnit.assert_equal (String_map.is_empty v ) true
- | _ -> (* 0 *) OUnit.assert_failure "should be empty"
- end
- ;
- "empty_arr" >:: begin fun _ ->
- (* 1 *) let v =parse_json_from_string "[]" in
- match v with
- | Arr {content = [||]} -> (* 1 *) ()
- | _ -> (* 0 *) OUnit.assert_failure "should be empty"
- end
- ;
- "empty trails" >:: begin fun _ ->
- (* 1 *) (OUnit.assert_raises Parse_error @@ fun _ ->
- (* 1 *) try parse_json_from_string {| [,]|} with _ -> (* 1 *) raise Parse_error);
- OUnit.assert_raises Parse_error @@ fun _ ->
- (* 1 *) try parse_json_from_string {| {,}|} with _ -> (* 1 *) raise Parse_error
- end;
- "two trails" >:: begin fun _ ->
- (* 1 *) (OUnit.assert_raises Parse_error @@ fun _ ->
- (* 1 *) try parse_json_from_string {| [1,2,,]|} with _ -> (* 1 *) raise Parse_error);
- (OUnit.assert_raises Parse_error @@ fun _ ->
- (* 1 *) try parse_json_from_string {| { "x": 3, ,}|} with _ -> (* 1 *) raise Parse_error)
- end;
- "two trails fail" >:: begin fun _ ->
- (* 1 *) (OUnit.assert_raises Parse_error @@ fun _ ->
- (* 1 *) try parse_json_from_string {| { "x": 3, 2 ,}|} with _ -> (* 1 *) raise Parse_error)
- end;
+val to_channel : out_channel -> Ext_json_types.t -> unit
+end = struct
+#1 "ext_json_write.ml"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
- "trail comma obj" >:: begin fun _ ->
- (* 1 *) let v = parse_json_from_string {| { "x" : 3 , }|} in
- let v1 = parse_json_from_string {| { "x" : 3 , }|} in
- let test (v : Ext_json_types.t) =
- (* 2 *) match v with
- | Obj {map = v} ->
- (* 2 *) v
- |? ("x" , `Flo (fun x -> (* 2 *) OUnit.assert_equal x "3"))
- |> ignore
- | _ -> (* 0 *) OUnit.assert_failure "trail comma" in
- test v ;
- test v1
- end
- ;
- "trail comma arr" >:: begin fun _ ->
- (* 1 *) let v = parse_json_from_string {| [ 1, 3, ]|} in
- let v1 = parse_json_from_string {| [ 1, 3 ]|} in
- let test (v : Ext_json_types.t) =
- (* 2 *) match v with
- | Arr { content = [| Flo {flo = "1"} ; Flo { flo = "3"} |] } -> (* 2 *) ()
- | _ -> (* 0 *) OUnit.assert_failure "trailing comma array" in
- test v ;
- test v1
+(** poor man's serialization *)
+
+let quot x =
+ (* 30 *) "\"" ^ String.escaped x ^ "\""
+
+let rec encode_aux (x : Ext_json_types.t )
+ (buf : Buffer.t) : unit =
+ (* 72 *) let a str = (* 162 *) Buffer.add_string buf str in
+ match x with
+ | Null _ -> (* 0 *) a "null"
+ | Str {str = s } -> (* 12 *) a (quot s)
+ | Flo {flo = s} -> (* 33 *) a s
+ | Arr {content} ->
+ (* 12 *) begin match content with
+ | [||] -> (* 3 *) a "[]"
+ | _ ->
+ (* 9 *) a "[ ";
+ encode_aux
+ (Array.unsafe_get content 0)
+ buf ;
+ for i = 1 to Array.length content - 1 do
+ (* 27 *) a " , ";
+ encode_aux
+ (Array.unsafe_get content i)
+ buf
+ done;
+ a " ]"
end
- ]
+ | True _ -> (* 3 *) a "true"
+ | False _ -> (* 3 *) a "false"
+ | Obj {map} ->
+ (* 9 *) if String_map.is_empty map then
+ (* 3 *) a "{}"
+ else
+ (* 6 *) begin
+ (*prerr_endline "WEIRD";
+ prerr_endline (string_of_int @@ String_map.cardinal map ); *)
+ a "{ ";
+ let _ : int = String_map.fold (fun k v i ->
+ (* 18 *) if i <> 0 then (* 12 *) begin
+ a " , "
+ end;
+ a (quot k);
+ a " : ";
+ encode_aux v buf ;
+ i + 1
+ ) map 0 in
+ a " }"
+ end
+
+
+let to_string (x : Ext_json_types.t) =
+ (* 18 *) let buf = Buffer.create 1024 in
+ encode_aux x buf ;
+ Buffer.contents buf
+
+let to_channel (oc : out_channel) x =
+ (* 0 *) let buf = Buffer.create 1024 in
+ encode_aux x buf ;
+ Buffer.output_buffer oc buf
end
-module Ext_list : sig
-#1 "ext_list.mli"
+module Ext_pervasives : sig
+#1 "ext_pervasives.mli"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
*
* This program is free software: you can redistribute it and/or modify
@@ -9580,50 +9743,408 @@ module Ext_list : sig
-(** Extension to the standard library [List] module *)
-
-(** TODO some function are no efficiently implemented. *)
+(** Extension to standard library [Pervavives] module, safe to open
+ *)
-val filter_map : ('a -> 'b option) -> 'a list -> 'b list
+external reraise: exn -> 'a = "%reraise"
-val excludes : ('a -> bool) -> 'a list -> bool * 'a list
-val exclude_with_fact : ('a -> bool) -> 'a list -> 'a option * 'a list
-val exclude_with_fact2 :
- ('a -> bool) -> ('a -> bool) -> 'a list -> 'a option * 'a option * 'a list
-val same_length : 'a list -> 'b list -> bool
+val finally : 'a -> ('a -> 'c) -> ('a -> 'b) -> 'b
-val init : int -> (int -> 'a) -> 'a list
+val with_file_as_chan : string -> (out_channel -> 'a) -> 'a
-val take : int -> 'a list -> 'a list * 'a list
-val try_take : int -> 'a list -> 'a list * int * 'a list
+val with_file_as_pp : string -> (Format.formatter -> 'a) -> 'a
-val exclude_tail : 'a list -> 'a * 'a list
+val is_pos_pow : Int32.t -> int
-val length_compare : 'a list -> int -> [`Gt | `Eq | `Lt ]
+val failwithf : loc:string -> ('a, unit, string, 'b) format4 -> 'a
-(**
+val invalid_argf : ('a, unit, string, 'b) format4 -> 'a
- {[length xs = length ys + n ]}
- input n should be positive
- TODO: input checking
-*)
+val bad_argf : ('a, unit, string, 'b) format4 -> 'a
-val length_larger_than_n :
- int -> 'a list -> 'a list -> bool
-val filter_map2 : ('a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list
-val filter_map2i : (int -> 'a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list
+val dump : 'a -> string
+val pp_any : Format.formatter -> 'a -> unit
+external id : 'a -> 'a = "%identity"
-val filter_mapi : (int -> 'a -> 'b option) -> 'a list -> 'b list
+(** Copied from {!Btype.hash_variant}:
+ need sync up and add test case
+ *)
+val hash_variant : string -> int
-val flat_map2 : ('a -> 'b -> 'c list) -> 'a list -> 'b list -> 'c list
+end = struct
+#1 "ext_pervasives.ml"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-val flat_map_acc : ('a -> 'b list) -> 'b list -> 'a list -> 'b list
-val flat_map : ('a -> 'b list) -> 'a list -> 'b list
-(** for the last element the first element will be passed [true] *)
+
+
+
+external reraise: exn -> 'a = "%reraise"
+
+let finally v action f =
+ (* 0 *) match f v with
+ | exception e ->
+ (* 0 *) action v ;
+ reraise e
+ | e -> (* 0 *) action v ; e
+
+let with_file_as_chan filename f =
+ (* 0 *) finally (open_out_bin filename) close_out f
+
+let with_file_as_pp filename f =
+ (* 0 *) finally (open_out_bin filename) close_out
+ (fun chan ->
+ (* 0 *) let fmt = Format.formatter_of_out_channel chan in
+ let v = f fmt in
+ Format.pp_print_flush fmt ();
+ v
+ )
+
+
+let is_pos_pow n =
+ (* 0 *) let module M = struct exception E end in
+ let rec aux c (n : Int32.t) =
+ (* 0 *) if n <= 0l then (* 0 *) -2
+ else (* 0 *) if n = 1l then (* 0 *) c
+ else (* 0 *) if Int32.logand n 1l = 0l then
+ (* 0 *) aux (c + 1) (Int32.shift_right n 1 )
+ else (* 0 *) raise M.E in
+ try aux 0 n with M.E -> (* 0 *) -1
+
+let failwithf ~loc fmt = (* 0 *) Format.ksprintf (fun s -> (* 0 *) failwith (loc ^ s))
+ fmt
+
+let invalid_argf fmt = (* 0 *) Format.ksprintf invalid_arg fmt
+
+let bad_argf fmt = (* 0 *) Format.ksprintf (fun x -> (* 0 *) raise (Arg.Bad x ) ) fmt
+
+
+let rec dump r =
+ (* 0 *) if Obj.is_int r then
+ (* 0 *) string_of_int (Obj.magic r : int)
+ else (* Block. *)
+ (* 0 *) let rec get_fields acc = function
+ | 0 -> (* 0 *) acc
+ | n -> (* 0 *) let n = n-1 in get_fields (Obj.field r n :: acc) n
+ in
+ let rec is_list r =
+ (* 0 *) if Obj.is_int r then
+ (* 0 *) r = Obj.repr 0 (* [] *)
+ else
+ (* 0 *) let s = Obj.size r and t = Obj.tag r in
+ t = 0 && s = 2 && is_list (Obj.field r 1) (* h :: t *)
+ in
+ let rec get_list r =
+ (* 0 *) if Obj.is_int r then
+ (* 0 *) []
+ else
+ (* 0 *) let h = Obj.field r 0 and t = get_list (Obj.field r 1) in
+ h :: t
+ in
+ let opaque name =
+ (* XXX In future, print the address of value 'r'. Not possible
+ * in pure OCaml at the moment. *)
+ (* 0 *) "<" ^ name ^ ">"
+ in
+ let s = Obj.size r and t = Obj.tag r in
+ (* From the tag, determine the type of block. *)
+ match t with
+ | _ when (* 0 *) is_list r ->
+ (* 0 *) let fields = get_list r in
+ "[" ^ String.concat "; " (List.map dump fields) ^ "]"
+ | 0 ->
+ (* 0 *) let fields = get_fields [] s in
+ "(" ^ String.concat ", " (List.map dump fields) ^ ")"
+ | x when (* 0 *) x = Obj.lazy_tag ->
+ (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not
+ * clear if very large constructed values could have the same
+ * tag. XXX *)
+ (* 0 *) opaque "lazy"
+ | x when (* 0 *) x = Obj.closure_tag ->
+ (* 0 *) opaque "closure"
+ | x when (* 0 *) x = Obj.object_tag ->
+ (* 0 *) let fields = get_fields [] s in
+ let _clasz, id, slots =
+ match fields with
+ | h::h'::t -> (* 0 *) h, h', t
+ | _ -> (* 0 *) assert false
+ in
+ (* No information on decoding the class (first field). So just print
+ * out the ID and the slots. *)
+ "Object #" ^ dump id ^ " (" ^ String.concat ", " (List.map dump slots) ^ ")"
+ | x when (* 0 *) x = Obj.infix_tag ->
+ (* 0 *) opaque "infix"
+ | x when (* 0 *) x = Obj.forward_tag ->
+ (* 0 *) opaque "forward"
+ | x when (* 0 *) x < Obj.no_scan_tag ->
+ (* 0 *) let fields = get_fields [] s in
+ "Tag" ^ string_of_int t ^
+ " (" ^ String.concat ", " (List.map dump fields) ^ ")"
+ | x when (* 0 *) x = Obj.string_tag ->
+ (* 0 *) "\"" ^ String.escaped (Obj.magic r : string) ^ "\""
+ | x when (* 0 *) x = Obj.double_tag ->
+ (* 0 *) string_of_float (Obj.magic r : float)
+ | x when (* 0 *) x = Obj.abstract_tag ->
+ (* 0 *) opaque "abstract"
+ | x when (* 0 *) x = Obj.custom_tag ->
+ (* 0 *) opaque "custom"
+ | x when (* 0 *) x = Obj.custom_tag ->
+ (* 0 *) opaque "final"
+ | x when (* 0 *) x = Obj.double_array_tag ->
+ (* 0 *) "[|"^
+ String.concat ";"
+ (Array.to_list (Array.map string_of_float (Obj.magic r : float array))) ^
+ "|]"
+ | _ ->
+ (* 0 *) opaque (Printf.sprintf "unknown: tag %d size %d" t s)
+
+let dump v = (* 0 *) dump (Obj.repr v)
+
+let pp_any fmt v =
+ (* 0 *) Format.fprintf fmt "@[%s@]"
+ (dump v )
+external id : 'a -> 'a = "%identity"
+
+
+let hash_variant s =
+ (* 0 *) let accu = ref 0 in
+ for i = 0 to String.length s - 1 do
+ (* 0 *) accu := 223 * !accu + Char.code s.[i]
+ done;
+ (* reduce to 31 bits *)
+ accu := !accu land (1 lsl 31 - 1);
+ (* make it signed for 64 bits architectures *)
+ if !accu > 0x3FFFFFFF then (* 0 *) !accu - (1 lsl 31) else (* 0 *) !accu
+
+
+end
+module Ounit_json_tests
+= struct
+#1 "ounit_json_tests.ml"
+
+let ((>::),
+ (>:::)) = OUnit.((>::),(>:::))
+
+open Ext_json_parse
+let (|?) m (key, cb) =
+ (* 2 *) m |> Ext_json.test key cb
+
+let id_parsing_serializing x =
+ (* 6 *) let normal_s =
+ Ext_json_write.to_string ( Ext_json_parse.parse_json_from_string x )
+ in
+ let normal_ss =
+ Ext_json_write.to_string
+ (Ext_json_parse.parse_json_from_string normal_s)
+ in
+ if normal_s <> normal_ss then
+ (* 0 *) begin
+ prerr_endline "ERROR";
+ prerr_endline normal_s ;
+ prerr_endline normal_ss ;
+ end;
+ OUnit.assert_equal ~cmp:(fun (x:string) y -> (* 6 *) x = y) normal_s normal_ss
+
+let id_parsing_x2 x =
+ (* 6 *) let stru = Ext_json_parse.parse_json_from_string x in
+ let normal_s = Ext_json_write.to_string stru in
+ let normal_ss = (Ext_json_parse.parse_json_from_string normal_s) in
+ if Ext_json.equal stru normal_ss then
+ (* 6 *) true
+ else (* 0 *) begin
+ prerr_endline "ERROR";
+ prerr_endline normal_s;
+ Format.fprintf Format.err_formatter
+ "%a@.%a@." Ext_pervasives.pp_any stru Ext_pervasives.pp_any normal_ss;
+
+ prerr_endline (Ext_json_write.to_string normal_ss);
+ false
+ end
+
+let test_data =
+ [{|
+ {}
+ |};
+ {| [] |};
+ {| [1,2,3]|};
+ {| ["x", "y", 1,2,3 ]|};
+ {| { "x" : 3, "y" : "x", "z" : [1,2,3, "x"] }|};
+ {| {"x " : true , "y" : false , "z\"" : 1} |}
+ ]
+exception Parse_error
+let suites =
+ __FILE__
+ >:::
+ [
+
+ __LOC__ >:: begin fun _ ->
+ (* 1 *) List.iter id_parsing_serializing test_data
+ end;
+
+ __LOC__ >:: begin fun _ ->
+ (* 1 *) List.iteri (fun i x -> (* 6 *) OUnit.assert_bool (__LOC__ ^ string_of_int i ) (id_parsing_x2 x)) test_data
+ end;
+ "empty_json" >:: begin fun _ ->
+ (* 1 *) let v =parse_json_from_string "{}" in
+ match v with
+ | Obj {map = v} -> (* 1 *) OUnit.assert_equal (String_map.is_empty v ) true
+ | _ -> (* 0 *) OUnit.assert_failure "should be empty"
+ end
+ ;
+ "empty_arr" >:: begin fun _ ->
+ (* 1 *) let v =parse_json_from_string "[]" in
+ match v with
+ | Arr {content = [||]} -> (* 1 *) ()
+ | _ -> (* 0 *) OUnit.assert_failure "should be empty"
+ end
+ ;
+ "empty trails" >:: begin fun _ ->
+ (* 1 *) (OUnit.assert_raises Parse_error @@ fun _ ->
+ (* 1 *) try parse_json_from_string {| [,]|} with _ -> (* 1 *) raise Parse_error);
+ OUnit.assert_raises Parse_error @@ fun _ ->
+ (* 1 *) try parse_json_from_string {| {,}|} with _ -> (* 1 *) raise Parse_error
+ end;
+ "two trails" >:: begin fun _ ->
+ (* 1 *) (OUnit.assert_raises Parse_error @@ fun _ ->
+ (* 1 *) try parse_json_from_string {| [1,2,,]|} with _ -> (* 1 *) raise Parse_error);
+ (OUnit.assert_raises Parse_error @@ fun _ ->
+ (* 1 *) try parse_json_from_string {| { "x": 3, ,}|} with _ -> (* 1 *) raise Parse_error)
+ end;
+
+ "two trails fail" >:: begin fun _ ->
+ (* 1 *) (OUnit.assert_raises Parse_error @@ fun _ ->
+ (* 1 *) try parse_json_from_string {| { "x": 3, 2 ,}|} with _ -> (* 1 *) raise Parse_error)
+ end;
+
+ "trail comma obj" >:: begin fun _ ->
+ (* 1 *) let v = parse_json_from_string {| { "x" : 3 , }|} in
+ let v1 = parse_json_from_string {| { "x" : 3 , }|} in
+ let test (v : Ext_json_types.t) =
+ (* 2 *) match v with
+ | Obj {map = v} ->
+ (* 2 *) v
+ |? ("x" , `Flo (fun x -> (* 2 *) OUnit.assert_equal x "3"))
+ |> ignore
+ | _ -> (* 0 *) OUnit.assert_failure "trail comma" in
+ test v ;
+ test v1
+ end
+ ;
+ "trail comma arr" >:: begin fun _ ->
+ (* 1 *) let v = parse_json_from_string {| [ 1, 3, ]|} in
+ let v1 = parse_json_from_string {| [ 1, 3 ]|} in
+ let test (v : Ext_json_types.t) =
+ (* 2 *) match v with
+ | Arr { content = [| Flo {flo = "1"} ; Flo { flo = "3"} |] } -> (* 2 *) ()
+ | _ -> (* 0 *) OUnit.assert_failure "trailing comma array" in
+ test v ;
+ test v1
+ end
+ ]
+
+end
+module Ext_list : sig
+#1 "ext_list.mli"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+
+
+
+
+
+
+
+
+(** Extension to the standard library [List] module *)
+
+(** TODO some function are no efficiently implemented. *)
+
+val filter_map : ('a -> 'b option) -> 'a list -> 'b list
+
+val excludes : ('a -> bool) -> 'a list -> bool * 'a list
+val exclude_with_fact : ('a -> bool) -> 'a list -> 'a option * 'a list
+val exclude_with_fact2 :
+ ('a -> bool) -> ('a -> bool) -> 'a list -> 'a option * 'a option * 'a list
+val same_length : 'a list -> 'b list -> bool
+
+val init : int -> (int -> 'a) -> 'a list
+
+val take : int -> 'a list -> 'a list * 'a list
+val try_take : int -> 'a list -> 'a list * int * 'a list
+
+val exclude_tail : 'a list -> 'a * 'a list
+
+val length_compare : 'a list -> int -> [`Gt | `Eq | `Lt ]
+
+(**
+
+ {[length xs = length ys + n ]}
+ input n should be positive
+ TODO: input checking
+*)
+
+val length_larger_than_n :
+ int -> 'a list -> 'a list -> bool
+
+val filter_map2 : ('a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list
+
+val filter_map2i : (int -> 'a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list
+
+val filter_mapi : (int -> 'a -> 'b option) -> 'a list -> 'b list
+
+val flat_map2 : ('a -> 'b -> 'c list) -> 'a list -> 'b list -> 'c list
+
+val flat_map_acc : ('a -> 'b list) -> 'b list -> 'a list -> 'b list
+val flat_map : ('a -> 'b list) -> 'a list -> 'b list
+
+
+(** for the last element the first element will be passed [true] *)
val fold_right2_last : (bool -> 'a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c
@@ -10560,239 +11081,6 @@ let suites =
end
]
-end
-module Ext_pervasives : sig
-#1 "ext_pervasives.mli"
-(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * In addition to the permissions granted to you by the LGPL, you may combine
- * or link a "work that uses the Library" with a publicly distributed version
- * of this file to produce a combined library or application, then distribute
- * that combined work under the terms of your choosing, with no requirement
- * to comply with the obligations normally placed on you by section 4 of the
- * LGPL version 3 (or the corresponding section of a later version of the LGPL
- * should you choose to use a later version).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-
-
-
-
-
-
-
-
-(** Extension to standard library [Pervavives] module, safe to open
- *)
-
-external reraise: exn -> 'a = "%reraise"
-
-val finally : 'a -> ('a -> 'c) -> ('a -> 'b) -> 'b
-
-val with_file_as_chan : string -> (out_channel -> 'a) -> 'a
-
-val with_file_as_pp : string -> (Format.formatter -> 'a) -> 'a
-
-val is_pos_pow : Int32.t -> int
-
-val failwithf : loc:string -> ('a, unit, string, 'b) format4 -> 'a
-
-val invalid_argf : ('a, unit, string, 'b) format4 -> 'a
-
-val bad_argf : ('a, unit, string, 'b) format4 -> 'a
-
-
-
-val dump : 'a -> string
-val pp_any : Format.formatter -> 'a -> unit
-external id : 'a -> 'a = "%identity"
-
-(** Copied from {!Btype.hash_variant}:
- need sync up and add test case
- *)
-val hash_variant : string -> int
-
-end = struct
-#1 "ext_pervasives.ml"
-(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * In addition to the permissions granted to you by the LGPL, you may combine
- * or link a "work that uses the Library" with a publicly distributed version
- * of this file to produce a combined library or application, then distribute
- * that combined work under the terms of your choosing, with no requirement
- * to comply with the obligations normally placed on you by section 4 of the
- * LGPL version 3 (or the corresponding section of a later version of the LGPL
- * should you choose to use a later version).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-
-
-
-
-
-
-external reraise: exn -> 'a = "%reraise"
-
-let finally v action f =
- (* 0 *) match f v with
- | exception e ->
- (* 0 *) action v ;
- reraise e
- | e -> (* 0 *) action v ; e
-
-let with_file_as_chan filename f =
- (* 0 *) finally (open_out_bin filename) close_out f
-
-let with_file_as_pp filename f =
- (* 0 *) finally (open_out_bin filename) close_out
- (fun chan ->
- (* 0 *) let fmt = Format.formatter_of_out_channel chan in
- let v = f fmt in
- Format.pp_print_flush fmt ();
- v
- )
-
-
-let is_pos_pow n =
- (* 0 *) let module M = struct exception E end in
- let rec aux c (n : Int32.t) =
- (* 0 *) if n <= 0l then (* 0 *) -2
- else (* 0 *) if n = 1l then (* 0 *) c
- else (* 0 *) if Int32.logand n 1l = 0l then
- (* 0 *) aux (c + 1) (Int32.shift_right n 1 )
- else (* 0 *) raise M.E in
- try aux 0 n with M.E -> (* 0 *) -1
-
-let failwithf ~loc fmt = (* 0 *) Format.ksprintf (fun s -> (* 0 *) failwith (loc ^ s))
- fmt
-
-let invalid_argf fmt = (* 0 *) Format.ksprintf invalid_arg fmt
-
-let bad_argf fmt = (* 0 *) Format.ksprintf (fun x -> (* 0 *) raise (Arg.Bad x ) ) fmt
-
-
-let rec dump r =
- (* 0 *) if Obj.is_int r then
- (* 0 *) string_of_int (Obj.magic r : int)
- else (* Block. *)
- (* 0 *) let rec get_fields acc = function
- | 0 -> (* 0 *) acc
- | n -> (* 0 *) let n = n-1 in get_fields (Obj.field r n :: acc) n
- in
- let rec is_list r =
- (* 0 *) if Obj.is_int r then
- (* 0 *) r = Obj.repr 0 (* [] *)
- else
- (* 0 *) let s = Obj.size r and t = Obj.tag r in
- t = 0 && s = 2 && is_list (Obj.field r 1) (* h :: t *)
- in
- let rec get_list r =
- (* 0 *) if Obj.is_int r then
- (* 0 *) []
- else
- (* 0 *) let h = Obj.field r 0 and t = get_list (Obj.field r 1) in
- h :: t
- in
- let opaque name =
- (* XXX In future, print the address of value 'r'. Not possible
- * in pure OCaml at the moment. *)
- (* 0 *) "<" ^ name ^ ">"
- in
- let s = Obj.size r and t = Obj.tag r in
- (* From the tag, determine the type of block. *)
- match t with
- | _ when (* 0 *) is_list r ->
- (* 0 *) let fields = get_list r in
- "[" ^ String.concat "; " (List.map dump fields) ^ "]"
- | 0 ->
- (* 0 *) let fields = get_fields [] s in
- "(" ^ String.concat ", " (List.map dump fields) ^ ")"
- | x when (* 0 *) x = Obj.lazy_tag ->
- (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not
- * clear if very large constructed values could have the same
- * tag. XXX *)
- (* 0 *) opaque "lazy"
- | x when (* 0 *) x = Obj.closure_tag ->
- (* 0 *) opaque "closure"
- | x when (* 0 *) x = Obj.object_tag ->
- (* 0 *) let fields = get_fields [] s in
- let _clasz, id, slots =
- match fields with
- | h::h'::t -> (* 0 *) h, h', t
- | _ -> (* 0 *) assert false
- in
- (* No information on decoding the class (first field). So just print
- * out the ID and the slots. *)
- "Object #" ^ dump id ^ " (" ^ String.concat ", " (List.map dump slots) ^ ")"
- | x when (* 0 *) x = Obj.infix_tag ->
- (* 0 *) opaque "infix"
- | x when (* 0 *) x = Obj.forward_tag ->
- (* 0 *) opaque "forward"
- | x when (* 0 *) x < Obj.no_scan_tag ->
- (* 0 *) let fields = get_fields [] s in
- "Tag" ^ string_of_int t ^
- " (" ^ String.concat ", " (List.map dump fields) ^ ")"
- | x when (* 0 *) x = Obj.string_tag ->
- (* 0 *) "\"" ^ String.escaped (Obj.magic r : string) ^ "\""
- | x when (* 0 *) x = Obj.double_tag ->
- (* 0 *) string_of_float (Obj.magic r : float)
- | x when (* 0 *) x = Obj.abstract_tag ->
- (* 0 *) opaque "abstract"
- | x when (* 0 *) x = Obj.custom_tag ->
- (* 0 *) opaque "custom"
- | x when (* 0 *) x = Obj.custom_tag ->
- (* 0 *) opaque "final"
- | x when (* 0 *) x = Obj.double_array_tag ->
- (* 0 *) "[|"^
- String.concat ";"
- (Array.to_list (Array.map string_of_float (Obj.magic r : float array))) ^
- "|]"
- | _ ->
- (* 0 *) opaque (Printf.sprintf "unknown: tag %d size %d" t s)
-
-let dump v = (* 0 *) dump (Obj.repr v)
-
-let pp_any fmt v =
- (* 0 *) Format.fprintf fmt "@[%s@]"
- (dump v )
-external id : 'a -> 'a = "%identity"
-
-
-let hash_variant s =
- (* 0 *) let accu = ref 0 in
- for i = 0 to String.length s - 1 do
- (* 0 *) accu := 223 * !accu + Char.code s.[i]
- done;
- (* reduce to 31 bits *)
- accu := !accu land (1 lsl 31 - 1);
- (* make it signed for 64 bits architectures *)
- if !accu > 0x3FFFFFFF then (* 0 *) !accu - (1 lsl 31) else (* 0 *) !accu
-
-
end
module Ext_filename : sig
#1 "ext_filename.mli"
@@ -13197,8 +13485,8 @@ let suites =
__LOC__ >:: begin fun _ ->
(* 1 *) OUnit.assert_bool __LOC__ @@
- List.for_all (fun x -> (* 10 *) Ext_string.is_valid_source_name x = Good)
- ["x.ml"; "x.mli"; "x.re"; "x.rei"; "x.mll";
+ List.for_all (fun x -> (* 9 *) Ext_string.is_valid_source_name x = Good)
+ ["x.ml"; "x.mli"; "x.re"; "x.rei";
"A_x.ml"; "ab.ml"; "a_.ml"; "a__.ml";
"ax.ml"];
OUnit.assert_bool __LOC__ @@ not @@
diff --git a/jscomp/bin/all_ounit_tests.ml b/jscomp/bin/all_ounit_tests.ml
index a6c9297f24..9f1088b5e6 100644
--- a/jscomp/bin/all_ounit_tests.ml
+++ b/jscomp/bin/all_ounit_tests.ml
@@ -1320,6 +1320,12 @@ val find_and_split :
val exists : ('a -> bool) -> 'a array -> bool
val is_empty : 'a array -> bool
+
+val for_all2_no_exn :
+ ('a -> 'b -> bool) ->
+ 'a array ->
+ 'b array ->
+ bool
end = struct
#1 "ext_array.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
@@ -1508,6 +1514,21 @@ let exists p a =
let is_empty arr =
Array.length arr = 0
+
+
+let rec unsafe_loop index len p xs ys =
+ if index >= len then true
+ else
+ p
+ (Array.unsafe_get xs index)
+ (Array.unsafe_get ys index) &&
+ unsafe_loop (succ index) len p xs ys
+
+let for_all2_no_exn p xs ys =
+ let len_xs = Array.length xs in
+ let len_ys = Array.length ys in
+ len_xs = len_ys &&
+ unsafe_loop 0 len_xs p xs ys
end
module Ext_bytes : sig
#1 "ext_bytes.mli"
@@ -2143,7 +2164,8 @@ let is_valid_source_name name : check_result =
match check_any_suffix_case_then_chop name [
".ml";
".re";
- ".mli"; ".mll"; ".rei"
+ ".mli";
+ ".rei"
] with
| None -> Suffix_mismatch
| Some x ->
@@ -2342,6 +2364,34 @@ let suites =
[|1;2;3;4;5;6|] []
=~ [2;4;6]
end;
+
+ __LOC__ >:: begin fun _ ->
+ OUnit.assert_bool __LOC__
+ (Ext_array.for_all2_no_exn
+ (=)
+ [|1;2;3|]
+ [|1;2;3|]
+ )
+ end;
+ __LOC__ >:: begin fun _ ->
+ OUnit.assert_bool __LOC__
+ (Ext_array.for_all2_no_exn
+ (=) [||] [||]
+ );
+ OUnit.assert_bool __LOC__
+ (not @@ Ext_array.for_all2_no_exn
+ (=) [||] [|1|]
+ )
+ end
+ ;
+ __LOC__ >:: begin fun _ ->
+ OUnit.assert_bool __LOC__
+ (not (Ext_array.for_all2_no_exn
+ (=)
+ [|1;2;3|]
+ [|1;2;33|]
+ ))
+ end
]
end
module Ounit_tests_util
@@ -8661,9 +8711,32 @@ val query : path -> Ext_json_types.t -> status
val loc_of : Ext_json_types.t -> Ext_position.t
+val equal : Ext_json_types.t -> Ext_json_types.t -> bool
end = struct
#1 "ext_json.ml"
-
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
type callback =
[
@@ -8679,7 +8752,7 @@ type callback =
| `Id of (Ext_json_types.t -> unit )
]
-
+
type path = string list
type status =
@@ -8689,26 +8762,26 @@ type status =
let test ?(fail=(fun () -> ())) key
(cb : callback) (m : Ext_json_types.t String_map.t)
- =
- begin match String_map.find_exn key m, cb with
- | exception Not_found ->
- begin match cb with `Not_found f -> f ()
- | _ -> fail ()
- end
- | True _, `Bool cb -> cb true
- | False _, `Bool cb -> cb false
- | Flo {flo = s} , `Flo cb -> cb s
- | Obj {map = b} , `Obj cb -> cb b
- | Arr {content}, `Arr cb -> cb content
- | Arr {content; loc_start ; loc_end}, `Arr_loc cb ->
- cb content loc_start loc_end
- | Null _, `Null cb -> cb ()
- | Str {str = s }, `Str cb -> cb s
- | Str {str = s ; loc }, `Str_loc cb -> cb s loc
- | any , `Id cb -> cb any
- | _, _ -> fail ()
- end;
- m
+ =
+ begin match String_map.find_exn key m, cb with
+ | exception Not_found ->
+ begin match cb with `Not_found f -> f ()
+ | _ -> fail ()
+ end
+ | True _, `Bool cb -> cb true
+ | False _, `Bool cb -> cb false
+ | Flo {flo = s} , `Flo cb -> cb s
+ | Obj {map = b} , `Obj cb -> cb b
+ | Arr {content}, `Arr cb -> cb content
+ | Arr {content; loc_start ; loc_end}, `Arr_loc cb ->
+ cb content loc_start loc_end
+ | Null _, `Null cb -> cb ()
+ | Str {str = s }, `Str cb -> cb s
+ | Str {str = s ; loc }, `Str_loc cb -> cb s loc
+ | any , `Id cb -> cb any
+ | _, _ -> fail ()
+ end;
+ m
let query path (json : Ext_json_types.t ) =
let rec aux acc paths json =
match path with
@@ -8732,7 +8805,53 @@ let loc_of (x : Ext_json_types.t) =
| Arr p -> p.loc_start
| Obj p -> p.loc
| Flo p -> p.loc
-
+
+
+let rec equal
+ (x : Ext_json_types.t)
+ (y : Ext_json_types.t) =
+ match x with
+ | Null _ -> (* [%p? Null _ ] *)
+ begin match y with
+ | Null _ -> true
+ | _ -> false end
+ | Str {str } ->
+ begin match y with
+ | Str {str = str2} -> str = str2
+ | _ -> false end
+ | Flo {flo}
+ ->
+ begin match y with
+ | Flo {flo = flo2} ->
+ flo = flo2
+ | _ -> false
+ end
+ | True _ ->
+ begin match y with
+ | True _ -> true
+ | _ -> false
+ end
+ | False _ ->
+ begin match y with
+ | False _ -> true
+ | _ -> false
+ end
+ | Arr {content}
+ ->
+ begin match y with
+ | Arr {content = content2}
+ ->
+ Ext_array.for_all2_no_exn equal content content2
+ | _ -> false
+ end
+
+ | Obj {map} ->
+ begin match y with
+ | Obj { map = map2} ->
+ String_map.equal equal map map2
+ | _ -> false
+ end
+
end
module Ext_json_parse : sig
@@ -9472,83 +9591,128 @@ let parse_json_from_file s =
# 694 "ext/ext_json_parse.ml"
end
-module Ounit_json_tests
-= struct
-#1 "ounit_json_tests.ml"
+module Ext_json_write : sig
+#1 "ext_json_write.mli"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-let ((>::),
- (>:::)) = OUnit.((>::),(>:::))
-open Ext_json_parse
-let (|?) m (key, cb) =
- m |> Ext_json.test key cb
+val to_string : Ext_json_types.t -> string
-exception Parse_error
-let suites =
- __FILE__
- >:::
- [
- "empty_json" >:: begin fun _ ->
- let v =parse_json_from_string "{}" in
- match v with
- | Obj {map = v} -> OUnit.assert_equal (String_map.is_empty v ) true
- | _ -> OUnit.assert_failure "should be empty"
- end
- ;
- "empty_arr" >:: begin fun _ ->
- let v =parse_json_from_string "[]" in
- match v with
- | Arr {content = [||]} -> ()
- | _ -> OUnit.assert_failure "should be empty"
- end
- ;
- "empty trails" >:: begin fun _ ->
- (OUnit.assert_raises Parse_error @@ fun _ ->
- try parse_json_from_string {| [,]|} with _ -> raise Parse_error);
- OUnit.assert_raises Parse_error @@ fun _ ->
- try parse_json_from_string {| {,}|} with _ -> raise Parse_error
- end;
- "two trails" >:: begin fun _ ->
- (OUnit.assert_raises Parse_error @@ fun _ ->
- try parse_json_from_string {| [1,2,,]|} with _ -> raise Parse_error);
- (OUnit.assert_raises Parse_error @@ fun _ ->
- try parse_json_from_string {| { "x": 3, ,}|} with _ -> raise Parse_error)
- end;
- "two trails fail" >:: begin fun _ ->
- (OUnit.assert_raises Parse_error @@ fun _ ->
- try parse_json_from_string {| { "x": 3, 2 ,}|} with _ -> raise Parse_error)
- end;
+val to_channel : out_channel -> Ext_json_types.t -> unit
+end = struct
+#1 "ext_json_write.ml"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
- "trail comma obj" >:: begin fun _ ->
- let v = parse_json_from_string {| { "x" : 3 , }|} in
- let v1 = parse_json_from_string {| { "x" : 3 , }|} in
- let test (v : Ext_json_types.t) =
- match v with
- | Obj {map = v} ->
- v
- |? ("x" , `Flo (fun x -> OUnit.assert_equal x "3"))
- |> ignore
- | _ -> OUnit.assert_failure "trail comma" in
- test v ;
- test v1
- end
- ;
- "trail comma arr" >:: begin fun _ ->
- let v = parse_json_from_string {| [ 1, 3, ]|} in
- let v1 = parse_json_from_string {| [ 1, 3 ]|} in
- let test (v : Ext_json_types.t) =
- match v with
- | Arr { content = [| Flo {flo = "1"} ; Flo { flo = "3"} |] } -> ()
- | _ -> OUnit.assert_failure "trailing comma array" in
- test v ;
- test v1
+(** poor man's serialization *)
+
+let quot x =
+ "\"" ^ String.escaped x ^ "\""
+
+let rec encode_aux (x : Ext_json_types.t )
+ (buf : Buffer.t) : unit =
+ let a str = Buffer.add_string buf str in
+ match x with
+ | Null _ -> a "null"
+ | Str {str = s } -> a (quot s)
+ | Flo {flo = s} ->
+ a s (* since our parsing keep the original float representation, we just dump it as is, there is no cases like [nan] *)
+ | Arr {content} ->
+ begin match content with
+ | [||] -> a "[]"
+ | _ ->
+ a "[ ";
+ encode_aux
+ (Array.unsafe_get content 0)
+ buf ;
+ for i = 1 to Array.length content - 1 do
+ a " , ";
+ encode_aux
+ (Array.unsafe_get content i)
+ buf
+ done;
+ a " ]"
end
- ]
+ | True _ -> a "true"
+ | False _ -> a "false"
+ | Obj {map} ->
+ if String_map.is_empty map then
+ a "{}"
+ else
+ begin
+ (*prerr_endline "WEIRD";
+ prerr_endline (string_of_int @@ String_map.cardinal map ); *)
+ a "{ ";
+ let _ : int = String_map.fold (fun k v i ->
+ if i <> 0 then begin
+ a " , "
+ end;
+ a (quot k);
+ a " : ";
+ encode_aux v buf ;
+ i + 1
+ ) map 0 in
+ a " }"
+ end
+
+
+let to_string (x : Ext_json_types.t) =
+ let buf = Buffer.create 1024 in
+ encode_aux x buf ;
+ Buffer.contents buf
+
+let to_channel (oc : out_channel) x =
+ let buf = Buffer.create 1024 in
+ encode_aux x buf ;
+ Buffer.output_buffer oc buf
end
-module Ext_list : sig
-#1 "ext_list.mli"
+module Ext_pervasives : sig
+#1 "ext_pervasives.mli"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
*
* This program is free software: you can redistribute it and/or modify
@@ -9580,50 +9744,408 @@ module Ext_list : sig
-(** Extension to the standard library [List] module *)
-
-(** TODO some function are no efficiently implemented. *)
+(** Extension to standard library [Pervavives] module, safe to open
+ *)
-val filter_map : ('a -> 'b option) -> 'a list -> 'b list
+external reraise: exn -> 'a = "%reraise"
-val excludes : ('a -> bool) -> 'a list -> bool * 'a list
-val exclude_with_fact : ('a -> bool) -> 'a list -> 'a option * 'a list
-val exclude_with_fact2 :
- ('a -> bool) -> ('a -> bool) -> 'a list -> 'a option * 'a option * 'a list
-val same_length : 'a list -> 'b list -> bool
+val finally : 'a -> ('a -> 'c) -> ('a -> 'b) -> 'b
-val init : int -> (int -> 'a) -> 'a list
+val with_file_as_chan : string -> (out_channel -> 'a) -> 'a
-val take : int -> 'a list -> 'a list * 'a list
-val try_take : int -> 'a list -> 'a list * int * 'a list
+val with_file_as_pp : string -> (Format.formatter -> 'a) -> 'a
-val exclude_tail : 'a list -> 'a * 'a list
+val is_pos_pow : Int32.t -> int
-val length_compare : 'a list -> int -> [`Gt | `Eq | `Lt ]
+val failwithf : loc:string -> ('a, unit, string, 'b) format4 -> 'a
-(**
+val invalid_argf : ('a, unit, string, 'b) format4 -> 'a
- {[length xs = length ys + n ]}
- input n should be positive
- TODO: input checking
-*)
+val bad_argf : ('a, unit, string, 'b) format4 -> 'a
-val length_larger_than_n :
- int -> 'a list -> 'a list -> bool
-val filter_map2 : ('a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list
-val filter_map2i : (int -> 'a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list
+val dump : 'a -> string
+val pp_any : Format.formatter -> 'a -> unit
+external id : 'a -> 'a = "%identity"
-val filter_mapi : (int -> 'a -> 'b option) -> 'a list -> 'b list
+(** Copied from {!Btype.hash_variant}:
+ need sync up and add test case
+ *)
+val hash_variant : string -> int
-val flat_map2 : ('a -> 'b -> 'c list) -> 'a list -> 'b list -> 'c list
+end = struct
+#1 "ext_pervasives.ml"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-val flat_map_acc : ('a -> 'b list) -> 'b list -> 'a list -> 'b list
-val flat_map : ('a -> 'b list) -> 'a list -> 'b list
-(** for the last element the first element will be passed [true] *)
+
+
+
+external reraise: exn -> 'a = "%reraise"
+
+let finally v action f =
+ match f v with
+ | exception e ->
+ action v ;
+ reraise e
+ | e -> action v ; e
+
+let with_file_as_chan filename f =
+ finally (open_out_bin filename) close_out f
+
+let with_file_as_pp filename f =
+ finally (open_out_bin filename) close_out
+ (fun chan ->
+ let fmt = Format.formatter_of_out_channel chan in
+ let v = f fmt in
+ Format.pp_print_flush fmt ();
+ v
+ )
+
+
+let is_pos_pow n =
+ let module M = struct exception E end in
+ let rec aux c (n : Int32.t) =
+ if n <= 0l then -2
+ else if n = 1l then c
+ else if Int32.logand n 1l = 0l then
+ aux (c + 1) (Int32.shift_right n 1 )
+ else raise M.E in
+ try aux 0 n with M.E -> -1
+
+let failwithf ~loc fmt = Format.ksprintf (fun s -> failwith (loc ^ s))
+ fmt
+
+let invalid_argf fmt = Format.ksprintf invalid_arg fmt
+
+let bad_argf fmt = Format.ksprintf (fun x -> raise (Arg.Bad x ) ) fmt
+
+
+let rec dump r =
+ if Obj.is_int r then
+ string_of_int (Obj.magic r : int)
+ else (* Block. *)
+ let rec get_fields acc = function
+ | 0 -> acc
+ | n -> let n = n-1 in get_fields (Obj.field r n :: acc) n
+ in
+ let rec is_list r =
+ if Obj.is_int r then
+ r = Obj.repr 0 (* [] *)
+ else
+ let s = Obj.size r and t = Obj.tag r in
+ t = 0 && s = 2 && is_list (Obj.field r 1) (* h :: t *)
+ in
+ let rec get_list r =
+ if Obj.is_int r then
+ []
+ else
+ let h = Obj.field r 0 and t = get_list (Obj.field r 1) in
+ h :: t
+ in
+ let opaque name =
+ (* XXX In future, print the address of value 'r'. Not possible
+ * in pure OCaml at the moment. *)
+ "<" ^ name ^ ">"
+ in
+ let s = Obj.size r and t = Obj.tag r in
+ (* From the tag, determine the type of block. *)
+ match t with
+ | _ when is_list r ->
+ let fields = get_list r in
+ "[" ^ String.concat "; " (List.map dump fields) ^ "]"
+ | 0 ->
+ let fields = get_fields [] s in
+ "(" ^ String.concat ", " (List.map dump fields) ^ ")"
+ | x when x = Obj.lazy_tag ->
+ (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not
+ * clear if very large constructed values could have the same
+ * tag. XXX *)
+ opaque "lazy"
+ | x when x = Obj.closure_tag ->
+ opaque "closure"
+ | x when x = Obj.object_tag ->
+ let fields = get_fields [] s in
+ let _clasz, id, slots =
+ match fields with
+ | h::h'::t -> h, h', t
+ | _ -> assert false
+ in
+ (* No information on decoding the class (first field). So just print
+ * out the ID and the slots. *)
+ "Object #" ^ dump id ^ " (" ^ String.concat ", " (List.map dump slots) ^ ")"
+ | x when x = Obj.infix_tag ->
+ opaque "infix"
+ | x when x = Obj.forward_tag ->
+ opaque "forward"
+ | x when x < Obj.no_scan_tag ->
+ let fields = get_fields [] s in
+ "Tag" ^ string_of_int t ^
+ " (" ^ String.concat ", " (List.map dump fields) ^ ")"
+ | x when x = Obj.string_tag ->
+ "\"" ^ String.escaped (Obj.magic r : string) ^ "\""
+ | x when x = Obj.double_tag ->
+ string_of_float (Obj.magic r : float)
+ | x when x = Obj.abstract_tag ->
+ opaque "abstract"
+ | x when x = Obj.custom_tag ->
+ opaque "custom"
+ | x when x = Obj.custom_tag ->
+ opaque "final"
+ | x when x = Obj.double_array_tag ->
+ "[|"^
+ String.concat ";"
+ (Array.to_list (Array.map string_of_float (Obj.magic r : float array))) ^
+ "|]"
+ | _ ->
+ opaque (Printf.sprintf "unknown: tag %d size %d" t s)
+
+let dump v = dump (Obj.repr v)
+
+let pp_any fmt v =
+ Format.fprintf fmt "@[%s@]"
+ (dump v )
+external id : 'a -> 'a = "%identity"
+
+
+let hash_variant s =
+ let accu = ref 0 in
+ for i = 0 to String.length s - 1 do
+ accu := 223 * !accu + Char.code s.[i]
+ done;
+ (* reduce to 31 bits *)
+ accu := !accu land (1 lsl 31 - 1);
+ (* make it signed for 64 bits architectures *)
+ if !accu > 0x3FFFFFFF then !accu - (1 lsl 31) else !accu
+
+
+end
+module Ounit_json_tests
+= struct
+#1 "ounit_json_tests.ml"
+
+let ((>::),
+ (>:::)) = OUnit.((>::),(>:::))
+
+open Ext_json_parse
+let (|?) m (key, cb) =
+ m |> Ext_json.test key cb
+
+let id_parsing_serializing x =
+ let normal_s =
+ Ext_json_write.to_string ( Ext_json_parse.parse_json_from_string x )
+ in
+ let normal_ss =
+ Ext_json_write.to_string
+ (Ext_json_parse.parse_json_from_string normal_s)
+ in
+ if normal_s <> normal_ss then
+ begin
+ prerr_endline "ERROR";
+ prerr_endline normal_s ;
+ prerr_endline normal_ss ;
+ end;
+ OUnit.assert_equal ~cmp:(fun (x:string) y -> x = y) normal_s normal_ss
+
+let id_parsing_x2 x =
+ let stru = Ext_json_parse.parse_json_from_string x in
+ let normal_s = Ext_json_write.to_string stru in
+ let normal_ss = (Ext_json_parse.parse_json_from_string normal_s) in
+ if Ext_json.equal stru normal_ss then
+ true
+ else begin
+ prerr_endline "ERROR";
+ prerr_endline normal_s;
+ Format.fprintf Format.err_formatter
+ "%a@.%a@." Ext_pervasives.pp_any stru Ext_pervasives.pp_any normal_ss;
+
+ prerr_endline (Ext_json_write.to_string normal_ss);
+ false
+ end
+
+let test_data =
+ [{|
+ {}
+ |};
+ {| [] |};
+ {| [1,2,3]|};
+ {| ["x", "y", 1,2,3 ]|};
+ {| { "x" : 3, "y" : "x", "z" : [1,2,3, "x"] }|};
+ {| {"x " : true , "y" : false , "z\"" : 1} |}
+ ]
+exception Parse_error
+let suites =
+ __FILE__
+ >:::
+ [
+
+ __LOC__ >:: begin fun _ ->
+ List.iter id_parsing_serializing test_data
+ end;
+
+ __LOC__ >:: begin fun _ ->
+ List.iteri (fun i x -> OUnit.assert_bool (__LOC__ ^ string_of_int i ) (id_parsing_x2 x)) test_data
+ end;
+ "empty_json" >:: begin fun _ ->
+ let v =parse_json_from_string "{}" in
+ match v with
+ | Obj {map = v} -> OUnit.assert_equal (String_map.is_empty v ) true
+ | _ -> OUnit.assert_failure "should be empty"
+ end
+ ;
+ "empty_arr" >:: begin fun _ ->
+ let v =parse_json_from_string "[]" in
+ match v with
+ | Arr {content = [||]} -> ()
+ | _ -> OUnit.assert_failure "should be empty"
+ end
+ ;
+ "empty trails" >:: begin fun _ ->
+ (OUnit.assert_raises Parse_error @@ fun _ ->
+ try parse_json_from_string {| [,]|} with _ -> raise Parse_error);
+ OUnit.assert_raises Parse_error @@ fun _ ->
+ try parse_json_from_string {| {,}|} with _ -> raise Parse_error
+ end;
+ "two trails" >:: begin fun _ ->
+ (OUnit.assert_raises Parse_error @@ fun _ ->
+ try parse_json_from_string {| [1,2,,]|} with _ -> raise Parse_error);
+ (OUnit.assert_raises Parse_error @@ fun _ ->
+ try parse_json_from_string {| { "x": 3, ,}|} with _ -> raise Parse_error)
+ end;
+
+ "two trails fail" >:: begin fun _ ->
+ (OUnit.assert_raises Parse_error @@ fun _ ->
+ try parse_json_from_string {| { "x": 3, 2 ,}|} with _ -> raise Parse_error)
+ end;
+
+ "trail comma obj" >:: begin fun _ ->
+ let v = parse_json_from_string {| { "x" : 3 , }|} in
+ let v1 = parse_json_from_string {| { "x" : 3 , }|} in
+ let test (v : Ext_json_types.t) =
+ match v with
+ | Obj {map = v} ->
+ v
+ |? ("x" , `Flo (fun x -> OUnit.assert_equal x "3"))
+ |> ignore
+ | _ -> OUnit.assert_failure "trail comma" in
+ test v ;
+ test v1
+ end
+ ;
+ "trail comma arr" >:: begin fun _ ->
+ let v = parse_json_from_string {| [ 1, 3, ]|} in
+ let v1 = parse_json_from_string {| [ 1, 3 ]|} in
+ let test (v : Ext_json_types.t) =
+ match v with
+ | Arr { content = [| Flo {flo = "1"} ; Flo { flo = "3"} |] } -> ()
+ | _ -> OUnit.assert_failure "trailing comma array" in
+ test v ;
+ test v1
+ end
+ ]
+
+end
+module Ext_list : sig
+#1 "ext_list.mli"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+
+
+
+
+
+
+
+
+(** Extension to the standard library [List] module *)
+
+(** TODO some function are no efficiently implemented. *)
+
+val filter_map : ('a -> 'b option) -> 'a list -> 'b list
+
+val excludes : ('a -> bool) -> 'a list -> bool * 'a list
+val exclude_with_fact : ('a -> bool) -> 'a list -> 'a option * 'a list
+val exclude_with_fact2 :
+ ('a -> bool) -> ('a -> bool) -> 'a list -> 'a option * 'a option * 'a list
+val same_length : 'a list -> 'b list -> bool
+
+val init : int -> (int -> 'a) -> 'a list
+
+val take : int -> 'a list -> 'a list * 'a list
+val try_take : int -> 'a list -> 'a list * int * 'a list
+
+val exclude_tail : 'a list -> 'a * 'a list
+
+val length_compare : 'a list -> int -> [`Gt | `Eq | `Lt ]
+
+(**
+
+ {[length xs = length ys + n ]}
+ input n should be positive
+ TODO: input checking
+*)
+
+val length_larger_than_n :
+ int -> 'a list -> 'a list -> bool
+
+val filter_map2 : ('a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list
+
+val filter_map2i : (int -> 'a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list
+
+val filter_mapi : (int -> 'a -> 'b option) -> 'a list -> 'b list
+
+val flat_map2 : ('a -> 'b -> 'c list) -> 'a list -> 'b list -> 'c list
+
+val flat_map_acc : ('a -> 'b list) -> 'b list -> 'a list -> 'b list
+val flat_map : ('a -> 'b list) -> 'a list -> 'b list
+
+
+(** for the last element the first element will be passed [true] *)
val fold_right2_last : (bool -> 'a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c
@@ -10560,239 +11082,6 @@ let suites =
end
]
-end
-module Ext_pervasives : sig
-#1 "ext_pervasives.mli"
-(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * In addition to the permissions granted to you by the LGPL, you may combine
- * or link a "work that uses the Library" with a publicly distributed version
- * of this file to produce a combined library or application, then distribute
- * that combined work under the terms of your choosing, with no requirement
- * to comply with the obligations normally placed on you by section 4 of the
- * LGPL version 3 (or the corresponding section of a later version of the LGPL
- * should you choose to use a later version).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-
-
-
-
-
-
-
-
-(** Extension to standard library [Pervavives] module, safe to open
- *)
-
-external reraise: exn -> 'a = "%reraise"
-
-val finally : 'a -> ('a -> 'c) -> ('a -> 'b) -> 'b
-
-val with_file_as_chan : string -> (out_channel -> 'a) -> 'a
-
-val with_file_as_pp : string -> (Format.formatter -> 'a) -> 'a
-
-val is_pos_pow : Int32.t -> int
-
-val failwithf : loc:string -> ('a, unit, string, 'b) format4 -> 'a
-
-val invalid_argf : ('a, unit, string, 'b) format4 -> 'a
-
-val bad_argf : ('a, unit, string, 'b) format4 -> 'a
-
-
-
-val dump : 'a -> string
-val pp_any : Format.formatter -> 'a -> unit
-external id : 'a -> 'a = "%identity"
-
-(** Copied from {!Btype.hash_variant}:
- need sync up and add test case
- *)
-val hash_variant : string -> int
-
-end = struct
-#1 "ext_pervasives.ml"
-(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * In addition to the permissions granted to you by the LGPL, you may combine
- * or link a "work that uses the Library" with a publicly distributed version
- * of this file to produce a combined library or application, then distribute
- * that combined work under the terms of your choosing, with no requirement
- * to comply with the obligations normally placed on you by section 4 of the
- * LGPL version 3 (or the corresponding section of a later version of the LGPL
- * should you choose to use a later version).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-
-
-
-
-
-
-external reraise: exn -> 'a = "%reraise"
-
-let finally v action f =
- match f v with
- | exception e ->
- action v ;
- reraise e
- | e -> action v ; e
-
-let with_file_as_chan filename f =
- finally (open_out_bin filename) close_out f
-
-let with_file_as_pp filename f =
- finally (open_out_bin filename) close_out
- (fun chan ->
- let fmt = Format.formatter_of_out_channel chan in
- let v = f fmt in
- Format.pp_print_flush fmt ();
- v
- )
-
-
-let is_pos_pow n =
- let module M = struct exception E end in
- let rec aux c (n : Int32.t) =
- if n <= 0l then -2
- else if n = 1l then c
- else if Int32.logand n 1l = 0l then
- aux (c + 1) (Int32.shift_right n 1 )
- else raise M.E in
- try aux 0 n with M.E -> -1
-
-let failwithf ~loc fmt = Format.ksprintf (fun s -> failwith (loc ^ s))
- fmt
-
-let invalid_argf fmt = Format.ksprintf invalid_arg fmt
-
-let bad_argf fmt = Format.ksprintf (fun x -> raise (Arg.Bad x ) ) fmt
-
-
-let rec dump r =
- if Obj.is_int r then
- string_of_int (Obj.magic r : int)
- else (* Block. *)
- let rec get_fields acc = function
- | 0 -> acc
- | n -> let n = n-1 in get_fields (Obj.field r n :: acc) n
- in
- let rec is_list r =
- if Obj.is_int r then
- r = Obj.repr 0 (* [] *)
- else
- let s = Obj.size r and t = Obj.tag r in
- t = 0 && s = 2 && is_list (Obj.field r 1) (* h :: t *)
- in
- let rec get_list r =
- if Obj.is_int r then
- []
- else
- let h = Obj.field r 0 and t = get_list (Obj.field r 1) in
- h :: t
- in
- let opaque name =
- (* XXX In future, print the address of value 'r'. Not possible
- * in pure OCaml at the moment. *)
- "<" ^ name ^ ">"
- in
- let s = Obj.size r and t = Obj.tag r in
- (* From the tag, determine the type of block. *)
- match t with
- | _ when is_list r ->
- let fields = get_list r in
- "[" ^ String.concat "; " (List.map dump fields) ^ "]"
- | 0 ->
- let fields = get_fields [] s in
- "(" ^ String.concat ", " (List.map dump fields) ^ ")"
- | x when x = Obj.lazy_tag ->
- (* Note that [lazy_tag .. forward_tag] are < no_scan_tag. Not
- * clear if very large constructed values could have the same
- * tag. XXX *)
- opaque "lazy"
- | x when x = Obj.closure_tag ->
- opaque "closure"
- | x when x = Obj.object_tag ->
- let fields = get_fields [] s in
- let _clasz, id, slots =
- match fields with
- | h::h'::t -> h, h', t
- | _ -> assert false
- in
- (* No information on decoding the class (first field). So just print
- * out the ID and the slots. *)
- "Object #" ^ dump id ^ " (" ^ String.concat ", " (List.map dump slots) ^ ")"
- | x when x = Obj.infix_tag ->
- opaque "infix"
- | x when x = Obj.forward_tag ->
- opaque "forward"
- | x when x < Obj.no_scan_tag ->
- let fields = get_fields [] s in
- "Tag" ^ string_of_int t ^
- " (" ^ String.concat ", " (List.map dump fields) ^ ")"
- | x when x = Obj.string_tag ->
- "\"" ^ String.escaped (Obj.magic r : string) ^ "\""
- | x when x = Obj.double_tag ->
- string_of_float (Obj.magic r : float)
- | x when x = Obj.abstract_tag ->
- opaque "abstract"
- | x when x = Obj.custom_tag ->
- opaque "custom"
- | x when x = Obj.custom_tag ->
- opaque "final"
- | x when x = Obj.double_array_tag ->
- "[|"^
- String.concat ";"
- (Array.to_list (Array.map string_of_float (Obj.magic r : float array))) ^
- "|]"
- | _ ->
- opaque (Printf.sprintf "unknown: tag %d size %d" t s)
-
-let dump v = dump (Obj.repr v)
-
-let pp_any fmt v =
- Format.fprintf fmt "@[%s@]"
- (dump v )
-external id : 'a -> 'a = "%identity"
-
-
-let hash_variant s =
- let accu = ref 0 in
- for i = 0 to String.length s - 1 do
- accu := 223 * !accu + Char.code s.[i]
- done;
- (* reduce to 31 bits *)
- accu := !accu land (1 lsl 31 - 1);
- (* make it signed for 64 bits architectures *)
- if !accu > 0x3FFFFFFF then !accu - (1 lsl 31) else !accu
-
-
end
module Ext_filename : sig
#1 "ext_filename.mli"
@@ -13198,7 +13487,7 @@ let suites =
__LOC__ >:: begin fun _ ->
OUnit.assert_bool __LOC__ @@
List.for_all (fun x -> Ext_string.is_valid_source_name x = Good)
- ["x.ml"; "x.mli"; "x.re"; "x.rei"; "x.mll";
+ ["x.ml"; "x.mli"; "x.re"; "x.rei";
"A_x.ml"; "ab.ml"; "a_.ml"; "a__.ml";
"ax.ml"];
OUnit.assert_bool __LOC__ @@ not @@
diff --git a/jscomp/bin/bsb.ml b/jscomp/bin/bsb.ml
index cc16646b74..db82f92945 100644
--- a/jscomp/bin/bsb.ml
+++ b/jscomp/bin/bsb.ml
@@ -921,7 +921,8 @@ let is_valid_source_name name : check_result =
match check_any_suffix_case_then_chop name [
".ml";
".re";
- ".mli"; ".mll"; ".rei"
+ ".mli";
+ ".rei"
] with
| None -> Suffix_mismatch
| Some x ->
@@ -2781,6 +2782,289 @@ let header =
"// Generated by BUCKLESCRIPT VERSION 1.7.5, PLEASE EDIT WITH CARE"
let package_name = "bs-platform"
+end
+module Ext_array : sig
+#1 "ext_array.mli"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+
+
+
+
+
+
+(** Some utilities for {!Array} operations *)
+val reverse_range : 'a array -> int -> int -> unit
+val reverse_in_place : 'a array -> unit
+val reverse : 'a array -> 'a array
+val reverse_of_list : 'a list -> 'a array
+
+val filter : ('a -> bool) -> 'a array -> 'a array
+
+val filter_map : ('a -> 'b option) -> 'a array -> 'b array
+
+val range : int -> int -> int array
+
+val map2i : (int -> 'a -> 'b -> 'c ) -> 'a array -> 'b array -> 'c array
+
+val to_list_map : ('a -> 'b option) -> 'a array -> 'b list
+
+val to_list_map_acc :
+ ('a -> 'b option) ->
+ 'a array ->
+ 'b list ->
+ 'b list
+
+val of_list_map : ('a -> 'b) -> 'a list -> 'b array
+
+val rfind_with_index : 'a array -> ('a -> 'b -> bool) -> 'b -> int
+
+
+type 'a split = [ `No_split | `Split of 'a array * 'a array ]
+
+val rfind_and_split :
+ 'a array ->
+ ('a -> 'b -> bool) ->
+ 'b -> 'a split
+
+val find_and_split :
+ 'a array ->
+ ('a -> 'b -> bool) ->
+ 'b -> 'a split
+
+val exists : ('a -> bool) -> 'a array -> bool
+
+val is_empty : 'a array -> bool
+
+val for_all2_no_exn :
+ ('a -> 'b -> bool) ->
+ 'a array ->
+ 'b array ->
+ bool
+end = struct
+#1 "ext_array.ml"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+
+
+
+
+
+let reverse_range a i len =
+ if len = 0 then ()
+ else
+ for k = 0 to (len-1)/2 do
+ let t = Array.unsafe_get a (i+k) in
+ Array.unsafe_set a (i+k) ( Array.unsafe_get a (i+len-1-k));
+ Array.unsafe_set a (i+len-1-k) t;
+ done
+
+
+let reverse_in_place a =
+ reverse_range a 0 (Array.length a)
+
+let reverse a =
+ let b_len = Array.length a in
+ if b_len = 0 then [||] else
+ let b = Array.copy a in
+ for i = 0 to b_len - 1 do
+ Array.unsafe_set b i (Array.unsafe_get a (b_len - 1 -i ))
+ done;
+ b
+
+let reverse_of_list = function
+ | [] -> [||]
+ | hd::tl as l ->
+ let len = List.length l in
+ let a = Array.make len hd in
+ let rec fill i = function
+ | [] -> a
+ | hd::tl -> Array.unsafe_set a (len - i - 2) hd; fill (i+1) tl in
+ fill 0 tl
+
+let filter f a =
+ let arr_len = Array.length a in
+ let rec aux acc i =
+ if i = arr_len
+ then reverse_of_list acc
+ else
+ let v = Array.unsafe_get a i in
+ if f v then
+ aux (v::acc) (i+1)
+ else aux acc (i + 1)
+ in aux [] 0
+
+
+let filter_map (f : _ -> _ option) a =
+ let arr_len = Array.length a in
+ let rec aux acc i =
+ if i = arr_len
+ then reverse_of_list acc
+ else
+ let v = Array.unsafe_get a i in
+ match f v with
+ | Some v ->
+ aux (v::acc) (i+1)
+ | None ->
+ aux acc (i + 1)
+ in aux [] 0
+
+let range from to_ =
+ if from > to_ then invalid_arg "Ext_array.range"
+ else Array.init (to_ - from + 1) (fun i -> i + from)
+
+let map2i f a b =
+ let len = Array.length a in
+ if len <> Array.length b then
+ invalid_arg "Ext_array.map2i"
+ else
+ Array.mapi (fun i a -> f i a ( Array.unsafe_get b i )) a
+
+
+ let rec tolist_aux a f i res =
+ if i < 0 then res else
+ let v = Array.unsafe_get a i in
+ tolist_aux a f (i - 1)
+ (match f v with
+ | Some v -> v :: res
+ | None -> res)
+
+let to_list_map f a =
+ tolist_aux a f (Array.length a - 1) []
+
+let to_list_map_acc f a acc =
+ tolist_aux a f (Array.length a - 1) acc
+
+
+(* TODO: What would happen if [f] raise, memory leak? *)
+let of_list_map f a =
+ match a with
+ | [] -> [||]
+ | h::tl ->
+ let hd = f h in
+ let len = List.length tl + 1 in
+ let arr = Array.make len hd in
+ let rec fill i = function
+ | [] -> arr
+ | hd :: tl ->
+ Array.unsafe_set arr i (f hd);
+ fill (i + 1) tl in
+ fill 1 tl
+
+(**
+{[
+# rfind_with_index [|1;2;3|] (=) 2;;
+- : int = 1
+# rfind_with_index [|1;2;3|] (=) 1;;
+- : int = 0
+# rfind_with_index [|1;2;3|] (=) 3;;
+- : int = 2
+# rfind_with_index [|1;2;3|] (=) 4;;
+- : int = -1
+]}
+*)
+let rfind_with_index arr cmp v =
+ let len = Array.length arr in
+ let rec aux i =
+ if i < 0 then i
+ else if cmp (Array.unsafe_get arr i) v then i
+ else aux (i - 1) in
+ aux (len - 1)
+
+type 'a split = [ `No_split | `Split of 'a array * 'a array ]
+let rfind_and_split arr cmp v : _ split =
+ let i = rfind_with_index arr cmp v in
+ if i < 0 then
+ `No_split
+ else
+ `Split (Array.sub arr 0 i , Array.sub arr (i + 1 ) (Array.length arr - i - 1 ))
+
+
+let find_with_index arr cmp v =
+ let len = Array.length arr in
+ let rec aux i len =
+ if i >= len then -1
+ else if cmp (Array.unsafe_get arr i ) v then i
+ else aux (i + 1) len in
+ aux 0 len
+
+let find_and_split arr cmp v : _ split =
+ let i = find_with_index arr cmp v in
+ if i < 0 then
+ `No_split
+ else
+ `Split (Array.sub arr 0 i, Array.sub arr (i + 1 ) (Array.length arr - i - 1))
+
+(** TODO: available since 4.03, use {!Array.exists} *)
+
+let exists p a =
+ let n = Array.length a in
+ let rec loop i =
+ if i = n then false
+ else if p (Array.unsafe_get a i) then true
+ else loop (succ i) in
+ loop 0
+
+
+let is_empty arr =
+ Array.length arr = 0
+
+
+let rec unsafe_loop index len p xs ys =
+ if index >= len then true
+ else
+ p
+ (Array.unsafe_get xs index)
+ (Array.unsafe_get ys index) &&
+ unsafe_loop (succ index) len p xs ys
+
+let for_all2_no_exn p xs ys =
+ let len_xs = Array.length xs in
+ let len_ys = Array.length ys in
+ len_xs = len_ys &&
+ unsafe_loop 0 len_xs p xs ys
end
module Map_gen
= struct
@@ -3436,233 +3720,16 @@ module Ext_position : sig
type t = Lexing.position = {
- pos_fname : string ;
- pos_lnum : int ;
- pos_bol : int ;
- pos_cnum : int
-}
-
-
-val print : Format.formatter -> t -> unit
-end = struct
-#1 "ext_position.ml"
-(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * In addition to the permissions granted to you by the LGPL, you may combine
- * or link a "work that uses the Library" with a publicly distributed version
- * of this file to produce a combined library or application, then distribute
- * that combined work under the terms of your choosing, with no requirement
- * to comply with the obligations normally placed on you by section 4 of the
- * LGPL version 3 (or the corresponding section of a later version of the LGPL
- * should you choose to use a later version).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-
-
-type t = Lexing.position = {
- pos_fname : string ;
- pos_lnum : int ;
- pos_bol : int ;
- pos_cnum : int
-}
-
-
-let print fmt (pos : t) =
- Format.fprintf fmt "(%d,%d)" pos.pos_lnum (pos.pos_cnum - pos.pos_bol)
-
-
-
-
-
-
-end
-module Ext_json : sig
-#1 "ext_json.mli"
-(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * In addition to the permissions granted to you by the LGPL, you may combine
- * or link a "work that uses the Library" with a publicly distributed version
- * of this file to produce a combined library or application, then distribute
- * that combined work under the terms of your choosing, with no requirement
- * to comply with the obligations normally placed on you by section 4 of the
- * LGPL version 3 (or the corresponding section of a later version of the LGPL
- * should you choose to use a later version).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-
-
-type path = string list
-type status =
- | No_path
- | Found of Ext_json_types.t
- | Wrong_type of path
-
-
-type callback =
- [
- `Str of (string -> unit)
- | `Str_loc of (string -> Lexing.position -> unit)
- | `Flo of (string -> unit )
- | `Bool of (bool -> unit )
- | `Obj of (Ext_json_types.t String_map.t -> unit)
- | `Arr of (Ext_json_types.t array -> unit )
- | `Arr_loc of
- (Ext_json_types.t array -> Lexing.position -> Lexing.position -> unit)
- | `Null of (unit -> unit)
- | `Not_found of (unit -> unit)
- | `Id of (Ext_json_types.t -> unit )
- ]
-
-val test:
- ?fail:(unit -> unit) ->
- string -> callback
- -> Ext_json_types.t String_map.t
- -> Ext_json_types.t String_map.t
-
-val query : path -> Ext_json_types.t -> status
-
-val loc_of : Ext_json_types.t -> Ext_position.t
-
-end = struct
-#1 "ext_json.ml"
-
-
-type callback =
- [
- `Str of (string -> unit)
- | `Str_loc of (string -> Lexing.position -> unit)
- | `Flo of (string -> unit )
- | `Bool of (bool -> unit )
- | `Obj of (Ext_json_types.t String_map.t -> unit)
- | `Arr of (Ext_json_types.t array -> unit )
- | `Arr_loc of (Ext_json_types.t array -> Lexing.position -> Lexing.position -> unit)
- | `Null of (unit -> unit)
- | `Not_found of (unit -> unit)
- | `Id of (Ext_json_types.t -> unit )
- ]
-
-
-type path = string list
-
-type status =
- | No_path
- | Found of Ext_json_types.t
- | Wrong_type of path
-
-let test ?(fail=(fun () -> ())) key
- (cb : callback) (m : Ext_json_types.t String_map.t)
- =
- begin match String_map.find_exn key m, cb with
- | exception Not_found ->
- begin match cb with `Not_found f -> f ()
- | _ -> fail ()
- end
- | True _, `Bool cb -> cb true
- | False _, `Bool cb -> cb false
- | Flo {flo = s} , `Flo cb -> cb s
- | Obj {map = b} , `Obj cb -> cb b
- | Arr {content}, `Arr cb -> cb content
- | Arr {content; loc_start ; loc_end}, `Arr_loc cb ->
- cb content loc_start loc_end
- | Null _, `Null cb -> cb ()
- | Str {str = s }, `Str cb -> cb s
- | Str {str = s ; loc }, `Str_loc cb -> cb s loc
- | any , `Id cb -> cb any
- | _, _ -> fail ()
- end;
- m
-let query path (json : Ext_json_types.t ) =
- let rec aux acc paths json =
- match path with
- | [] -> Found json
- | p :: rest ->
- begin match json with
- | Obj {map = m} ->
- begin match String_map.find_exn p m with
- | m' -> aux (p::acc) rest m'
- | exception Not_found -> No_path
- end
- | _ -> Wrong_type acc
- end
- in aux [] path json
-
-
-let loc_of (x : Ext_json_types.t) =
- match x with
- | True p | False p | Null p -> p
- | Str p -> p.loc
- | Arr p -> p.loc_start
- | Obj p -> p.loc
- | Flo p -> p.loc
-
-
-end
-module Bsb_exception : sig
-#1 "bsb_exception.mli"
-(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * In addition to the permissions granted to you by the LGPL, you may combine
- * or link a "work that uses the Library" with a publicly distributed version
- * of this file to produce a combined library or application, then distribute
- * that combined work under the terms of your choosing, with no requirement
- * to comply with the obligations normally placed on you by section 4 of the
- * LGPL version 3 (or the corresponding section of a later version of the LGPL
- * should you choose to use a later version).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-
-
-
-type error =
- | Package_not_found of string * string option (* json file *)
-
-
-val error : error -> 'a
-
-val failf : ?loc:Ext_position.t -> ('a, unit, string, 'b) format4 -> 'a
-
-val failwith_config : Ext_json_types.t -> ('a, unit, string, 'b) format4 -> 'a
+ pos_fname : string ;
+ pos_lnum : int ;
+ pos_bol : int ;
+ pos_cnum : int
+}
-(* val expect_an_array_fmt : (string -> 'a, 'b, 'a) format *)
+val print : Format.formatter -> t -> unit
end = struct
-#1 "bsb_exception.ml"
+#1 "ext_position.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
*
* This program is free software: you can redistribute it and/or modify
@@ -3688,75 +3755,25 @@ end = struct
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+type t = Lexing.position = {
+ pos_fname : string ;
+ pos_lnum : int ;
+ pos_bol : int ;
+ pos_cnum : int
+}
-type error =
- | Package_not_found of string * string option (* json file *)
-
-
-exception Error of error
-
-let error err = raise (Error err)
-
-let to_string (x : error) =
- match x with
- | Package_not_found (name,json_opt) ->
- let in_json = match json_opt with None -> Ext_string.empty | Some x -> " in " ^ x in
- if Ext_string.equal name Bs_version.package_name then
- Printf.sprintf "Package bs-platform is not found %s , it is the basic package required, if you have it installed globally\n\
- Please run 'npm link bs-platform' to make it available " in_json
- else
- Printf.sprintf
- "BuckleScript package %s not found or built %s, if it is not built\n\
- Please run 'bsb -make-world', otherwise please install it " name in_json
-
-let () =
- Printexc.register_printer (fun x ->
- match x with
- | Error x ->
- Some (to_string x )
- | _ -> None
- )
-
-
-
-let failf ?loc fmt =
- let prefix =
- match loc with
- | None -> "Error "
- | Some x ->
- Format.asprintf "Error " Ext_position.print x in
- Format.ksprintf (fun s -> failwith (prefix ^ s)) fmt
-
-let expect_an_array_fmt : _ format = "%s expect an array"
-let failwith_config config fmt =
- let loc = Ext_json.loc_of config in
- failf ~loc fmt
-
-end
-module Bs_hash_stubs
-= struct
-#1 "bs_hash_stubs.ml"
-external hash_string : string -> int = "caml_bs_hash_string" "noalloc";;
-
-external hash_string_int : string -> int -> int = "caml_bs_hash_string_and_int" "noalloc";;
-external hash_string_small_int : string -> int -> int = "caml_bs_hash_string_and_small_int" "noalloc";;
+let print fmt (pos : t) =
+ Format.fprintf fmt "(%d,%d)" pos.pos_lnum (pos.pos_cnum - pos.pos_bol)
-external hash_stamp_and_name : int -> string -> int = "caml_bs_hash_stamp_and_name" "noalloc";;
-external hash_small_int : int -> int = "caml_bs_hash_small_int" "noalloc";;
-external hash_int : int -> int = "caml_bs_hash_int" "noalloc";;
-external string_length_based_compare : string -> string -> int = "caml_string_length_based_compare" "noalloc";;
-external
- int_unsafe_blit :
- int array -> int -> int array -> int -> int -> unit = "caml_int_array_blit" "noalloc";;
end
-module Ext_util : sig
-#1 "ext_util.mli"
+module Ext_json : sig
+#1 "ext_json.mli"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
*
* This program is free software: you can redistribute it and/or modify
@@ -3782,15 +3799,43 @@ module Ext_util : sig
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-
-val power_2_above : int -> int -> int
+type path = string list
+type status =
+ | No_path
+ | Found of Ext_json_types.t
+ | Wrong_type of path
-val stats_to_string : Hashtbl.statistics -> string
+type callback =
+ [
+ `Str of (string -> unit)
+ | `Str_loc of (string -> Lexing.position -> unit)
+ | `Flo of (string -> unit )
+ | `Bool of (bool -> unit )
+ | `Obj of (Ext_json_types.t String_map.t -> unit)
+ | `Arr of (Ext_json_types.t array -> unit )
+ | `Arr_loc of
+ (Ext_json_types.t array -> Lexing.position -> Lexing.position -> unit)
+ | `Null of (unit -> unit)
+ | `Not_found of (unit -> unit)
+ | `Id of (Ext_json_types.t -> unit )
+ ]
+
+val test:
+ ?fail:(unit -> unit) ->
+ string -> callback
+ -> Ext_json_types.t String_map.t
+ -> Ext_json_types.t String_map.t
+
+val query : path -> Ext_json_types.t -> status
+
+val loc_of : Ext_json_types.t -> Ext_position.t
+
+val equal : Ext_json_types.t -> Ext_json_types.t -> bool
end = struct
-#1 "ext_util.ml"
+#1 "ext_json.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -3808,252 +3853,171 @@ end = struct
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-(**
- {[
- (power_2_above 16 63 = 64)
- (power_2_above 16 76 = 128)
- ]}
-*)
-let rec power_2_above x n =
- if x >= n then x
- else if x * 2 > Sys.max_array_length then x
- else power_2_above (x * 2) n
-
-
-let stats_to_string ({num_bindings; num_buckets; max_bucket_length; bucket_histogram} : Hashtbl.statistics) =
- Printf.sprintf
- "bindings: %d,buckets: %d, longest: %d, hist:[%s]"
- num_bindings
- num_buckets
- max_bucket_length
- (String.concat "," (Array.to_list (Array.map string_of_int bucket_histogram)))
-end
-module Hashtbl_gen
-= struct
-#1 "hashtbl_gen.ml"
-(***********************************************************************)
-(* *)
-(* OCaml *)
-(* *)
-(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
-(* *)
-(* Copyright 1996 Institut National de Recherche en Informatique et *)
-(* en Automatique. All rights reserved. This file is distributed *)
-(* under the terms of the GNU Library General Public License, with *)
-(* the special exception on linking described in file ../LICENSE. *)
-(* *)
-(***********************************************************************)
-
-(* Hash tables *)
-
-
-
-module type S = sig
- type key
- type 'a t
- val create: int -> 'a t
- val clear: 'a t -> unit
- val reset: 'a t -> unit
- val copy: 'a t -> 'a t
- val add: 'a t -> key -> 'a -> unit
- val modify_or_init: 'a t -> key -> ('a -> unit) -> (unit -> 'a) -> unit
- val remove: 'a t -> key -> unit
- val find_exn: 'a t -> key -> 'a
- val find_all: 'a t -> key -> 'a list
- val find_opt: 'a t -> key -> 'a option
-
- (** return the key found in the hashtbl.
- Use case: when you find the key existed in hashtbl,
- you want to use the one stored in the hashtbl.
- (they are semantically equivlanent, but may have other information different)
- *)
- val find_key_opt: 'a t -> key -> key option
-
- val find_default: 'a t -> key -> 'a -> 'a
-
- val replace: 'a t -> key -> 'a -> unit
- val mem: 'a t -> key -> bool
- val iter: (key -> 'a -> unit) -> 'a t -> unit
- val fold: (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b
- val length: 'a t -> int
- val stats: 'a t -> Hashtbl.statistics
- val of_list2: key list -> 'a list -> 'a t
-end
-
-(* We do dynamic hashing, and resize the table and rehash the elements
- when buckets become too long. *)
-
-type ('a, 'b) t =
- { mutable size: int; (* number of entries *)
- mutable data: ('a, 'b) bucketlist array; (* the buckets *)
- mutable seed: int; (* for randomization *)
- initial_size: int; (* initial array size *)
- }
-
-and ('a, 'b) bucketlist =
- | Empty
- | Cons of 'a * 'b * ('a, 'b) bucketlist
-
-
-let create initial_size =
- let s = Ext_util.power_2_above 16 initial_size in
- { initial_size = s; size = 0; seed = 0; data = Array.make s Empty }
-
-let clear h =
- h.size <- 0;
- let len = Array.length h.data in
- for i = 0 to len - 1 do
- h.data.(i) <- Empty
- done
-
-let reset h =
- h.size <- 0;
- h.data <- Array.make h.initial_size Empty
+type callback =
+ [
+ `Str of (string -> unit)
+ | `Str_loc of (string -> Lexing.position -> unit)
+ | `Flo of (string -> unit )
+ | `Bool of (bool -> unit )
+ | `Obj of (Ext_json_types.t String_map.t -> unit)
+ | `Arr of (Ext_json_types.t array -> unit )
+ | `Arr_loc of (Ext_json_types.t array -> Lexing.position -> Lexing.position -> unit)
+ | `Null of (unit -> unit)
+ | `Not_found of (unit -> unit)
+ | `Id of (Ext_json_types.t -> unit )
+ ]
-let copy h = { h with data = Array.copy h.data }
+type path = string list
-let length h = h.size
+type status =
+ | No_path
+ | Found of Ext_json_types.t
+ | Wrong_type of path
-let resize indexfun h =
- let odata = h.data in
- let osize = Array.length odata in
- let nsize = osize * 2 in
- if nsize < Sys.max_array_length then begin
- let ndata = Array.make nsize Empty in
- h.data <- ndata; (* so that indexfun sees the new bucket count *)
- let rec insert_bucket = function
- Empty -> ()
- | Cons(key, data, rest) ->
- insert_bucket rest; (* preserve original order of elements *)
- let nidx = indexfun h key in
- ndata.(nidx) <- Cons(key, data, ndata.(nidx)) in
- for i = 0 to osize - 1 do
- insert_bucket (Array.unsafe_get odata i)
- done
- end
+let test ?(fail=(fun () -> ())) key
+ (cb : callback) (m : Ext_json_types.t String_map.t)
+ =
+ begin match String_map.find_exn key m, cb with
+ | exception Not_found ->
+ begin match cb with `Not_found f -> f ()
+ | _ -> fail ()
+ end
+ | True _, `Bool cb -> cb true
+ | False _, `Bool cb -> cb false
+ | Flo {flo = s} , `Flo cb -> cb s
+ | Obj {map = b} , `Obj cb -> cb b
+ | Arr {content}, `Arr cb -> cb content
+ | Arr {content; loc_start ; loc_end}, `Arr_loc cb ->
+ cb content loc_start loc_end
+ | Null _, `Null cb -> cb ()
+ | Str {str = s }, `Str cb -> cb s
+ | Str {str = s ; loc }, `Str_loc cb -> cb s loc
+ | any , `Id cb -> cb any
+ | _, _ -> fail ()
+ end;
+ m
+let query path (json : Ext_json_types.t ) =
+ let rec aux acc paths json =
+ match path with
+ | [] -> Found json
+ | p :: rest ->
+ begin match json with
+ | Obj {map = m} ->
+ begin match String_map.find_exn p m with
+ | m' -> aux (p::acc) rest m'
+ | exception Not_found -> No_path
+ end
+ | _ -> Wrong_type acc
+ end
+ in aux [] path json
+let loc_of (x : Ext_json_types.t) =
+ match x with
+ | True p | False p | Null p -> p
+ | Str p -> p.loc
+ | Arr p -> p.loc_start
+ | Obj p -> p.loc
+ | Flo p -> p.loc
-let iter f h =
- let rec do_bucket = function
- | Empty ->
- ()
- | Cons(k, d, rest) ->
- f k d; do_bucket rest in
- let d = h.data in
- for i = 0 to Array.length d - 1 do
- do_bucket (Array.unsafe_get d i)
- done
-let fold f h init =
- let rec do_bucket b accu =
- match b with
- Empty ->
- accu
- | Cons(k, d, rest) ->
- do_bucket rest (f k d accu) in
- let d = h.data in
- let accu = ref init in
- for i = 0 to Array.length d - 1 do
- accu := do_bucket d.(i) !accu
- done;
- !accu
+let rec equal
+ (x : Ext_json_types.t)
+ (y : Ext_json_types.t) =
+ match x with
+ | Null _ -> (* [%p? Null _ ] *)
+ begin match y with
+ | Null _ -> true
+ | _ -> false end
+ | Str {str } ->
+ begin match y with
+ | Str {str = str2} -> str = str2
+ | _ -> false end
+ | Flo {flo}
+ ->
+ begin match y with
+ | Flo {flo = flo2} ->
+ flo = flo2
+ | _ -> false
+ end
+ | True _ ->
+ begin match y with
+ | True _ -> true
+ | _ -> false
+ end
+ | False _ ->
+ begin match y with
+ | False _ -> true
+ | _ -> false
+ end
+ | Arr {content}
+ ->
+ begin match y with
+ | Arr {content = content2}
+ ->
+ Ext_array.for_all2_no_exn equal content content2
+ | _ -> false
+ end
-let rec bucket_length accu = function
- | Empty -> accu
- | Cons(_, _, rest) -> bucket_length (accu + 1) rest
+ | Obj {map} ->
+ begin match y with
+ | Obj { map = map2} ->
+ String_map.equal equal map map2
+ | _ -> false
+ end
-let stats h =
- let mbl =
- Array.fold_left (fun m b -> max m (bucket_length 0 b)) 0 h.data in
- let histo = Array.make (mbl + 1) 0 in
- Array.iter
- (fun b ->
- let l = bucket_length 0 b in
- histo.(l) <- histo.(l) + 1)
- h.data;
- {Hashtbl.
- num_bindings = h.size;
- num_buckets = Array.length h.data;
- max_bucket_length = mbl;
- bucket_histogram = histo }
+end
+module Bsb_exception : sig
+#1 "bsb_exception.mli"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-let rec small_bucket_mem eq key (lst : _ bucketlist) =
- match lst with
- | Empty -> false
- | Cons(k1,_,rest1) ->
- eq key k1 ||
- match rest1 with
- | Empty -> false
- | Cons(k2,_,rest2) ->
- eq key k2 ||
- match rest2 with
- | Empty -> false
- | Cons(k3,_,rest3) ->
- eq key k3 ||
- small_bucket_mem eq key rest3
+type error =
+ | Package_not_found of string * string option (* json file *)
-let rec small_bucket_opt eq key (lst : _ bucketlist) : _ option =
- match lst with
- | Empty -> None
- | Cons(k1,d1,rest1) ->
- if eq key k1 then Some d1 else
- match rest1 with
- | Empty -> None
- | Cons(k2,d2,rest2) ->
- if eq key k2 then Some d2 else
- match rest2 with
- | Empty -> None
- | Cons(k3,d3,rest3) ->
- if eq key k3 then Some d3 else
- small_bucket_opt eq key rest3
+val error : error -> 'a
-let rec small_bucket_key_opt eq key (lst : _ bucketlist) : _ option =
- match lst with
- | Empty -> None
- | Cons(k1,d1,rest1) ->
- if eq key k1 then Some k1 else
- match rest1 with
- | Empty -> None
- | Cons(k2,d2,rest2) ->
- if eq key k2 then Some k2 else
- match rest2 with
- | Empty -> None
- | Cons(k3,d3,rest3) ->
- if eq key k3 then Some k3 else
- small_bucket_key_opt eq key rest3
+val failf : ?loc:Ext_position.t -> ('a, unit, string, 'b) format4 -> 'a
+val failwith_config : Ext_json_types.t -> ('a, unit, string, 'b) format4 -> 'a
-let rec small_bucket_default eq key default (lst : _ bucketlist) =
- match lst with
- | Empty -> default
- | Cons(k1,d1,rest1) ->
- if eq key k1 then d1 else
- match rest1 with
- | Empty -> default
- | Cons(k2,d2,rest2) ->
- if eq key k2 then d2 else
- match rest2 with
- | Empty -> default
- | Cons(k3,d3,rest3) ->
- if eq key k3 then d3 else
- small_bucket_default eq key default rest3
+(* val expect_an_array_fmt : (string -> 'a, 'b, 'a) format *)
-end
-module String_hashtbl : sig
-#1 "string_hashtbl.mli"
+end = struct
+#1 "bsb_exception.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
- *
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@@ -4071,159 +4035,113 @@ module String_hashtbl : sig
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-include Hashtbl_gen.S with type key = string
+type error =
+ | Package_not_found of string * string option (* json file *)
+exception Error of error
-end = struct
-#1 "string_hashtbl.ml"
-# 9 "ext/hashtbl.cppo.ml"
-type key = string
-type 'a t = (key, 'a) Hashtbl_gen.t
-let key_index (h : _ t ) (key : key) =
- (Bs_hash_stubs.hash_string key ) land (Array.length h.data - 1)
-let eq_key = Ext_string.equal
+let error err = raise (Error err)
-# 33
-type ('a, 'b) bucketlist = ('a,'b) Hashtbl_gen.bucketlist
-let create = Hashtbl_gen.create
-let clear = Hashtbl_gen.clear
-let reset = Hashtbl_gen.reset
-let copy = Hashtbl_gen.copy
-let iter = Hashtbl_gen.iter
-let fold = Hashtbl_gen.fold
-let length = Hashtbl_gen.length
-let stats = Hashtbl_gen.stats
+let to_string (x : error) =
+ match x with
+ | Package_not_found (name,json_opt) ->
+ let in_json = match json_opt with None -> Ext_string.empty | Some x -> " in " ^ x in
+ if Ext_string.equal name Bs_version.package_name then
+ Printf.sprintf "Package bs-platform is not found %s , it is the basic package required, if you have it installed globally\n\
+ Please run 'npm link bs-platform' to make it available " in_json
+ else
+ Printf.sprintf
+ "BuckleScript package %s not found or built %s, if it is not built\n\
+ Please run 'bsb -make-world', otherwise please install it " name in_json
+let () =
+ Printexc.register_printer (fun x ->
+ match x with
+ | Error x ->
+ Some (to_string x )
+ | _ -> None
+ )
-let add (h : _ t) key info =
- let i = key_index h key in
- let h_data = h.data in
- Array.unsafe_set h_data i (Cons(key, info, (Array.unsafe_get h_data i)));
- h.size <- h.size + 1;
- if h.size > Array.length h_data lsl 1 then Hashtbl_gen.resize key_index h
-(* after upgrade to 4.04 we should provide an efficient [replace_or_init] *)
-let modify_or_init (h : _ t) key modf default =
- let rec find_bucket (bucketlist : _ bucketlist) =
- match bucketlist with
- | Cons(k,i,next) ->
- if eq_key k key then begin modf i; false end
- else find_bucket next
- | Empty -> true in
- let i = key_index h key in
- let h_data = h.data in
- if find_bucket (Array.unsafe_get h_data i) then
- begin
- Array.unsafe_set h_data i (Cons(key,default (), Array.unsafe_get h_data i));
- h.size <- h.size + 1 ;
- if h.size > Array.length h_data lsl 1 then Hashtbl_gen.resize key_index h
- end
+let failf ?loc fmt =
+ let prefix =
+ match loc with
+ | None -> "Error "
+ | Some x ->
+ Format.asprintf "Error " Ext_position.print x in
+ Format.ksprintf (fun s -> failwith (prefix ^ s)) fmt
+let expect_an_array_fmt : _ format = "%s expect an array"
+let failwith_config config fmt =
+ let loc = Ext_json.loc_of config in
+ failf ~loc fmt
-let rec remove_bucket key (h : _ t) (bucketlist : _ bucketlist) : _ bucketlist =
- match bucketlist with
- | Empty ->
- Empty
- | Cons(k, i, next) ->
- if eq_key k key
- then begin h.size <- h.size - 1; next end
- else Cons(k, i, remove_bucket key h next)
+end
+module Bs_hash_stubs
+= struct
+#1 "bs_hash_stubs.ml"
+external hash_string : string -> int = "caml_bs_hash_string" "noalloc";;
-let remove (h : _ t ) key =
- let i = key_index h key in
- let h_data = h.data in
- let old_h_szie = h.size in
- let new_bucket = remove_bucket key h (Array.unsafe_get h_data i) in
- if old_h_szie <> h.size then
- Array.unsafe_set h_data i new_bucket
+external hash_string_int : string -> int -> int = "caml_bs_hash_string_and_int" "noalloc";;
-let rec find_rec key (bucketlist : _ bucketlist) = match bucketlist with
- | Empty ->
- raise Not_found
- | Cons(k, d, rest) ->
- if eq_key key k then d else find_rec key rest
+external hash_string_small_int : string -> int -> int = "caml_bs_hash_string_and_small_int" "noalloc";;
-let find_exn (h : _ t) key =
- match Array.unsafe_get h.data (key_index h key) with
- | Empty -> raise Not_found
- | Cons(k1, d1, rest1) ->
- if eq_key key k1 then d1 else
- match rest1 with
- | Empty -> raise Not_found
- | Cons(k2, d2, rest2) ->
- if eq_key key k2 then d2 else
- match rest2 with
- | Empty -> raise Not_found
- | Cons(k3, d3, rest3) ->
- if eq_key key k3 then d3 else find_rec key rest3
+external hash_stamp_and_name : int -> string -> int = "caml_bs_hash_stamp_and_name" "noalloc";;
-let find_opt (h : _ t) key =
- Hashtbl_gen.small_bucket_opt eq_key key (Array.unsafe_get h.data (key_index h key))
+external hash_small_int : int -> int = "caml_bs_hash_small_int" "noalloc";;
-let find_key_opt (h : _ t) key =
- Hashtbl_gen.small_bucket_key_opt eq_key key (Array.unsafe_get h.data (key_index h key))
-
-let find_default (h : _ t) key default =
- Hashtbl_gen.small_bucket_default eq_key key default (Array.unsafe_get h.data (key_index h key))
-let find_all (h : _ t) key =
- let rec find_in_bucket (bucketlist : _ bucketlist) = match bucketlist with
- | Empty ->
- []
- | Cons(k, d, rest) ->
- if eq_key k key
- then d :: find_in_bucket rest
- else find_in_bucket rest in
- find_in_bucket (Array.unsafe_get h.data (key_index h key))
+external hash_int : int -> int = "caml_bs_hash_int" "noalloc";;
-let replace h key info =
- let rec replace_bucket (bucketlist : _ bucketlist) : _ bucketlist = match bucketlist with
- | Empty ->
- raise_notrace Not_found
- | Cons(k, i, next) ->
- if eq_key k key
- then Cons(key, info, next)
- else Cons(k, i, replace_bucket next) in
- let i = key_index h key in
- let h_data = h.data in
- let l = Array.unsafe_get h_data i in
- try
- Array.unsafe_set h_data i (replace_bucket l)
- with Not_found ->
- begin
- Array.unsafe_set h_data i (Cons(key, info, l));
- h.size <- h.size + 1;
- if h.size > Array.length h_data lsl 1 then Hashtbl_gen.resize key_index h;
- end
+external string_length_based_compare : string -> string -> int = "caml_string_length_based_compare" "noalloc";;
-let mem (h : _ t) key =
- let rec mem_in_bucket (bucketlist : _ bucketlist) = match bucketlist with
- | Empty ->
- false
- | Cons(k, d, rest) ->
- eq_key k key || mem_in_bucket rest in
- mem_in_bucket (Array.unsafe_get h.data (key_index h key))
+external
+ int_unsafe_blit :
+ int array -> int -> int array -> int -> int -> unit = "caml_int_array_blit" "noalloc";;
+end
+module Ext_util : sig
+#1 "ext_util.mli"
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
-let of_list2 ks vs =
- let len = List.length ks in
- let map = create len in
- List.iter2 (fun k v -> add map k v) ks vs ;
- map
+
+val power_2_above : int -> int -> int
-end
-module Bsb_pkg : sig
-#1 "bsb_pkg.mli"
+val stats_to_string : Hashtbl.statistics -> string
+end = struct
+#1 "ext_util.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
*
* This program is free software: you can redistribute it and/or modify
@@ -4248,125 +4166,245 @@ module Bsb_pkg : sig
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+(**
+ {[
+ (power_2_above 16 63 = 64)
+ (power_2_above 16 76 = 128)
+ ]}
+*)
+let rec power_2_above x n =
+ if x >= n then x
+ else if x * 2 > Sys.max_array_length then x
+ else power_2_above (x * 2) n
-(** [resolve cwd module_name],
- [cwd] is current working directory, absolute path
- Trying to find paths to load [module_name]
- it is sepcialized for option [-bs-package-include] which requires
- [npm_package_name/lib/ocaml]
- it relies on [npm_config_prefix] env variable for global npm modules
-*)
+let stats_to_string ({num_bindings; num_buckets; max_bucket_length; bucket_histogram} : Hashtbl.statistics) =
+ Printf.sprintf
+ "bindings: %d,buckets: %d, longest: %d, hist:[%s]"
+ num_bindings
+ num_buckets
+ max_bucket_length
+ (String.concat "," (Array.to_list (Array.map string_of_int bucket_histogram)))
+end
+module Hashtbl_gen
+= struct
+#1 "hashtbl_gen.ml"
+(***********************************************************************)
+(* *)
+(* OCaml *)
+(* *)
+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
+(* *)
+(* Copyright 1996 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the GNU Library General Public License, with *)
+(* the special exception on linking described in file ../LICENSE. *)
+(* *)
+(***********************************************************************)
-(** @raise when not found *)
-val resolve_bs_package :
- cwd:string -> string -> string
+(* Hash tables *)
+
+
+
+module type S = sig
+ type key
+ type 'a t
+ val create: int -> 'a t
+ val clear: 'a t -> unit
+ val reset: 'a t -> unit
+ val copy: 'a t -> 'a t
+ val add: 'a t -> key -> 'a -> unit
+ val modify_or_init: 'a t -> key -> ('a -> unit) -> (unit -> 'a) -> unit
+ val remove: 'a t -> key -> unit
+ val find_exn: 'a t -> key -> 'a
+ val find_all: 'a t -> key -> 'a list
+ val find_opt: 'a t -> key -> 'a option
+
+ (** return the key found in the hashtbl.
+ Use case: when you find the key existed in hashtbl,
+ you want to use the one stored in the hashtbl.
+ (they are semantically equivlanent, but may have other information different)
+ *)
+ val find_key_opt: 'a t -> key -> key option
+
+ val find_default: 'a t -> key -> 'a -> 'a
+
+ val replace: 'a t -> key -> 'a -> unit
+ val mem: 'a t -> key -> bool
+ val iter: (key -> 'a -> unit) -> 'a t -> unit
+ val fold: (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b
+ val length: 'a t -> int
+ val stats: 'a t -> Hashtbl.statistics
+ val of_list2: key list -> 'a list -> 'a t
+end
+
+(* We do dynamic hashing, and resize the table and rehash the elements
+ when buckets become too long. *)
+
+type ('a, 'b) t =
+ { mutable size: int; (* number of entries *)
+ mutable data: ('a, 'b) bucketlist array; (* the buckets *)
+ mutable seed: int; (* for randomization *)
+ initial_size: int; (* initial array size *)
+ }
+
+and ('a, 'b) bucketlist =
+ | Empty
+ | Cons of 'a * 'b * ('a, 'b) bucketlist
+
+
+let create initial_size =
+ let s = Ext_util.power_2_above 16 initial_size in
+ { initial_size = s; size = 0; seed = 0; data = Array.make s Empty }
+
+let clear h =
+ h.size <- 0;
+ let len = Array.length h.data in
+ for i = 0 to len - 1 do
+ h.data.(i) <- Empty
+ done
+
+let reset h =
+ h.size <- 0;
+ h.data <- Array.make h.initial_size Empty
+
+
+let copy h = { h with data = Array.copy h.data }
+
+let length h = h.size
+
+let resize indexfun h =
+ let odata = h.data in
+ let osize = Array.length odata in
+ let nsize = osize * 2 in
+ if nsize < Sys.max_array_length then begin
+ let ndata = Array.make nsize Empty in
+ h.data <- ndata; (* so that indexfun sees the new bucket count *)
+ let rec insert_bucket = function
+ Empty -> ()
+ | Cons(key, data, rest) ->
+ insert_bucket rest; (* preserve original order of elements *)
+ let nidx = indexfun h key in
+ ndata.(nidx) <- Cons(key, data, ndata.(nidx)) in
+ for i = 0 to osize - 1 do
+ insert_bucket (Array.unsafe_get odata i)
+ done
+ end
+
+
+
+let iter f h =
+ let rec do_bucket = function
+ | Empty ->
+ ()
+ | Cons(k, d, rest) ->
+ f k d; do_bucket rest in
+ let d = h.data in
+ for i = 0 to Array.length d - 1 do
+ do_bucket (Array.unsafe_get d i)
+ done
+let fold f h init =
+ let rec do_bucket b accu =
+ match b with
+ Empty ->
+ accu
+ | Cons(k, d, rest) ->
+ do_bucket rest (f k d accu) in
+ let d = h.data in
+ let accu = ref init in
+ for i = 0 to Array.length d - 1 do
+ accu := do_bucket d.(i) !accu
+ done;
+ !accu
+let rec bucket_length accu = function
+ | Empty -> accu
+ | Cons(_, _, rest) -> bucket_length (accu + 1) rest
-end = struct
-#1 "bsb_pkg.ml"
+let stats h =
+ let mbl =
+ Array.fold_left (fun m b -> max m (bucket_length 0 b)) 0 h.data in
+ let histo = Array.make (mbl + 1) 0 in
+ Array.iter
+ (fun b ->
+ let l = bucket_length 0 b in
+ histo.(l) <- histo.(l) + 1)
+ h.data;
+ {Hashtbl.
+ num_bindings = h.size;
+ num_buckets = Array.length h.data;
+ max_bucket_length = mbl;
+ bucket_histogram = histo }
-let (//) = Filename.concat
+let rec small_bucket_mem eq key (lst : _ bucketlist) =
+ match lst with
+ | Empty -> false
+ | Cons(k1,_,rest1) ->
+ eq key k1 ||
+ match rest1 with
+ | Empty -> false
+ | Cons(k2,_,rest2) ->
+ eq key k2 ||
+ match rest2 with
+ | Empty -> false
+ | Cons(k3,_,rest3) ->
+ eq key k3 ||
+ small_bucket_mem eq key rest3
-(** It makes sense to have this function raise, when [bsb] could not resolve a package, it used to mean
- a failure
-*)
-let resolve_bs_package
- ~cwd
- name =
- let marker = Literals.bsconfig_json in
- let sub_path = name // marker in
- let rec aux cwd =
- let abs_marker = cwd // Literals.node_modules // sub_path in
- if Sys.file_exists abs_marker then (* Some *) (Filename.dirname abs_marker)
- else
- let cwd' = Filename.dirname cwd in (* TODO: may non-terminating when see symlinks *)
- if String.length cwd' < String.length cwd then
- aux cwd'
- else
- try
- let abs_marker =
- Sys.getenv "npm_config_prefix"
- // "lib" // Literals.node_modules // sub_path in
- if Sys.file_exists abs_marker
- then
- Filename.dirname abs_marker
- else
- begin
- Format.fprintf Format.err_formatter
- "@{Package not found: resolving package %s in %s @}@." name cwd ;
- Bsb_exception.error (Package_not_found (name, None))
- end
- with
- Not_found ->
- begin
- Format.fprintf Format.err_formatter
- "@{Package not found: resolving package %s in %s @}@." name cwd ;
- Bsb_exception.error (Package_not_found (name,None))
- end
- in
- aux cwd
+let rec small_bucket_opt eq key (lst : _ bucketlist) : _ option =
+ match lst with
+ | Empty -> None
+ | Cons(k1,d1,rest1) ->
+ if eq key k1 then Some d1 else
+ match rest1 with
+ | Empty -> None
+ | Cons(k2,d2,rest2) ->
+ if eq key k2 then Some d2 else
+ match rest2 with
+ | Empty -> None
+ | Cons(k3,d3,rest3) ->
+ if eq key k3 then Some d3 else
+ small_bucket_opt eq key rest3
-let cache = String_hashtbl.create 0
+let rec small_bucket_key_opt eq key (lst : _ bucketlist) : _ option =
+ match lst with
+ | Empty -> None
+ | Cons(k1,d1,rest1) ->
+ if eq key k1 then Some k1 else
+ match rest1 with
+ | Empty -> None
+ | Cons(k2,d2,rest2) ->
+ if eq key k2 then Some k2 else
+ match rest2 with
+ | Empty -> None
+ | Cons(k3,d3,rest3) ->
+ if eq key k3 then Some k3 else
+ small_bucket_key_opt eq key rest3
-(** TODO: collect all warnings and print later *)
-let resolve_bs_package ~cwd package =
- match String_hashtbl.find_opt cache package with
- | None ->
- let result = resolve_bs_package ~cwd package in
- Format.fprintf Format.std_formatter "@{Package@} %s -> %s@." package result ;
- String_hashtbl.add cache package result ;
- result
- | Some x
- ->
- let result = resolve_bs_package ~cwd package in
- if result <> x then
- begin
- Format.fprintf Format.err_formatter
- "@{Duplicated package:@} %s %s (chosen) vs %s in %s @." package x result cwd;
- end;
- x
-(** The package does not need to be a bspackage
- example:
- {[
- resolve_npm_package_file ~cwd "reason/refmt";;
- resolve_npm_package_file ~cwd "reason/refmt/xx/yy"
- ]}
- It also returns the path name
- Note the input [sub_path] is already converted to physical meaning path according to OS
-*)
-(* let resolve_npm_package_file ~cwd sub_path = *)
-(* let rec aux cwd = *)
-(* let abs_marker = cwd // Literals.node_modules // sub_path in *)
-(* if Sys.file_exists abs_marker then Some abs_marker *)
-(* else *)
-(* let cwd' = Filename.dirname cwd in *)
-(* if String.length cwd' < String.length cwd then *)
-(* aux cwd' *)
-(* else *)
-(* try *)
-(* let abs_marker = *)
-(* Sys.getenv "npm_config_prefix" *)
-(* // "lib" // Literals.node_modules // sub_path in *)
-(* if Sys.file_exists abs_marker *)
-(* then Some abs_marker *)
-(* else None *)
-(* (\* Bs_exception.error (Bs_package_not_found name) *\) *)
-(* with *)
-(* Not_found -> None *)
-(* (\* Bs_exception.error (Bs_package_not_found name) *\) *)
-(* in *)
-(* aux cwd *)
+let rec small_bucket_default eq key default (lst : _ bucketlist) =
+ match lst with
+ | Empty -> default
+ | Cons(k1,d1,rest1) ->
+ if eq key k1 then d1 else
+ match rest1 with
+ | Empty -> default
+ | Cons(k2,d2,rest2) ->
+ if eq key k2 then d2 else
+ match rest2 with
+ | Empty -> default
+ | Cons(k3,d3,rest3) ->
+ if eq key k3 then d3 else
+ small_bucket_default eq key default rest3
end
-module Ext_array : sig
-#1 "ext_array.mli"
+module String_hashtbl : sig
+#1 "string_hashtbl.mli"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
*
* This program is free software: you can redistribute it and/or modify
@@ -4392,54 +4430,153 @@ module Ext_array : sig
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+include Hashtbl_gen.S with type key = string
-(** Some utilities for {!Array} operations *)
-val reverse_range : 'a array -> int -> int -> unit
-val reverse_in_place : 'a array -> unit
-val reverse : 'a array -> 'a array
-val reverse_of_list : 'a list -> 'a array
+end = struct
+#1 "string_hashtbl.ml"
+# 9 "ext/hashtbl.cppo.ml"
+type key = string
+type 'a t = (key, 'a) Hashtbl_gen.t
+let key_index (h : _ t ) (key : key) =
+ (Bs_hash_stubs.hash_string key ) land (Array.length h.data - 1)
+let eq_key = Ext_string.equal
-val filter : ('a -> bool) -> 'a array -> 'a array
+# 33
+type ('a, 'b) bucketlist = ('a,'b) Hashtbl_gen.bucketlist
+let create = Hashtbl_gen.create
+let clear = Hashtbl_gen.clear
+let reset = Hashtbl_gen.reset
+let copy = Hashtbl_gen.copy
+let iter = Hashtbl_gen.iter
+let fold = Hashtbl_gen.fold
+let length = Hashtbl_gen.length
+let stats = Hashtbl_gen.stats
-val filter_map : ('a -> 'b option) -> 'a array -> 'b array
-val range : int -> int -> int array
-val map2i : (int -> 'a -> 'b -> 'c ) -> 'a array -> 'b array -> 'c array
+let add (h : _ t) key info =
+ let i = key_index h key in
+ let h_data = h.data in
+ Array.unsafe_set h_data i (Cons(key, info, (Array.unsafe_get h_data i)));
+ h.size <- h.size + 1;
+ if h.size > Array.length h_data lsl 1 then Hashtbl_gen.resize key_index h
+
+(* after upgrade to 4.04 we should provide an efficient [replace_or_init] *)
+let modify_or_init (h : _ t) key modf default =
+ let rec find_bucket (bucketlist : _ bucketlist) =
+ match bucketlist with
+ | Cons(k,i,next) ->
+ if eq_key k key then begin modf i; false end
+ else find_bucket next
+ | Empty -> true in
+ let i = key_index h key in
+ let h_data = h.data in
+ if find_bucket (Array.unsafe_get h_data i) then
+ begin
+ Array.unsafe_set h_data i (Cons(key,default (), Array.unsafe_get h_data i));
+ h.size <- h.size + 1 ;
+ if h.size > Array.length h_data lsl 1 then Hashtbl_gen.resize key_index h
+ end
+
+
+let rec remove_bucket key (h : _ t) (bucketlist : _ bucketlist) : _ bucketlist =
+ match bucketlist with
+ | Empty ->
+ Empty
+ | Cons(k, i, next) ->
+ if eq_key k key
+ then begin h.size <- h.size - 1; next end
+ else Cons(k, i, remove_bucket key h next)
+
+let remove (h : _ t ) key =
+ let i = key_index h key in
+ let h_data = h.data in
+ let old_h_szie = h.size in
+ let new_bucket = remove_bucket key h (Array.unsafe_get h_data i) in
+ if old_h_szie <> h.size then
+ Array.unsafe_set h_data i new_bucket
+
+let rec find_rec key (bucketlist : _ bucketlist) = match bucketlist with
+ | Empty ->
+ raise Not_found
+ | Cons(k, d, rest) ->
+ if eq_key key k then d else find_rec key rest
-val to_list_map : ('a -> 'b option) -> 'a array -> 'b list
+let find_exn (h : _ t) key =
+ match Array.unsafe_get h.data (key_index h key) with
+ | Empty -> raise Not_found
+ | Cons(k1, d1, rest1) ->
+ if eq_key key k1 then d1 else
+ match rest1 with
+ | Empty -> raise Not_found
+ | Cons(k2, d2, rest2) ->
+ if eq_key key k2 then d2 else
+ match rest2 with
+ | Empty -> raise Not_found
+ | Cons(k3, d3, rest3) ->
+ if eq_key key k3 then d3 else find_rec key rest3
-val to_list_map_acc :
- ('a -> 'b option) ->
- 'a array ->
- 'b list ->
- 'b list
+let find_opt (h : _ t) key =
+ Hashtbl_gen.small_bucket_opt eq_key key (Array.unsafe_get h.data (key_index h key))
-val of_list_map : ('a -> 'b) -> 'a list -> 'b array
+let find_key_opt (h : _ t) key =
+ Hashtbl_gen.small_bucket_key_opt eq_key key (Array.unsafe_get h.data (key_index h key))
+
+let find_default (h : _ t) key default =
+ Hashtbl_gen.small_bucket_default eq_key key default (Array.unsafe_get h.data (key_index h key))
+let find_all (h : _ t) key =
+ let rec find_in_bucket (bucketlist : _ bucketlist) = match bucketlist with
+ | Empty ->
+ []
+ | Cons(k, d, rest) ->
+ if eq_key k key
+ then d :: find_in_bucket rest
+ else find_in_bucket rest in
+ find_in_bucket (Array.unsafe_get h.data (key_index h key))
-val rfind_with_index : 'a array -> ('a -> 'b -> bool) -> 'b -> int
+let replace h key info =
+ let rec replace_bucket (bucketlist : _ bucketlist) : _ bucketlist = match bucketlist with
+ | Empty ->
+ raise_notrace Not_found
+ | Cons(k, i, next) ->
+ if eq_key k key
+ then Cons(key, info, next)
+ else Cons(k, i, replace_bucket next) in
+ let i = key_index h key in
+ let h_data = h.data in
+ let l = Array.unsafe_get h_data i in
+ try
+ Array.unsafe_set h_data i (replace_bucket l)
+ with Not_found ->
+ begin
+ Array.unsafe_set h_data i (Cons(key, info, l));
+ h.size <- h.size + 1;
+ if h.size > Array.length h_data lsl 1 then Hashtbl_gen.resize key_index h;
+ end
+let mem (h : _ t) key =
+ let rec mem_in_bucket (bucketlist : _ bucketlist) = match bucketlist with
+ | Empty ->
+ false
+ | Cons(k, d, rest) ->
+ eq_key k key || mem_in_bucket rest in
+ mem_in_bucket (Array.unsafe_get h.data (key_index h key))
-type 'a split = [ `No_split | `Split of 'a array * 'a array ]
-val rfind_and_split :
- 'a array ->
- ('a -> 'b -> bool) ->
- 'b -> 'a split
+let of_list2 ks vs =
+ let len = List.length ks in
+ let map = create len in
+ List.iter2 (fun k v -> add map k v) ks vs ;
+ map
-val find_and_split :
- 'a array ->
- ('a -> 'b -> bool) ->
- 'b -> 'a split
-val exists : ('a -> bool) -> 'a array -> bool
+end
+module Bsb_pkg : sig
+#1 "bsb_pkg.mli"
-val is_empty : 'a array -> bool
-end = struct
-#1 "ext_array.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
*
* This program is free software: you can redistribute it and/or modify
@@ -4465,167 +4602,121 @@ end = struct
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+(** [resolve cwd module_name],
+ [cwd] is current working directory, absolute path
+ Trying to find paths to load [module_name]
+ it is sepcialized for option [-bs-package-include] which requires
+ [npm_package_name/lib/ocaml]
+ it relies on [npm_config_prefix] env variable for global npm modules
+*)
+(** @raise when not found *)
+val resolve_bs_package :
+ cwd:string -> string -> string
-let reverse_range a i len =
- if len = 0 then ()
- else
- for k = 0 to (len-1)/2 do
- let t = Array.unsafe_get a (i+k) in
- Array.unsafe_set a (i+k) ( Array.unsafe_get a (i+len-1-k));
- Array.unsafe_set a (i+len-1-k) t;
- done
-
-
-let reverse_in_place a =
- reverse_range a 0 (Array.length a)
-
-let reverse a =
- let b_len = Array.length a in
- if b_len = 0 then [||] else
- let b = Array.copy a in
- for i = 0 to b_len - 1 do
- Array.unsafe_set b i (Array.unsafe_get a (b_len - 1 -i ))
- done;
- b
-
-let reverse_of_list = function
- | [] -> [||]
- | hd::tl as l ->
- let len = List.length l in
- let a = Array.make len hd in
- let rec fill i = function
- | [] -> a
- | hd::tl -> Array.unsafe_set a (len - i - 2) hd; fill (i+1) tl in
- fill 0 tl
-
-let filter f a =
- let arr_len = Array.length a in
- let rec aux acc i =
- if i = arr_len
- then reverse_of_list acc
- else
- let v = Array.unsafe_get a i in
- if f v then
- aux (v::acc) (i+1)
- else aux acc (i + 1)
- in aux [] 0
-
-
-let filter_map (f : _ -> _ option) a =
- let arr_len = Array.length a in
- let rec aux acc i =
- if i = arr_len
- then reverse_of_list acc
- else
- let v = Array.unsafe_get a i in
- match f v with
- | Some v ->
- aux (v::acc) (i+1)
- | None ->
- aux acc (i + 1)
- in aux [] 0
-
-let range from to_ =
- if from > to_ then invalid_arg "Ext_array.range"
- else Array.init (to_ - from + 1) (fun i -> i + from)
-let map2i f a b =
- let len = Array.length a in
- if len <> Array.length b then
- invalid_arg "Ext_array.map2i"
- else
- Array.mapi (fun i a -> f i a ( Array.unsafe_get b i )) a
+end = struct
+#1 "bsb_pkg.ml"
- let rec tolist_aux a f i res =
- if i < 0 then res else
- let v = Array.unsafe_get a i in
- tolist_aux a f (i - 1)
- (match f v with
- | Some v -> v :: res
- | None -> res)
+let (//) = Filename.concat
-let to_list_map f a =
- tolist_aux a f (Array.length a - 1) []
-let to_list_map_acc f a acc =
- tolist_aux a f (Array.length a - 1) acc
-(* TODO: What would happen if [f] raise, memory leak? *)
-let of_list_map f a =
- match a with
- | [] -> [||]
- | h::tl ->
- let hd = f h in
- let len = List.length tl + 1 in
- let arr = Array.make len hd in
- let rec fill i = function
- | [] -> arr
- | hd :: tl ->
- Array.unsafe_set arr i (f hd);
- fill (i + 1) tl in
- fill 1 tl
-
-(**
-{[
-# rfind_with_index [|1;2;3|] (=) 2;;
-- : int = 1
-# rfind_with_index [|1;2;3|] (=) 1;;
-- : int = 0
-# rfind_with_index [|1;2;3|] (=) 3;;
-- : int = 2
-# rfind_with_index [|1;2;3|] (=) 4;;
-- : int = -1
-]}
+(** It makes sense to have this function raise, when [bsb] could not resolve a package, it used to mean
+ a failure
*)
-let rfind_with_index arr cmp v =
- let len = Array.length arr in
- let rec aux i =
- if i < 0 then i
- else if cmp (Array.unsafe_get arr i) v then i
- else aux (i - 1) in
- aux (len - 1)
-
-type 'a split = [ `No_split | `Split of 'a array * 'a array ]
-let rfind_and_split arr cmp v : _ split =
- let i = rfind_with_index arr cmp v in
- if i < 0 then
- `No_split
- else
- `Split (Array.sub arr 0 i , Array.sub arr (i + 1 ) (Array.length arr - i - 1 ))
-
-
-let find_with_index arr cmp v =
- let len = Array.length arr in
- let rec aux i len =
- if i >= len then -1
- else if cmp (Array.unsafe_get arr i ) v then i
- else aux (i + 1) len in
- aux 0 len
+let resolve_bs_package
+ ~cwd
+ name =
+ let marker = Literals.bsconfig_json in
+ let sub_path = name // marker in
+ let rec aux cwd =
+ let abs_marker = cwd // Literals.node_modules // sub_path in
+ if Sys.file_exists abs_marker then (* Some *) (Filename.dirname abs_marker)
+ else
+ let cwd' = Filename.dirname cwd in (* TODO: may non-terminating when see symlinks *)
+ if String.length cwd' < String.length cwd then
+ aux cwd'
+ else
+ try
+ let abs_marker =
+ Sys.getenv "npm_config_prefix"
+ // "lib" // Literals.node_modules // sub_path in
+ if Sys.file_exists abs_marker
+ then
+ Filename.dirname abs_marker
+ else
+ begin
+ Format.fprintf Format.err_formatter
+ "@{Package not found: resolving package %s in %s @}@." name cwd ;
+ Bsb_exception.error (Package_not_found (name, None))
+ end
+ with
+ Not_found ->
+ begin
+ Format.fprintf Format.err_formatter
+ "@{Package not found: resolving package %s in %s @}@." name cwd ;
+ Bsb_exception.error (Package_not_found (name,None))
+ end
+ in
+ aux cwd
-let find_and_split arr cmp v : _ split =
- let i = find_with_index arr cmp v in
- if i < 0 then
- `No_split
- else
- `Split (Array.sub arr 0 i, Array.sub arr (i + 1 ) (Array.length arr - i - 1))
-(** TODO: available since 4.03, use {!Array.exists} *)
+let cache = String_hashtbl.create 0
-let exists p a =
- let n = Array.length a in
- let rec loop i =
- if i = n then false
- else if p (Array.unsafe_get a i) then true
- else loop (succ i) in
- loop 0
+(** TODO: collect all warnings and print later *)
+let resolve_bs_package ~cwd package =
+ match String_hashtbl.find_opt cache package with
+ | None ->
+ let result = resolve_bs_package ~cwd package in
+ Format.fprintf Format.std_formatter "@{Package@} %s -> %s@." package result ;
+ String_hashtbl.add cache package result ;
+ result
+ | Some x
+ ->
+ let result = resolve_bs_package ~cwd package in
+ if result <> x then
+ begin
+ Format.fprintf Format.err_formatter
+ "@{Duplicated package:@} %s %s (chosen) vs %s in %s @." package x result cwd;
+ end;
+ x
+(** The package does not need to be a bspackage
+ example:
+ {[
+ resolve_npm_package_file ~cwd "reason/refmt";;
+ resolve_npm_package_file ~cwd "reason/refmt/xx/yy"
+ ]}
+ It also returns the path name
+ Note the input [sub_path] is already converted to physical meaning path according to OS
+*)
+(* let resolve_npm_package_file ~cwd sub_path = *)
+(* let rec aux cwd = *)
+(* let abs_marker = cwd // Literals.node_modules // sub_path in *)
+(* if Sys.file_exists abs_marker then Some abs_marker *)
+(* else *)
+(* let cwd' = Filename.dirname cwd in *)
+(* if String.length cwd' < String.length cwd then *)
+(* aux cwd' *)
+(* else *)
+(* try *)
+(* let abs_marker = *)
+(* Sys.getenv "npm_config_prefix" *)
+(* // "lib" // Literals.node_modules // sub_path in *)
+(* if Sys.file_exists abs_marker *)
+(* then Some abs_marker *)
+(* else None *)
+(* (\* Bs_exception.error (Bs_package_not_found name) *\) *)
+(* with *)
+(* Not_found -> None *)
+(* (\* Bs_exception.error (Bs_package_not_found name) *\) *)
+(* in *)
+(* aux cwd *)
-let is_empty arr =
- Array.length arr = 0
end
module Ext_json_parse : sig
#1 "ext_json_parse.mli"
@@ -6377,7 +6468,6 @@ type module_info =
{
mli : mli_kind ;
ml : ml_kind ;
- mll : string option
}
type file_group_rouces = module_info String_map.t
@@ -6445,7 +6535,7 @@ type module_info =
{
mli : mli_kind ;
ml : ml_kind ;
- mll : string option ;
+ (*mll : string option ;*)
}
@@ -6460,7 +6550,7 @@ let module_info_magic_number = "BSBUILD20161019"
let dir_of_module_info (x : module_info)
=
match x with
- | { mli; ml; mll} ->
+ | { mli; ml; } ->
begin match mli with
| Mli s | Rei s ->
Filename.dirname s
@@ -6468,11 +6558,11 @@ let dir_of_module_info (x : module_info)
begin match ml with
| Ml s | Re s ->
Filename.dirname s
- | Ml_empty ->
- begin match mll with
+ | Ml_empty -> Ext_string.empty
+ (*begin match mll with
| None -> ""
| Some s -> Filename.dirname s
- end
+ end *)
end
end
@@ -6494,7 +6584,7 @@ let read_build_cache bsbuild : t =
let bsbuild_cache = ".bsbuild"
-let empty_module_info = {mli = Mli_empty ; mll = None ; ml = Ml_empty}
+let empty_module_info = {mli = Mli_empty ; ml = Ml_empty}
let adjust_module_info x suffix name =
match suffix with
@@ -6502,7 +6592,6 @@ let adjust_module_info x suffix name =
| ".re" -> {x with ml = Re name}
| ".mli" -> {x with mli = Mli name}
| ".rei" -> { x with mli = Rei name}
- | ".mll" -> {x with mll = Some name}
| _ -> failwith ("don't know what to do with " ^ name)
let map_update ?dir (map : file_group_rouces) name : file_group_rouces =
@@ -7401,7 +7490,7 @@ type file_group =
type t =
- { files : file_group list ;
+ { files : file_group list ; (* flattened list of directories *)
intervals : Ext_file_pp.interval list ;
globbed_dirs : string list ;
@@ -7415,7 +7504,8 @@ type parsing_cxt = {
no_dev : bool ;
dir_index : dir_index ;
cwd : string ;
- root : string
+ root : string ;
+ cut_generators : bool
}
@@ -7547,7 +7637,8 @@ type parsing_cxt = {
no_dev : bool ;
dir_index : dir_index ;
cwd : string ;
- root : string
+ root : string;
+ cut_generators : bool
}
let handle_list_files acc
@@ -7593,6 +7684,29 @@ let (++) (u : t) (v : t) =
globbed_dirs = u.globbed_dirs @ v.globbed_dirs ;
}
+let get_input_output loc_start (content : Ext_json_types.t array) =
+ let error () =
+ Bsb_exception.failf ~loc:loc_start {| invalid edge format, expect ["input" , ":", "output" ]|}
+ in
+ match Ext_array.find_and_split content
+ (fun x () -> match x with Str { str =":"} -> true | _ -> false )
+ () with
+ | `No_split -> error ()
+ | `Split ( output, input) ->
+ Ext_array.to_list_map (fun (x : Ext_json_types.t) ->
+ match x with
+ | Str {str = ":"} ->
+ error ()
+ | Str {str } ->
+ Some str
+ | _ -> None) output ,
+ Ext_array.to_list_map (fun (x : Ext_json_types.t) ->
+ match x with
+ | Str {str = ":"} ->
+ error ()
+ | Str {str} ->
+ Some str (* More rigirous error checking: It would trigger a ninja syntax error *)
+ | _ -> None) input
(** [dir_index] can be inherited *)
let rec
@@ -7632,7 +7746,7 @@ and parsing_source ({no_dev; dir_index ; cwd} as cxt ) (x : Ext_json_types.t )
| _ -> empty
and parsing_source_dir_map
- ({ cwd = dir} as cxt )
+ ({ cwd = dir; no_dev; cut_generators } as cxt )
(x : Ext_json_types.t String_map.t)
(* { dir : xx, files : ... } [dir] is already extracted *)
=
@@ -7642,36 +7756,42 @@ and parsing_source_dir_map
let cur_update_queue = ref [] in
let cur_globbed_dirs = ref [] in
let generators : build_generator list ref = ref [] in
- (* begin match String_map.find_opt Bsb_build_schemas.generators x with *)
- (* | Some (Arr { content }) -> *)
- (* (\* TODO: need check is dev build or not *\) *)
- (* content |> Array.iter (fun (x : Ext_json_types.t) -> *)
- (* match x with *)
- (* | Obj { map = generator; loc} -> *)
- (* begin match String_map.find_opt Bsb_build_schemas.input generator, *)
- (* String_map.find_opt Bsb_build_schemas.output generator, *)
- (* String_map.find_opt Bsb_build_schemas.cmd generator *)
- (* with *)
- (* | Some (Str{str = input}), Some (Str {str = output}), Some (Str {str = cmd})-> *)
- (* generators := {input ; output ; cmd } :: !generators; *)
- (* (\** Now adding source files, it may be re-added again later when scanning files *)
- (* *\) *)
- (* begin match Ext_string.is_valid_source_name output with *)
- (* | Good -> *)
- (* cur_sources := Binary_cache.map_update ~dir !cur_sources output *)
- (* | Invalid_module_name -> *)
- (* () *)
- (* (\*Format.fprintf Format.err_formatter warning_unused_file output dir *\) *)
- (* | Suffix_mismatch -> () *)
- (* end *)
- (* | _ -> *)
- (* Bsb_exception.failf ~loc "Invalid generator format" *)
- (* end *)
- (* | _ -> () *)
- (* ) *)
- (* | Some _ | None -> () *)
- (* end *)
- (* ; *)
+ begin match String_map.find_opt Bsb_build_schemas.generators x with
+ | Some (Arr { content ; loc_start}) ->
+ (* Need check is dev build or not *)
+ content
+ |> Array.iter (fun (x : Ext_json_types.t) ->
+ match x with
+ | Obj { map = generator; loc} ->
+ begin match String_map.find_opt Bsb_build_schemas.name generator,
+ String_map.find_opt Bsb_build_schemas.edge generator
+ with
+ | Some (Str{str = command}), Some (Arr {content })->
+
+ let output, input = get_input_output loc_start content in
+ if not cut_generators && not no_dev then begin
+ generators := {input ; output ; command } :: !generators
+ end;
+ (** Now adding source files, it may be re-added again later when scanning files *)
+ output |> List.iter begin fun output ->
+ begin match Ext_string.is_valid_source_name output with
+ | Good ->
+ cur_sources := Binary_cache.map_update ~dir !cur_sources output
+ | Invalid_module_name ->
+ ()
+ (*Format.fprintf Format.err_formatter warning_unused_file output dir *)
+ | Suffix_mismatch -> ()
+ end
+ end
+ | _ ->
+ Bsb_exception.failf ~loc "Invalid generator format"
+ end
+ | _ -> Bsb_exception.failf ~loc:(Ext_json.loc_of x) "Invalid generator format"
+ )
+ | Some x -> Bsb_exception.failf ~loc:(Ext_json.loc_of x ) "Invalid generators format"
+ | None -> ()
+ end
+ ;
begin match String_map.find_opt Bsb_build_schemas.files x with
| Some (Arr {loc_start;loc_end; content = [||] }) -> (* [ ] *)
let tasks, files = handle_list_files !cur_sources cxt loc_start loc_end in
@@ -8142,6 +8262,8 @@ type t =
generate_merlin : bool ;
reason_react_jsx : bool ; (* whether apply PPX transform or not*)
entries : entries_t list ;
+ generators : string String_map.t ;
+ cut_generators : bool; (* note when used as a dev mode, we will always ignore it *)
}
end
@@ -8575,6 +8697,7 @@ let interpret_json
let js_post_build_cmd = ref None in
let built_in_package = ref None in
let generate_merlin = ref true in
+ let generators = ref String_map.empty in
let package_specs = ref (String_set.singleton Literals.commonjs) in
(* When we plan to add more deps here,
Make sure check it is consistent that for nested deps, we have a
@@ -8588,7 +8711,7 @@ let interpret_json
2. we need store it so that we can call ninja correctly
*)
let entries = ref Bsb_default.main_entries in
-
+ let cut_generators = ref false in
let config_json_chan = open_in_bin config_json in
let global_data = Ext_json_parse.parse_json_from_chan config_json_chan in
match global_data with
@@ -8642,6 +8765,20 @@ let interpret_json
else Bsb_build_util.resolve_bsb_magic_file ~cwd ~desc:Bsb_build_schemas.ppx_flags p
)
))
+ |? (Bsb_build_schemas.cut_generators, `Bool (fun b -> cut_generators := b))
+ |? (Bsb_build_schemas.generators, `Arr (fun s ->
+ generators :=
+ Array.fold_left (fun acc json ->
+ match (json : Ext_json_types.t) with
+ | Obj {map = m ; loc} ->
+ begin match String_map.find_opt Bsb_build_schemas.name m,
+ String_map.find_opt Bsb_build_schemas.command m with
+ | Some (Str {str = name}), Some ( Str {str = command}) ->
+ String_map.add name command acc
+ | _, _ ->
+ Bsb_exception.failf ~loc {| generators exepect format like { "name" : "cppo", "command" : "cppo $in -o $out"} |}
+ end
+ | _ -> acc ) String_map.empty s ))
|? (Bsb_build_schemas.refmt, `Str (fun s ->
refmt := Some (Bsb_build_util.resolve_bsb_magic_file ~cwd ~desc:Bsb_build_schemas.refmt s) ))
|? (Bsb_build_schemas.refmt_flags, `Arr (fun s -> refmt_flags := get_list_string s))
@@ -8649,8 +8786,11 @@ let interpret_json
|> ignore ;
begin match String_map.find_opt Bsb_build_schemas.sources map with
| Some x ->
- let res = Bsb_build_ui.parsing_sources {no_dev; dir_index =
- Bsb_build_ui.lib_dir_index; cwd = Filename.current_dir_name; root = cwd} x in
+ let res = Bsb_build_ui.parsing_sources
+ {no_dev;
+ dir_index =
+ Bsb_build_ui.lib_dir_index; cwd = Filename.current_dir_name;
+ root = cwd; cut_generators = !cut_generators} x in
if generate_watch_metadata then
generate_sourcedirs_meta cwd res ;
begin match List.sort Ext_file_pp.interval_compare res.intervals with
@@ -8694,7 +8834,9 @@ let interpret_json
built_in_dependency = !built_in_package;
generate_merlin = !generate_merlin ;
reason_react_jsx = !reason_react_jsx ;
- entries = !entries
+ entries = !entries;
+ generators = !generators ;
+ cut_generators = !cut_generators
}
| None -> failwith "no sources specified, please checkout the schema for more details"
end
@@ -8983,14 +9125,8 @@ module Bsb_rule : sig
type t
-val get_name : t -> out_channel -> string
-val define :
- command:string ->
- ?depfile:string ->
- ?restat:unit ->
- ?description:string ->
- string -> t
+val get_name : t -> out_channel -> string
val build_ast_and_deps : t
val build_ast_and_deps_from_reason_impl : t
@@ -9003,7 +9139,18 @@ val build_cmj_js : t
val build_cmj_cmi_js : t
val build_cmi : t
-val reset : unit -> unit
+
+(** rules are generally composed of built-in rules and customized rules, there are two design choices:
+ 1. respect custom rules with the same name, then we need adjust our built-in
+ rules dynamically in case the conflict.
+ 2. respect our built-in rules, then we only need re-load custom rules for each bsconfig.json
+*)
+
+
+(** Since now we generate ninja files per bsconfig.json in a single process,
+ we must make sure it is re-entrant
+*)
+val reset : string String_map.t -> t String_map.t
end = struct
#1 "bsb_rule.ml"
@@ -9070,6 +9217,7 @@ let print_rule oc ~description ?restat ?depfile ~command name =
output_string oc " description = " ; output_string oc description; output_string oc "\n"
+(** allocate an unique name for such rule*)
let define
~command
?depfile
@@ -9077,19 +9225,23 @@ let define
?(description = "\027[34mBuilding\027[39m \027[2m${out}\027[22m") (* blue, dim *)
name
=
+ let rule_name = ask_name name in
let rec self = {
used = false;
- rule_name = ask_name name ;
+ rule_name ;
name = fun oc ->
if not self.used then
begin
- print_rule oc ~description ?depfile ?restat ~command name;
+ print_rule oc ~description ?depfile ?restat ~command rule_name;
self.used <- true
end ;
- self.rule_name
+ rule_name
} in self
+
+
+
let build_ast_and_deps =
define
~command:"${bsc} ${pp_flags} ${ppx_flags} ${bsc_flags} -c -o ${out} -bs-syntax-only -bs-binary-ast ${in}"
@@ -9174,20 +9326,30 @@ let build_cmi =
~depfile:"${in}.d"
"build_cmi" (* the compiler should always consult [.cmi], current the vanilla ocaml compiler only consult [.cmi] when [.mli] found*)
-let reset () =
- rule_id := 0;
- rule_names := String_set.empty;
- build_ast_and_deps.used <- false ;
- build_ast_and_deps_from_reason_impl.used <- false ;
- build_ast_and_deps_from_reason_intf.used <- false ;
- build_bin_deps.used <- false;
- reload.used <- false;
- copy_resources.used <- false ;
- build_ml_from_mll.used <- false ;
- build_cmj_js.used <- false;
- build_cmj_cmi_js.used <- false ;
- build_cmi.used <- false
+(* a snapshot of rule_names environment*)
+let built_in_rule_names = !rule_names
+let built_in_rule_id = !rule_id
+
+let reset (custom_rules : string String_map.t) =
+ begin
+ rule_id := built_in_rule_id;
+ rule_names := built_in_rule_names;
+
+ build_ast_and_deps.used <- false ;
+ build_ast_and_deps_from_reason_impl.used <- false ;
+ build_ast_and_deps_from_reason_intf.used <- false ;
+ build_bin_deps.used <- false;
+ reload.used <- false;
+ copy_resources.used <- false ;
+ build_ml_from_mll.used <- false ;
+ build_cmj_js.used <- false;
+ build_cmj_cmi_js.used <- false ;
+ build_cmi.used <- false ;
+ String_map.mapi (fun name command ->
+ define ~command name
+ ) custom_rules
+ end
end
@@ -9257,6 +9419,7 @@ val handle_file_groups : out_channel ->
package_specs:Bsb_config.package_specs ->
js_post_build_cmd:string option ->
files_to_install:String_hash_set.t ->
+ custom_rules:Bsb_rule.t String_map.t ->
Bsb_build_ui.file_group list ->
info -> info
@@ -9423,7 +9586,8 @@ let (++) (us : info) (vs : info) =
let install_file (file : string) files_to_install =
String_hash_set.add files_to_install (Ext_filename.chop_extension_if_any file )
-let handle_file_group oc ~package_specs ~js_post_build_cmd
+let handle_file_group oc ~custom_rules
+ ~package_specs ~js_post_build_cmd
(files_to_install : String_hash_set.t) acc (group: Bsb_build_ui.file_group) : info =
let handle_module_info oc module_name
( module_info : Binary_cache.module_info)
@@ -9433,11 +9597,11 @@ let handle_file_group oc ~package_specs ~js_post_build_cmd
| Export_all -> true
| Export_none -> false
| Export_set set -> String_set.mem module_name set in
- let emit_build (kind : [`Ml | `Mll | `Re | `Mli | `Rei ]) file_input : info =
+ let emit_build (kind : [`Ml | `Re | `Mli | `Rei ]) file_input : info =
let filename_sans_extension = Filename.chop_extension file_input in
let input = Bsb_config.proj_rel file_input in
let output_file_sans_extension = filename_sans_extension in
- let output_ml = output_file_sans_extension ^ Literals.suffix_ml in
+ (*let output_ml = output_file_sans_extension ^ Literals.suffix_ml in*)
let output_mlast = output_file_sans_extension ^ Literals.suffix_mlast in
let output_mlastd = output_file_sans_extension ^ Literals.suffix_mlastd in
let output_mliast = output_file_sans_extension ^ Literals.suffix_mliast in
@@ -9471,20 +9635,20 @@ let handle_file_group oc ~package_specs ~js_post_build_cmd
]
)
in
- if kind = `Mll then
+ (*if kind = `Mll then
output_build oc
~output:output_ml
~input
- ~rule: Rules.build_ml_from_mll ;
+ ~rule: Rules.build_ml_from_mll ;*)
begin match kind with
- | `Mll
+ (*| `Mll*)
| `Ml
| `Re ->
let input, rule =
if kind = `Re then
input, Rules.build_ast_and_deps_from_reason_impl
- else if kind = `Mll then
- output_ml, Rules.build_ast_and_deps
+ (*else if kind = `Mll then
+ output_ml, Rules.build_ast_and_deps*)
else
input, Rules.build_ast_and_deps
in
@@ -9572,25 +9736,29 @@ let handle_file_group oc ~package_specs ~js_post_build_cmd
emit_build `Rei rei_file
| Mli_empty -> zero
end ++
- begin match module_info.mll with
- | Some mll_file ->
- begin match module_info.ml with
- | Ml_empty -> emit_build `Mll mll_file
- | Ml input | Re input ->
- failwith ("both "^ mll_file ^ " and " ^ input ^ " are found in source listings" )
- end
- | None -> zero
- end ++ info
+ info
in
- (*
+ let map_to_source_dir =
+ (fun x -> Bsb_config.proj_rel (group.dir //x )) in
group.generators
- |> List.iter (fun ({output; input; cmd} : Bsb_build_ui.generator)->
- output_build oc ~output:(Bsb_config.proj_rel output)
- ~input:(Bsb_config.proj_rel input)
- ~rule:cmd
- );
- *) (* we need create a rule for it --
+ |> List.iter (fun ({output; input; command} : Bsb_build_ui.build_generator)->
+ begin match String_map.find_opt command custom_rules with
+ | None -> Ext_pervasives.failwithf ~loc:__LOC__ "custom rule %s used but not defined" command
+ | Some rule ->
+ begin match output, input with
+ | output::outputs, input::inputs ->
+ output_build oc
+ ~outputs:(List.map map_to_source_dir outputs)
+ ~inputs:(List.map map_to_source_dir inputs)
+ ~output:(map_to_source_dir output)
+ ~input:(map_to_source_dir input)
+ ~rule
+ | [], _ (* either output or input can not be empty *)
+ | _, [] -> assert false (* Error should be raised earlier *)
+ end
+ end
+ ); (* we need create a rule for it --
{[
rule ocamllex
]}
@@ -9604,9 +9772,9 @@ let handle_file_group oc ~package_specs ~js_post_build_cmd
let handle_file_groups
oc ~package_specs ~js_post_build_cmd
- ~files_to_install
+ ~files_to_install ~custom_rules
(file_groups : Bsb_build_ui.file_group list) st =
- List.fold_left (handle_file_group oc ~package_specs ~js_post_build_cmd files_to_install ) st file_groups
+ List.fold_left (handle_file_group oc ~package_specs ~custom_rules ~js_post_build_cmd files_to_install ) st file_groups
end
module Bsb_gen : sig
@@ -9694,30 +9862,29 @@ let dash_i = "-I"
let refmt_exe = "refmt.exe"
let dash_ppx = "-ppx"
-let ninja_required_version = "ninja_required_version = 1.5.1 \n"
-
let output_ninja
~cwd
~bsc_dir
- {
- Bsb_config_types.package_name;
- ocamllex;
- external_includes;
- bsc_flags ;
- ppx_flags;
- bs_dependencies;
- bs_dev_dependencies;
- refmt;
- refmt_flags;
- js_post_build_cmd;
- package_specs;
- bs_file_groups;
- files_to_install;
- built_in_dependency;
- reason_react_jsx
- }
+ ({
+ package_name;
+ ocamllex;
+ external_includes;
+ bsc_flags ;
+ ppx_flags;
+ bs_dependencies;
+ bs_dev_dependencies;
+ refmt;
+ refmt_flags;
+ js_post_build_cmd;
+ package_specs;
+ bs_file_groups;
+ files_to_install;
+ built_in_dependency;
+ reason_react_jsx;
+ generators ;
+ } : Bsb_config_types.t)
=
- let () = Bsb_rule.reset () in
+ let custom_rules = Bsb_rule.reset generators in
let bsc = bsc_dir // bsc_exe in (* The path to [bsc.exe] independent of config *)
let bsdep = bsc_dir // bsb_helper_exe in (* The path to [bsb_heler.exe] *)
(* let builddir = Bsb_config.lib_bs in *)
@@ -9727,7 +9894,6 @@ let output_ninja
let oc = open_out_bin (cwd // Bsb_config.lib_bs // Literals.build_ninja) in
begin
let () =
- output_string oc ninja_required_version ;
output_string oc "bs_package_flags = ";
output_string oc ("-bs-package-name " ^ package_name);
output_string oc "\n";
@@ -9805,7 +9971,8 @@ let output_ninja
static_resources;
in
let all_info =
- Bsb_ninja.handle_file_groups oc
+ Bsb_ninja.handle_file_groups oc
+ ~custom_rules
~js_post_build_cmd ~package_specs ~files_to_install bs_file_groups Bsb_ninja.zero in
let () =
List.iter (fun x -> Bsb_ninja.output_build oc
@@ -9900,32 +10067,51 @@ let root = OCamlRes.Res.([
"\n\
\n\
let () = Js.log \"Hello, BuckleScript\"")]) ;
- File (".gitignore",
- "*.exe\n\
- *.obj\n\
- *.out\n\
- *.compile\n\
- *.native\n\
- *.byte\n\
- *.cmo\n\
- *.annot\n\
- *.cmi\n\
- *.cmx\n\
- *.cmt\n\
- *.cmti\n\
- *.cma\n\
- *.a\n\
- *.cmxa\n\
- *.obj\n\
- *~\n\
- *.annot\n\
- *.cmj\n\
- *.bak\n\
- lib/bs\n\
- *.mlast\n\
- *.mliast\n\
- .vscode\n\
- .merlin") ;
+ File ("README.md",
+ "\n\
+ \n\
+ # Build\n\
+ ```\n\
+ npm run build\n\
+ ```\n\
+ \n\
+ # Watch\n\
+ \n\
+ ```\n\
+ npm run watch\n\
+ ```\n\
+ \n\
+ \n\
+ # Editor\n\
+ If you use `vscode`, Press `Windows + Shift + B` it will build automatically") ;
+ File ("package.json",
+ "{\n\
+ \ \"name\": \"${bsb:name}\",\n\
+ \ \"version\": \"${bsb:proj-version}\",\n\
+ \ \"scripts\": {\n\
+ \ \"clean\": \"bsb -clean-world\",\n\
+ \ \"build\": \"bsb -make-world\",\n\
+ \ \"watch\": \"bsb -make-world -w\"\n\
+ \ },\n\
+ \ \"keywords\": [\n\
+ \ \"BuckleScript\"\n\
+ \ ],\n\
+ \ \"license\": \"MIT\",\n\
+ \ \"devDependencies\": {\n\
+ \ \"bs-platform\": \"${bsb:bs-version}\"\n\
+ \ }\n\
+ }") ;
+ File ("bsconfig.json",
+ "{\n\
+ \ \"name\": \"${bsb:name}\",\n\
+ \ \"version\": \"${bsb:proj-version}\",\n\
+ \ \"sources\": [\n\
+ \ \"src\"\n\
+ \ ],\n\
+ \ \"bs-dependencies\" : [\n\
+ \ // add your bs-dependencies here \n\
+ \ ]\n\
+ }") ;
Dir (".vscode", [
File ("tasks.json",
"{\n\
@@ -9966,58 +10152,37 @@ let root = OCamlRes.Res.([
\ ]\n\
\ }\n\
}")]) ;
- File ("package.json",
- "{\n\
- \ \"name\": \"${bsb:name}\",\n\
- \ \"version\": \"${bsb:proj-version}\",\n\
- \ \"scripts\": {\n\
- \ \"clean\": \"bsb -clean-world\",\n\
- \ \"build\": \"bsb -make-world\",\n\
- \ \"watch\": \"bsb -make-world -w\"\n\
- \ },\n\
- \ \"keywords\": [\n\
- \ \"BuckleScript\"\n\
- \ ],\n\
- \ \"license\": \"MIT\",\n\
- \ \"devDependencies\": {\n\
- \ \"bs-platform\": \"${bsb:bs-version}\"\n\
- \ }\n\
- }") ;
- File ("bsconfig.json",
- "{\n\
- \ \"name\": \"${bsb:name}\",\n\
- \ \"version\": \"${bsb:proj-version}\",\n\
- \ \"sources\": [\n\
- \ \"src\"\n\
- \ ],\n\
- \ \"bs-dependencies\" : [\n\
- \ // add your bs-dependencies here \n\
- \ ]\n\
- }") ;
- File ("README.md",
- "\n\
- \n\
- # Build\n\
- ```\n\
- npm run build\n\
- ```\n\
- \n\
- # Watch\n\
- \n\
- ```\n\
- npm run watch\n\
- ```\n\
- \n\
- \n\
- # Editor\n\
- If you use `vscode`, Press `Windows + Shift + B` it will build automatically")]) ;
+ File (".gitignore",
+ "*.exe\n\
+ *.obj\n\
+ *.out\n\
+ *.compile\n\
+ *.native\n\
+ *.byte\n\
+ *.cmo\n\
+ *.annot\n\
+ *.cmi\n\
+ *.cmx\n\
+ *.cmt\n\
+ *.cmti\n\
+ *.cma\n\
+ *.a\n\
+ *.cmxa\n\
+ *.obj\n\
+ *~\n\
+ *.annot\n\
+ *.cmj\n\
+ *.bak\n\
+ lib/bs\n\
+ *.mlast\n\
+ *.mliast\n\
+ .vscode\n\
+ .merlin")]) ;
Dir ("minimal", [
Dir ("src", [ File ("main.ml", "")]) ;
- File (".gitignore",
- "lib\n\
- node_modules\n\
- .merlin\n\
- npm-debug.log") ;
+ File ("README.md",
+ "\n\
+ \ # ${bsb:name}") ;
File ("package.json",
"{\n\
\ \"name\": \"${bsb:name}\",\n\
@@ -10040,9 +10205,11 @@ let root = OCamlRes.Res.([
\ \"name\": \"${bsb:name}\",\n\
\ \"sources\": [\"src\"]\n\
}") ;
- File ("README.md",
- "\n\
- \ # ${bsb:name}")])
+ File (".gitignore",
+ "lib\n\
+ node_modules\n\
+ .merlin\n\
+ npm-debug.log")])
])
end
diff --git a/jscomp/bin/bsb_helper.ml b/jscomp/bin/bsb_helper.ml
index 792f83804b..3ae670f123 100644
--- a/jscomp/bin/bsb_helper.ml
+++ b/jscomp/bin/bsb_helper.ml
@@ -654,7 +654,8 @@ let is_valid_source_name name : check_result =
match check_any_suffix_case_then_chop name [
".ml";
".re";
- ".mli"; ".mll"; ".rei"
+ ".mli";
+ ".rei"
] with
| None -> Suffix_mismatch
| Some x ->
@@ -4017,7 +4018,6 @@ type module_info =
{
mli : mli_kind ;
ml : ml_kind ;
- mll : string option
}
type file_group_rouces = module_info String_map.t
@@ -4085,7 +4085,7 @@ type module_info =
{
mli : mli_kind ;
ml : ml_kind ;
- mll : string option ;
+ (*mll : string option ;*)
}
@@ -4100,7 +4100,7 @@ let module_info_magic_number = "BSBUILD20161019"
let dir_of_module_info (x : module_info)
=
match x with
- | { mli; ml; mll} ->
+ | { mli; ml; } ->
begin match mli with
| Mli s | Rei s ->
Filename.dirname s
@@ -4108,11 +4108,11 @@ let dir_of_module_info (x : module_info)
begin match ml with
| Ml s | Re s ->
Filename.dirname s
- | Ml_empty ->
- begin match mll with
+ | Ml_empty -> Ext_string.empty
+ (*begin match mll with
| None -> ""
| Some s -> Filename.dirname s
- end
+ end *)
end
end
@@ -4134,7 +4134,7 @@ let read_build_cache bsbuild : t =
let bsbuild_cache = ".bsbuild"
-let empty_module_info = {mli = Mli_empty ; mll = None ; ml = Ml_empty}
+let empty_module_info = {mli = Mli_empty ; ml = Ml_empty}
let adjust_module_info x suffix name =
match suffix with
@@ -4142,7 +4142,6 @@ let adjust_module_info x suffix name =
| ".re" -> {x with ml = Re name}
| ".mli" -> {x with mli = Mli name}
| ".rei" -> { x with mli = Rei name}
- | ".mll" -> {x with mll = Some name}
| _ -> failwith ("don't know what to do with " ^ name)
let map_update ?dir (map : file_group_rouces) name : file_group_rouces =
@@ -4266,7 +4265,7 @@ let handle_bin_depfile
Array.fold_left
(fun ((acc, len) as v) k ->
match String_map.find_opt k data.(0) with
- | Some ({ml = Ml s | Re s } | {mll = Some s })
+ | Some {ml = Ml s | Re s }
->
let new_file = op_concat @@ Filename.chop_extension s ^ suffix_inteface
in (new_file :: acc , len + String.length new_file + length_space)
@@ -4278,7 +4277,7 @@ let handle_bin_depfile
if index = 0 then v
else
begin match String_map.find_opt k data.(index) with
- | Some ({ml = Ml s | Re s } | {mll = Some s })
+ | Some {ml = Ml s | Re s }
->
let new_file = op_concat @@ Filename.chop_extension s ^ suffix_inteface
in (new_file :: acc , len + String.length new_file + length_space)
@@ -4306,7 +4305,6 @@ let handle_bin_depfile
(fun ((acc, len) as v) k ->
match String_map.find_opt k data.(0) with
| Some ({ ml = Ml f | Re f }
- | { mll = Some f }
| { mli = Mli f | Rei f }) ->
let new_file = (op_concat @@ Filename.chop_extension f ^ Literals.suffix_cmi) in
(new_file :: acc , len + String.length new_file + length_space)
@@ -4316,7 +4314,6 @@ let handle_bin_depfile
else
begin match String_map.find_opt k data.(index) with
| Some ({ ml = Ml f | Re f }
- | { mll = Some f }
| { mli = Mli f | Rei f }) ->
let new_file = (op_concat @@ Filename.chop_extension f ^ Literals.suffix_cmi) in
(new_file :: acc , len + String.length new_file + length_space)
diff --git a/jscomp/bin/bsb_watcher.js b/jscomp/bin/bsb_watcher.js
index 7ffa63ab5d..47cd693345 100644
--- a/jscomp/bin/bsb_watcher.js
+++ b/jscomp/bin/bsb_watcher.js
@@ -106,7 +106,7 @@ function build() {
*/
function on_change(event, reason) {
if(validEvent(event,reason)){
- console.log("Event", event);
+ console.log("Event", event, reason);
reasons_to_rebuild.push([event, reason])
if(needRebuild()){
build()
diff --git a/jscomp/bin/bsdep.ml b/jscomp/bin/bsdep.ml
index 5bc6bca6ac..e8a6c9f21a 100644
--- a/jscomp/bin/bsdep.ml
+++ b/jscomp/bin/bsdep.ml
@@ -23680,7 +23680,8 @@ let is_valid_source_name name : check_result =
match check_any_suffix_case_then_chop name [
".ml";
".re";
- ".mli"; ".mll"; ".rei"
+ ".mli";
+ ".rei"
] with
| None -> Suffix_mismatch
| Some x ->
@@ -28858,6 +28859,12 @@ val find_and_split :
val exists : ('a -> bool) -> 'a array -> bool
val is_empty : 'a array -> bool
+
+val for_all2_no_exn :
+ ('a -> 'b -> bool) ->
+ 'a array ->
+ 'b array ->
+ bool
end = struct
#1 "ext_array.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
@@ -29046,6 +29053,21 @@ let exists p a =
let is_empty arr =
Array.length arr = 0
+
+
+let rec unsafe_loop index len p xs ys =
+ if index >= len then true
+ else
+ p
+ (Array.unsafe_get xs index)
+ (Array.unsafe_get ys index) &&
+ unsafe_loop (succ index) len p xs ys
+
+let for_all2_no_exn p xs ys =
+ let len_xs = Array.length xs in
+ let len_ys = Array.length ys in
+ len_xs = len_ys &&
+ unsafe_loop 0 len_xs p xs ys
end
module Ext_json_types
= struct
diff --git a/jscomp/bin/bsppx.ml b/jscomp/bin/bsppx.ml
index 716ba306c0..123788fe2d 100644
--- a/jscomp/bin/bsppx.ml
+++ b/jscomp/bin/bsppx.ml
@@ -5628,7 +5628,8 @@ let is_valid_source_name name : check_result =
match check_any_suffix_case_then_chop name [
".ml";
".re";
- ".mli"; ".mll"; ".rei"
+ ".mli";
+ ".rei"
] with
| None -> Suffix_mismatch
| Some x ->
@@ -10806,6 +10807,12 @@ val find_and_split :
val exists : ('a -> bool) -> 'a array -> bool
val is_empty : 'a array -> bool
+
+val for_all2_no_exn :
+ ('a -> 'b -> bool) ->
+ 'a array ->
+ 'b array ->
+ bool
end = struct
#1 "ext_array.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
@@ -10994,6 +11001,21 @@ let exists p a =
let is_empty arr =
Array.length arr = 0
+
+
+let rec unsafe_loop index len p xs ys =
+ if index >= len then true
+ else
+ p
+ (Array.unsafe_get xs index)
+ (Array.unsafe_get ys index) &&
+ unsafe_loop (succ index) len p xs ys
+
+let for_all2_no_exn p xs ys =
+ let len_xs = Array.length xs in
+ let len_ys = Array.length ys in
+ len_xs = len_ys &&
+ unsafe_loop 0 len_xs p xs ys
end
module Ext_json_types
= struct
diff --git a/jscomp/bin/whole_compiler.ml b/jscomp/bin/whole_compiler.ml
index 2d7cbd45b8..ab9349c140 100644
--- a/jscomp/bin/whole_compiler.ml
+++ b/jscomp/bin/whole_compiler.ml
@@ -21186,7 +21186,8 @@ let is_valid_source_name name : check_result =
match check_any_suffix_case_then_chop name [
".ml";
".re";
- ".mli"; ".mll"; ".rei"
+ ".mli";
+ ".rei"
] with
| None -> Suffix_mismatch
| Some x ->
@@ -58856,6 +58857,12 @@ val find_and_split :
val exists : ('a -> bool) -> 'a array -> bool
val is_empty : 'a array -> bool
+
+val for_all2_no_exn :
+ ('a -> 'b -> bool) ->
+ 'a array ->
+ 'b array ->
+ bool
end = struct
#1 "ext_array.ml"
(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
@@ -59044,6 +59051,21 @@ let exists p a =
let is_empty arr =
Array.length arr = 0
+
+
+let rec unsafe_loop index len p xs ys =
+ if index >= len then true
+ else
+ p
+ (Array.unsafe_get xs index)
+ (Array.unsafe_get ys index) &&
+ unsafe_loop (succ index) len p xs ys
+
+let for_all2_no_exn p xs ys =
+ let len_xs = Array.length xs in
+ let len_ys = Array.length ys in
+ len_xs = len_ys &&
+ unsafe_loop 0 len_xs p xs ys
end
module Ext_json_types
= struct
diff --git a/jscomp/bsb/bsb_build_ui.ml b/jscomp/bsb/bsb_build_ui.ml
index 909b5908aa..bab20a509e 100644
--- a/jscomp/bsb/bsb_build_ui.ml
+++ b/jscomp/bsb/bsb_build_ui.ml
@@ -111,7 +111,8 @@ type parsing_cxt = {
no_dev : bool ;
dir_index : dir_index ;
cwd : string ;
- root : string
+ root : string;
+ cut_generators : bool
}
let handle_list_files acc
@@ -157,6 +158,29 @@ let (++) (u : t) (v : t) =
globbed_dirs = u.globbed_dirs @ v.globbed_dirs ;
}
+let get_input_output loc_start (content : Ext_json_types.t array) =
+ let error () =
+ Bsb_exception.failf ~loc:loc_start {| invalid edge format, expect ["input" , ":", "output" ]|}
+ in
+ match Ext_array.find_and_split content
+ (fun x () -> match x with Str { str =":"} -> true | _ -> false )
+ () with
+ | `No_split -> error ()
+ | `Split ( output, input) ->
+ Ext_array.to_list_map (fun (x : Ext_json_types.t) ->
+ match x with
+ | Str {str = ":"} ->
+ error ()
+ | Str {str } ->
+ Some str
+ | _ -> None) output ,
+ Ext_array.to_list_map (fun (x : Ext_json_types.t) ->
+ match x with
+ | Str {str = ":"} ->
+ error ()
+ | Str {str} ->
+ Some str (* More rigirous error checking: It would trigger a ninja syntax error *)
+ | _ -> None) input
(** [dir_index] can be inherited *)
let rec
@@ -196,7 +220,7 @@ and parsing_source ({no_dev; dir_index ; cwd} as cxt ) (x : Ext_json_types.t )
| _ -> empty
and parsing_source_dir_map
- ({ cwd = dir} as cxt )
+ ({ cwd = dir; no_dev; cut_generators } as cxt )
(x : Ext_json_types.t String_map.t)
(* { dir : xx, files : ... } [dir] is already extracted *)
=
@@ -206,36 +230,42 @@ and parsing_source_dir_map
let cur_update_queue = ref [] in
let cur_globbed_dirs = ref [] in
let generators : build_generator list ref = ref [] in
- (* begin match String_map.find_opt Bsb_build_schemas.generators x with *)
- (* | Some (Arr { content }) -> *)
- (* (\* TODO: need check is dev build or not *\) *)
- (* content |> Array.iter (fun (x : Ext_json_types.t) -> *)
- (* match x with *)
- (* | Obj { map = generator; loc} -> *)
- (* begin match String_map.find_opt Bsb_build_schemas.input generator, *)
- (* String_map.find_opt Bsb_build_schemas.output generator, *)
- (* String_map.find_opt Bsb_build_schemas.cmd generator *)
- (* with *)
- (* | Some (Str{str = input}), Some (Str {str = output}), Some (Str {str = cmd})-> *)
- (* generators := {input ; output ; cmd } :: !generators; *)
- (* (\** Now adding source files, it may be re-added again later when scanning files *)
- (* *\) *)
- (* begin match Ext_string.is_valid_source_name output with *)
- (* | Good -> *)
- (* cur_sources := Binary_cache.map_update ~dir !cur_sources output *)
- (* | Invalid_module_name -> *)
- (* () *)
- (* (\*Format.fprintf Format.err_formatter warning_unused_file output dir *\) *)
- (* | Suffix_mismatch -> () *)
- (* end *)
- (* | _ -> *)
- (* Bsb_exception.failf ~loc "Invalid generator format" *)
- (* end *)
- (* | _ -> () *)
- (* ) *)
- (* | Some _ | None -> () *)
- (* end *)
- (* ; *)
+ begin match String_map.find_opt Bsb_build_schemas.generators x with
+ | Some (Arr { content ; loc_start}) ->
+ (* Need check is dev build or not *)
+ content
+ |> Array.iter (fun (x : Ext_json_types.t) ->
+ match x with
+ | Obj { map = generator; loc} ->
+ begin match String_map.find_opt Bsb_build_schemas.name generator,
+ String_map.find_opt Bsb_build_schemas.edge generator
+ with
+ | Some (Str{str = command}), Some (Arr {content })->
+
+ let output, input = get_input_output loc_start content in
+ if not cut_generators && not no_dev then begin
+ generators := {input ; output ; command } :: !generators
+ end;
+ (** Now adding source files, it may be re-added again later when scanning files *)
+ output |> List.iter begin fun output ->
+ begin match Ext_string.is_valid_source_name output with
+ | Good ->
+ cur_sources := Binary_cache.map_update ~dir !cur_sources output
+ | Invalid_module_name ->
+ ()
+ (*Format.fprintf Format.err_formatter warning_unused_file output dir *)
+ | Suffix_mismatch -> ()
+ end
+ end
+ | _ ->
+ Bsb_exception.failf ~loc "Invalid generator format"
+ end
+ | _ -> Bsb_exception.failf ~loc:(Ext_json.loc_of x) "Invalid generator format"
+ )
+ | Some x -> Bsb_exception.failf ~loc:(Ext_json.loc_of x ) "Invalid generators format"
+ | None -> ()
+ end
+ ;
begin match String_map.find_opt Bsb_build_schemas.files x with
| Some (Arr {loc_start;loc_end; content = [||] }) -> (* [ ] *)
let tasks, files = handle_list_files !cur_sources cxt loc_start loc_end in
diff --git a/jscomp/bsb/bsb_build_ui.mli b/jscomp/bsb/bsb_build_ui.mli
index 346c819c9d..efdfb07687 100644
--- a/jscomp/bsb/bsb_build_ui.mli
+++ b/jscomp/bsb/bsb_build_ui.mli
@@ -46,7 +46,7 @@ type file_group =
type t =
- { files : file_group list ;
+ { files : file_group list ; (* flattened list of directories *)
intervals : Ext_file_pp.interval list ;
globbed_dirs : string list ;
@@ -60,7 +60,8 @@ type parsing_cxt = {
no_dev : bool ;
dir_index : dir_index ;
cwd : string ;
- root : string
+ root : string ;
+ cut_generators : bool
}
diff --git a/jscomp/bsb/bsb_config_parse.ml b/jscomp/bsb/bsb_config_parse.ml
index ea75b0c8db..88e1572fdb 100644
--- a/jscomp/bsb/bsb_config_parse.ml
+++ b/jscomp/bsb/bsb_config_parse.ml
@@ -275,6 +275,7 @@ let interpret_json
let js_post_build_cmd = ref None in
let built_in_package = ref None in
let generate_merlin = ref true in
+ let generators = ref String_map.empty in
let package_specs = ref (String_set.singleton Literals.commonjs) in
(* When we plan to add more deps here,
Make sure check it is consistent that for nested deps, we have a
@@ -288,7 +289,7 @@ let interpret_json
2. we need store it so that we can call ninja correctly
*)
let entries = ref Bsb_default.main_entries in
-
+ let cut_generators = ref false in
let config_json_chan = open_in_bin config_json in
let global_data = Ext_json_parse.parse_json_from_chan config_json_chan in
match global_data with
@@ -342,6 +343,20 @@ let interpret_json
else Bsb_build_util.resolve_bsb_magic_file ~cwd ~desc:Bsb_build_schemas.ppx_flags p
)
))
+ |? (Bsb_build_schemas.cut_generators, `Bool (fun b -> cut_generators := b))
+ |? (Bsb_build_schemas.generators, `Arr (fun s ->
+ generators :=
+ Array.fold_left (fun acc json ->
+ match (json : Ext_json_types.t) with
+ | Obj {map = m ; loc} ->
+ begin match String_map.find_opt Bsb_build_schemas.name m,
+ String_map.find_opt Bsb_build_schemas.command m with
+ | Some (Str {str = name}), Some ( Str {str = command}) ->
+ String_map.add name command acc
+ | _, _ ->
+ Bsb_exception.failf ~loc {| generators exepect format like { "name" : "cppo", "command" : "cppo $in -o $out"} |}
+ end
+ | _ -> acc ) String_map.empty s ))
|? (Bsb_build_schemas.refmt, `Str (fun s ->
refmt := Some (Bsb_build_util.resolve_bsb_magic_file ~cwd ~desc:Bsb_build_schemas.refmt s) ))
|? (Bsb_build_schemas.refmt_flags, `Arr (fun s -> refmt_flags := get_list_string s))
@@ -349,8 +364,11 @@ let interpret_json
|> ignore ;
begin match String_map.find_opt Bsb_build_schemas.sources map with
| Some x ->
- let res = Bsb_build_ui.parsing_sources {no_dev; dir_index =
- Bsb_build_ui.lib_dir_index; cwd = Filename.current_dir_name; root = cwd} x in
+ let res = Bsb_build_ui.parsing_sources
+ {no_dev;
+ dir_index =
+ Bsb_build_ui.lib_dir_index; cwd = Filename.current_dir_name;
+ root = cwd; cut_generators = !cut_generators} x in
if generate_watch_metadata then
generate_sourcedirs_meta cwd res ;
begin match List.sort Ext_file_pp.interval_compare res.intervals with
@@ -394,7 +412,9 @@ let interpret_json
built_in_dependency = !built_in_package;
generate_merlin = !generate_merlin ;
reason_react_jsx = !reason_react_jsx ;
- entries = !entries
+ entries = !entries;
+ generators = !generators ;
+ cut_generators = !cut_generators
}
| None -> failwith "no sources specified, please checkout the schema for more details"
end
diff --git a/jscomp/bsb/bsb_config_types.ml b/jscomp/bsb/bsb_config_types.ml
index 6428003038..d198ac7249 100644
--- a/jscomp/bsb/bsb_config_types.ml
+++ b/jscomp/bsb/bsb_config_types.ml
@@ -57,4 +57,6 @@ type t =
generate_merlin : bool ;
reason_react_jsx : bool ; (* whether apply PPX transform or not*)
entries : entries_t list ;
+ generators : string String_map.t ;
+ cut_generators : bool; (* note when used as a dev mode, we will always ignore it *)
}
diff --git a/jscomp/bsb/bsb_gen.ml b/jscomp/bsb/bsb_gen.ml
index d7b63b4429..38d3ca8ead 100644
--- a/jscomp/bsb/bsb_gen.ml
+++ b/jscomp/bsb/bsb_gen.ml
@@ -47,30 +47,29 @@ let dash_i = "-I"
let refmt_exe = "refmt.exe"
let dash_ppx = "-ppx"
-let ninja_required_version = "ninja_required_version = 1.5.1 \n"
-
let output_ninja
~cwd
~bsc_dir
- {
- Bsb_config_types.package_name;
- ocamllex;
- external_includes;
- bsc_flags ;
- ppx_flags;
- bs_dependencies;
- bs_dev_dependencies;
- refmt;
- refmt_flags;
- js_post_build_cmd;
- package_specs;
- bs_file_groups;
- files_to_install;
- built_in_dependency;
- reason_react_jsx
- }
+ ({
+ package_name;
+ ocamllex;
+ external_includes;
+ bsc_flags ;
+ ppx_flags;
+ bs_dependencies;
+ bs_dev_dependencies;
+ refmt;
+ refmt_flags;
+ js_post_build_cmd;
+ package_specs;
+ bs_file_groups;
+ files_to_install;
+ built_in_dependency;
+ reason_react_jsx;
+ generators ;
+ } : Bsb_config_types.t)
=
- let () = Bsb_rule.reset () in
+ let custom_rules = Bsb_rule.reset generators in
let bsc = bsc_dir // bsc_exe in (* The path to [bsc.exe] independent of config *)
let bsdep = bsc_dir // bsb_helper_exe in (* The path to [bsb_heler.exe] *)
(* let builddir = Bsb_config.lib_bs in *)
@@ -80,7 +79,6 @@ let output_ninja
let oc = open_out_bin (cwd // Bsb_config.lib_bs // Literals.build_ninja) in
begin
let () =
- output_string oc ninja_required_version ;
output_string oc "bs_package_flags = ";
output_string oc ("-bs-package-name " ^ package_name);
output_string oc "\n";
@@ -158,7 +156,8 @@ let output_ninja
static_resources;
in
let all_info =
- Bsb_ninja.handle_file_groups oc
+ Bsb_ninja.handle_file_groups oc
+ ~custom_rules
~js_post_build_cmd ~package_specs ~files_to_install bs_file_groups Bsb_ninja.zero in
let () =
List.iter (fun x -> Bsb_ninja.output_build oc
diff --git a/jscomp/bsb/bsb_ninja.ml b/jscomp/bsb/bsb_ninja.ml
index 214bb6ad06..7b3ef82f0f 100644
--- a/jscomp/bsb/bsb_ninja.ml
+++ b/jscomp/bsb/bsb_ninja.ml
@@ -156,7 +156,8 @@ let (++) (us : info) (vs : info) =
let install_file (file : string) files_to_install =
String_hash_set.add files_to_install (Ext_filename.chop_extension_if_any file )
-let handle_file_group oc ~package_specs ~js_post_build_cmd
+let handle_file_group oc ~custom_rules
+ ~package_specs ~js_post_build_cmd
(files_to_install : String_hash_set.t) acc (group: Bsb_build_ui.file_group) : info =
let handle_module_info oc module_name
( module_info : Binary_cache.module_info)
@@ -166,11 +167,11 @@ let handle_file_group oc ~package_specs ~js_post_build_cmd
| Export_all -> true
| Export_none -> false
| Export_set set -> String_set.mem module_name set in
- let emit_build (kind : [`Ml | `Mll | `Re | `Mli | `Rei ]) file_input : info =
+ let emit_build (kind : [`Ml | `Re | `Mli | `Rei ]) file_input : info =
let filename_sans_extension = Filename.chop_extension file_input in
let input = Bsb_config.proj_rel file_input in
let output_file_sans_extension = filename_sans_extension in
- let output_ml = output_file_sans_extension ^ Literals.suffix_ml in
+ (*let output_ml = output_file_sans_extension ^ Literals.suffix_ml in*)
let output_mlast = output_file_sans_extension ^ Literals.suffix_mlast in
let output_mlastd = output_file_sans_extension ^ Literals.suffix_mlastd in
let output_mliast = output_file_sans_extension ^ Literals.suffix_mliast in
@@ -204,20 +205,20 @@ let handle_file_group oc ~package_specs ~js_post_build_cmd
]
)
in
- if kind = `Mll then
+ (*if kind = `Mll then
output_build oc
~output:output_ml
~input
- ~rule: Rules.build_ml_from_mll ;
+ ~rule: Rules.build_ml_from_mll ;*)
begin match kind with
- | `Mll
+ (*| `Mll*)
| `Ml
| `Re ->
let input, rule =
if kind = `Re then
input, Rules.build_ast_and_deps_from_reason_impl
- else if kind = `Mll then
- output_ml, Rules.build_ast_and_deps
+ (*else if kind = `Mll then
+ output_ml, Rules.build_ast_and_deps*)
else
input, Rules.build_ast_and_deps
in
@@ -305,25 +306,29 @@ let handle_file_group oc ~package_specs ~js_post_build_cmd
emit_build `Rei rei_file
| Mli_empty -> zero
end ++
- begin match module_info.mll with
- | Some mll_file ->
- begin match module_info.ml with
- | Ml_empty -> emit_build `Mll mll_file
- | Ml input | Re input ->
- failwith ("both "^ mll_file ^ " and " ^ input ^ " are found in source listings" )
- end
- | None -> zero
- end ++ info
+ info
in
- (*
+ let map_to_source_dir =
+ (fun x -> Bsb_config.proj_rel (group.dir //x )) in
group.generators
- |> List.iter (fun ({output; input; cmd} : Bsb_build_ui.generator)->
- output_build oc ~output:(Bsb_config.proj_rel output)
- ~input:(Bsb_config.proj_rel input)
- ~rule:cmd
- );
- *) (* we need create a rule for it --
+ |> List.iter (fun ({output; input; command} : Bsb_build_ui.build_generator)->
+ begin match String_map.find_opt command custom_rules with
+ | None -> Ext_pervasives.failwithf ~loc:__LOC__ "custom rule %s used but not defined" command
+ | Some rule ->
+ begin match output, input with
+ | output::outputs, input::inputs ->
+ output_build oc
+ ~outputs:(List.map map_to_source_dir outputs)
+ ~inputs:(List.map map_to_source_dir inputs)
+ ~output:(map_to_source_dir output)
+ ~input:(map_to_source_dir input)
+ ~rule
+ | [], _ (* either output or input can not be empty *)
+ | _, [] -> assert false (* Error should be raised earlier *)
+ end
+ end
+ ); (* we need create a rule for it --
{[
rule ocamllex
]}
@@ -337,6 +342,6 @@ let handle_file_group oc ~package_specs ~js_post_build_cmd
let handle_file_groups
oc ~package_specs ~js_post_build_cmd
- ~files_to_install
+ ~files_to_install ~custom_rules
(file_groups : Bsb_build_ui.file_group list) st =
- List.fold_left (handle_file_group oc ~package_specs ~js_post_build_cmd files_to_install ) st file_groups
+ List.fold_left (handle_file_group oc ~package_specs ~custom_rules ~js_post_build_cmd files_to_install ) st file_groups
diff --git a/jscomp/bsb/bsb_ninja.mli b/jscomp/bsb/bsb_ninja.mli
index a895f04752..6eab6b6b7b 100644
--- a/jscomp/bsb/bsb_ninja.mli
+++ b/jscomp/bsb/bsb_ninja.mli
@@ -62,6 +62,7 @@ val handle_file_groups : out_channel ->
package_specs:Bsb_config.package_specs ->
js_post_build_cmd:string option ->
files_to_install:String_hash_set.t ->
+ custom_rules:Bsb_rule.t String_map.t ->
Bsb_build_ui.file_group list ->
info -> info
diff --git a/jscomp/bsb/bsb_rule.ml b/jscomp/bsb/bsb_rule.ml
index 7c86cdb6c3..e0862c5814 100644
--- a/jscomp/bsb/bsb_rule.ml
+++ b/jscomp/bsb/bsb_rule.ml
@@ -61,6 +61,7 @@ let print_rule oc ~description ?restat ?depfile ~command name =
output_string oc " description = " ; output_string oc description; output_string oc "\n"
+(** allocate an unique name for such rule*)
let define
~command
?depfile
@@ -68,19 +69,23 @@ let define
?(description = "\027[34mBuilding\027[39m \027[2m${out}\027[22m") (* blue, dim *)
name
=
+ let rule_name = ask_name name in
let rec self = {
used = false;
- rule_name = ask_name name ;
+ rule_name ;
name = fun oc ->
if not self.used then
begin
- print_rule oc ~description ?depfile ?restat ~command name;
+ print_rule oc ~description ?depfile ?restat ~command rule_name;
self.used <- true
end ;
- self.rule_name
+ rule_name
} in self
+
+
+
let build_ast_and_deps =
define
~command:"${bsc} ${pp_flags} ${ppx_flags} ${bsc_flags} -c -o ${out} -bs-syntax-only -bs-binary-ast ${in}"
@@ -165,18 +170,28 @@ let build_cmi =
~depfile:"${in}.d"
"build_cmi" (* the compiler should always consult [.cmi], current the vanilla ocaml compiler only consult [.cmi] when [.mli] found*)
-let reset () =
- rule_id := 0;
- rule_names := String_set.empty;
- build_ast_and_deps.used <- false ;
- build_ast_and_deps_from_reason_impl.used <- false ;
- build_ast_and_deps_from_reason_intf.used <- false ;
- build_bin_deps.used <- false;
- reload.used <- false;
- copy_resources.used <- false ;
- build_ml_from_mll.used <- false ;
- build_cmj_js.used <- false;
- build_cmj_cmi_js.used <- false ;
- build_cmi.used <- false
+(* a snapshot of rule_names environment*)
+let built_in_rule_names = !rule_names
+let built_in_rule_id = !rule_id
+
+let reset (custom_rules : string String_map.t) =
+ begin
+ rule_id := built_in_rule_id;
+ rule_names := built_in_rule_names;
+
+ build_ast_and_deps.used <- false ;
+ build_ast_and_deps_from_reason_impl.used <- false ;
+ build_ast_and_deps_from_reason_intf.used <- false ;
+ build_bin_deps.used <- false;
+ reload.used <- false;
+ copy_resources.used <- false ;
+ build_ml_from_mll.used <- false ;
+ build_cmj_js.used <- false;
+ build_cmj_cmi_js.used <- false ;
+ build_cmi.used <- false ;
+ String_map.mapi (fun name command ->
+ define ~command name
+ ) custom_rules
+ end
diff --git a/jscomp/bsb/bsb_rule.mli b/jscomp/bsb/bsb_rule.mli
index ef256fb5b6..0ead6cdeb7 100644
--- a/jscomp/bsb/bsb_rule.mli
+++ b/jscomp/bsb/bsb_rule.mli
@@ -26,14 +26,8 @@
type t
-val get_name : t -> out_channel -> string
-val define :
- command:string ->
- ?depfile:string ->
- ?restat:unit ->
- ?description:string ->
- string -> t
+val get_name : t -> out_channel -> string
val build_ast_and_deps : t
val build_ast_and_deps_from_reason_impl : t
@@ -46,4 +40,15 @@ val build_cmj_js : t
val build_cmj_cmi_js : t
val build_cmi : t
-val reset : unit -> unit
+
+(** rules are generally composed of built-in rules and customized rules, there are two design choices:
+ 1. respect custom rules with the same name, then we need adjust our built-in
+ rules dynamically in case the conflict.
+ 2. respect our built-in rules, then we only need re-load custom rules for each bsconfig.json
+*)
+
+
+(** Since now we generate ninja files per bsconfig.json in a single process,
+ we must make sure it is re-entrant
+*)
+val reset : string String_map.t -> t String_map.t
diff --git a/jscomp/bsb/bsb_templates.ml b/jscomp/bsb/bsb_templates.ml
index 1bf95f1b38..7589899779 100644
--- a/jscomp/bsb/bsb_templates.ml
+++ b/jscomp/bsb/bsb_templates.ml
@@ -6,32 +6,51 @@ let root = OCamlRes.Res.([
"\n\
\n\
let () = Js.log \"Hello, BuckleScript\"")]) ;
- File (".gitignore",
- "*.exe\n\
- *.obj\n\
- *.out\n\
- *.compile\n\
- *.native\n\
- *.byte\n\
- *.cmo\n\
- *.annot\n\
- *.cmi\n\
- *.cmx\n\
- *.cmt\n\
- *.cmti\n\
- *.cma\n\
- *.a\n\
- *.cmxa\n\
- *.obj\n\
- *~\n\
- *.annot\n\
- *.cmj\n\
- *.bak\n\
- lib/bs\n\
- *.mlast\n\
- *.mliast\n\
- .vscode\n\
- .merlin") ;
+ File ("README.md",
+ "\n\
+ \n\
+ # Build\n\
+ ```\n\
+ npm run build\n\
+ ```\n\
+ \n\
+ # Watch\n\
+ \n\
+ ```\n\
+ npm run watch\n\
+ ```\n\
+ \n\
+ \n\
+ # Editor\n\
+ If you use `vscode`, Press `Windows + Shift + B` it will build automatically") ;
+ File ("package.json",
+ "{\n\
+ \ \"name\": \"${bsb:name}\",\n\
+ \ \"version\": \"${bsb:proj-version}\",\n\
+ \ \"scripts\": {\n\
+ \ \"clean\": \"bsb -clean-world\",\n\
+ \ \"build\": \"bsb -make-world\",\n\
+ \ \"watch\": \"bsb -make-world -w\"\n\
+ \ },\n\
+ \ \"keywords\": [\n\
+ \ \"BuckleScript\"\n\
+ \ ],\n\
+ \ \"license\": \"MIT\",\n\
+ \ \"devDependencies\": {\n\
+ \ \"bs-platform\": \"${bsb:bs-version}\"\n\
+ \ }\n\
+ }") ;
+ File ("bsconfig.json",
+ "{\n\
+ \ \"name\": \"${bsb:name}\",\n\
+ \ \"version\": \"${bsb:proj-version}\",\n\
+ \ \"sources\": [\n\
+ \ \"src\"\n\
+ \ ],\n\
+ \ \"bs-dependencies\" : [\n\
+ \ // add your bs-dependencies here \n\
+ \ ]\n\
+ }") ;
Dir (".vscode", [
File ("tasks.json",
"{\n\
@@ -72,58 +91,37 @@ let root = OCamlRes.Res.([
\ ]\n\
\ }\n\
}")]) ;
- File ("package.json",
- "{\n\
- \ \"name\": \"${bsb:name}\",\n\
- \ \"version\": \"${bsb:proj-version}\",\n\
- \ \"scripts\": {\n\
- \ \"clean\": \"bsb -clean-world\",\n\
- \ \"build\": \"bsb -make-world\",\n\
- \ \"watch\": \"bsb -make-world -w\"\n\
- \ },\n\
- \ \"keywords\": [\n\
- \ \"BuckleScript\"\n\
- \ ],\n\
- \ \"license\": \"MIT\",\n\
- \ \"devDependencies\": {\n\
- \ \"bs-platform\": \"${bsb:bs-version}\"\n\
- \ }\n\
- }") ;
- File ("bsconfig.json",
- "{\n\
- \ \"name\": \"${bsb:name}\",\n\
- \ \"version\": \"${bsb:proj-version}\",\n\
- \ \"sources\": [\n\
- \ \"src\"\n\
- \ ],\n\
- \ \"bs-dependencies\" : [\n\
- \ // add your bs-dependencies here \n\
- \ ]\n\
- }") ;
- File ("README.md",
- "\n\
- \n\
- # Build\n\
- ```\n\
- npm run build\n\
- ```\n\
- \n\
- # Watch\n\
- \n\
- ```\n\
- npm run watch\n\
- ```\n\
- \n\
- \n\
- # Editor\n\
- If you use `vscode`, Press `Windows + Shift + B` it will build automatically")]) ;
+ File (".gitignore",
+ "*.exe\n\
+ *.obj\n\
+ *.out\n\
+ *.compile\n\
+ *.native\n\
+ *.byte\n\
+ *.cmo\n\
+ *.annot\n\
+ *.cmi\n\
+ *.cmx\n\
+ *.cmt\n\
+ *.cmti\n\
+ *.cma\n\
+ *.a\n\
+ *.cmxa\n\
+ *.obj\n\
+ *~\n\
+ *.annot\n\
+ *.cmj\n\
+ *.bak\n\
+ lib/bs\n\
+ *.mlast\n\
+ *.mliast\n\
+ .vscode\n\
+ .merlin")]) ;
Dir ("minimal", [
Dir ("src", [ File ("main.ml", "")]) ;
- File (".gitignore",
- "lib\n\
- node_modules\n\
- .merlin\n\
- npm-debug.log") ;
+ File ("README.md",
+ "\n\
+ \ # ${bsb:name}") ;
File ("package.json",
"{\n\
\ \"name\": \"${bsb:name}\",\n\
@@ -146,7 +144,9 @@ let root = OCamlRes.Res.([
\ \"name\": \"${bsb:name}\",\n\
\ \"sources\": [\"src\"]\n\
}") ;
- File ("README.md",
- "\n\
- \ # ${bsb:name}")])
+ File (".gitignore",
+ "lib\n\
+ node_modules\n\
+ .merlin\n\
+ npm-debug.log")])
])
diff --git a/jscomp/common/binary_cache.ml b/jscomp/common/binary_cache.ml
index 96a1f4116c..d4c20665c3 100644
--- a/jscomp/common/binary_cache.ml
+++ b/jscomp/common/binary_cache.ml
@@ -37,7 +37,7 @@ type module_info =
{
mli : mli_kind ;
ml : ml_kind ;
- mll : string option ;
+ (*mll : string option ;*)
}
@@ -52,7 +52,7 @@ let module_info_magic_number = "BSBUILD20161019"
let dir_of_module_info (x : module_info)
=
match x with
- | { mli; ml; mll} ->
+ | { mli; ml; } ->
begin match mli with
| Mli s | Rei s ->
Filename.dirname s
@@ -60,11 +60,11 @@ let dir_of_module_info (x : module_info)
begin match ml with
| Ml s | Re s ->
Filename.dirname s
- | Ml_empty ->
- begin match mll with
+ | Ml_empty -> Ext_string.empty
+ (*begin match mll with
| None -> ""
| Some s -> Filename.dirname s
- end
+ end *)
end
end
@@ -86,7 +86,7 @@ let read_build_cache bsbuild : t =
let bsbuild_cache = ".bsbuild"
-let empty_module_info = {mli = Mli_empty ; mll = None ; ml = Ml_empty}
+let empty_module_info = {mli = Mli_empty ; ml = Ml_empty}
let adjust_module_info x suffix name =
match suffix with
@@ -94,7 +94,6 @@ let adjust_module_info x suffix name =
| ".re" -> {x with ml = Re name}
| ".mli" -> {x with mli = Mli name}
| ".rei" -> { x with mli = Rei name}
- | ".mll" -> {x with mll = Some name}
| _ -> failwith ("don't know what to do with " ^ name)
let map_update ?dir (map : file_group_rouces) name : file_group_rouces =
diff --git a/jscomp/common/binary_cache.mli b/jscomp/common/binary_cache.mli
index c80106ee55..9c4d82798e 100644
--- a/jscomp/common/binary_cache.mli
+++ b/jscomp/common/binary_cache.mli
@@ -36,7 +36,6 @@ type module_info =
{
mli : mli_kind ;
ml : ml_kind ;
- mll : string option
}
type file_group_rouces = module_info String_map.t
diff --git a/jscomp/depends/depends_post_process.ml b/jscomp/depends/depends_post_process.ml
index 236b260f1c..606136ccb6 100644
--- a/jscomp/depends/depends_post_process.ml
+++ b/jscomp/depends/depends_post_process.ml
@@ -72,7 +72,7 @@ let handle_bin_depfile
Array.fold_left
(fun ((acc, len) as v) k ->
match String_map.find_opt k data.(0) with
- | Some ({ml = Ml s | Re s } | {mll = Some s })
+ | Some {ml = Ml s | Re s }
->
let new_file = op_concat @@ Filename.chop_extension s ^ suffix_inteface
in (new_file :: acc , len + String.length new_file + length_space)
@@ -84,7 +84,7 @@ let handle_bin_depfile
if index = 0 then v
else
begin match String_map.find_opt k data.(index) with
- | Some ({ml = Ml s | Re s } | {mll = Some s })
+ | Some {ml = Ml s | Re s }
->
let new_file = op_concat @@ Filename.chop_extension s ^ suffix_inteface
in (new_file :: acc , len + String.length new_file + length_space)
@@ -112,7 +112,6 @@ let handle_bin_depfile
(fun ((acc, len) as v) k ->
match String_map.find_opt k data.(0) with
| Some ({ ml = Ml f | Re f }
- | { mll = Some f }
| { mli = Mli f | Rei f }) ->
let new_file = (op_concat @@ Filename.chop_extension f ^ Literals.suffix_cmi) in
(new_file :: acc , len + String.length new_file + length_space)
@@ -122,7 +121,6 @@ let handle_bin_depfile
else
begin match String_map.find_opt k data.(index) with
| Some ({ ml = Ml f | Re f }
- | { mll = Some f }
| { mli = Mli f | Rei f }) ->
let new_file = (op_concat @@ Filename.chop_extension f ^ Literals.suffix_cmi) in
(new_file :: acc , len + String.length new_file + length_space)
diff --git a/jscomp/ext/ext_array.ml b/jscomp/ext/ext_array.ml
index 3d3863093d..e338cfffc0 100644
--- a/jscomp/ext/ext_array.ml
+++ b/jscomp/ext/ext_array.ml
@@ -183,4 +183,19 @@ let exists p a =
let is_empty arr =
- Array.length arr = 0
\ No newline at end of file
+ Array.length arr = 0
+
+
+let rec unsafe_loop index len p xs ys =
+ if index >= len then true
+ else
+ p
+ (Array.unsafe_get xs index)
+ (Array.unsafe_get ys index) &&
+ unsafe_loop (succ index) len p xs ys
+
+let for_all2_no_exn p xs ys =
+ let len_xs = Array.length xs in
+ let len_ys = Array.length ys in
+ len_xs = len_ys &&
+ unsafe_loop 0 len_xs p xs ys
\ No newline at end of file
diff --git a/jscomp/ext/ext_array.mli b/jscomp/ext/ext_array.mli
index 4a4309cad1..35445814e8 100644
--- a/jscomp/ext/ext_array.mli
+++ b/jscomp/ext/ext_array.mli
@@ -68,4 +68,10 @@ val find_and_split :
val exists : ('a -> bool) -> 'a array -> bool
-val is_empty : 'a array -> bool
\ No newline at end of file
+val is_empty : 'a array -> bool
+
+val for_all2_no_exn :
+ ('a -> 'b -> bool) ->
+ 'a array ->
+ 'b array ->
+ bool
\ No newline at end of file
diff --git a/jscomp/ext/ext_json.ml b/jscomp/ext/ext_json.ml
index a43c84602f..123b10bb5e 100644
--- a/jscomp/ext/ext_json.ml
+++ b/jscomp/ext/ext_json.ml
@@ -1,4 +1,26 @@
-
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
type callback =
[
@@ -14,7 +36,7 @@ type callback =
| `Id of (Ext_json_types.t -> unit )
]
-
+
type path = string list
type status =
@@ -24,26 +46,26 @@ type status =
let test ?(fail=(fun () -> ())) key
(cb : callback) (m : Ext_json_types.t String_map.t)
- =
- begin match String_map.find_exn key m, cb with
- | exception Not_found ->
- begin match cb with `Not_found f -> f ()
- | _ -> fail ()
- end
- | True _, `Bool cb -> cb true
- | False _, `Bool cb -> cb false
- | Flo {flo = s} , `Flo cb -> cb s
- | Obj {map = b} , `Obj cb -> cb b
- | Arr {content}, `Arr cb -> cb content
- | Arr {content; loc_start ; loc_end}, `Arr_loc cb ->
- cb content loc_start loc_end
- | Null _, `Null cb -> cb ()
- | Str {str = s }, `Str cb -> cb s
- | Str {str = s ; loc }, `Str_loc cb -> cb s loc
- | any , `Id cb -> cb any
- | _, _ -> fail ()
- end;
- m
+ =
+ begin match String_map.find_exn key m, cb with
+ | exception Not_found ->
+ begin match cb with `Not_found f -> f ()
+ | _ -> fail ()
+ end
+ | True _, `Bool cb -> cb true
+ | False _, `Bool cb -> cb false
+ | Flo {flo = s} , `Flo cb -> cb s
+ | Obj {map = b} , `Obj cb -> cb b
+ | Arr {content}, `Arr cb -> cb content
+ | Arr {content; loc_start ; loc_end}, `Arr_loc cb ->
+ cb content loc_start loc_end
+ | Null _, `Null cb -> cb ()
+ | Str {str = s }, `Str cb -> cb s
+ | Str {str = s ; loc }, `Str_loc cb -> cb s loc
+ | any , `Id cb -> cb any
+ | _, _ -> fail ()
+ end;
+ m
let query path (json : Ext_json_types.t ) =
let rec aux acc paths json =
match path with
@@ -67,4 +89,50 @@ let loc_of (x : Ext_json_types.t) =
| Arr p -> p.loc_start
| Obj p -> p.loc
| Flo p -> p.loc
-
+
+
+let rec equal
+ (x : Ext_json_types.t)
+ (y : Ext_json_types.t) =
+ match x with
+ | Null _ -> (* [%p? Null _ ] *)
+ begin match y with
+ | Null _ -> true
+ | _ -> false end
+ | Str {str } ->
+ begin match y with
+ | Str {str = str2} -> str = str2
+ | _ -> false end
+ | Flo {flo}
+ ->
+ begin match y with
+ | Flo {flo = flo2} ->
+ flo = flo2
+ | _ -> false
+ end
+ | True _ ->
+ begin match y with
+ | True _ -> true
+ | _ -> false
+ end
+ | False _ ->
+ begin match y with
+ | False _ -> true
+ | _ -> false
+ end
+ | Arr {content}
+ ->
+ begin match y with
+ | Arr {content = content2}
+ ->
+ Ext_array.for_all2_no_exn equal content content2
+ | _ -> false
+ end
+
+ | Obj {map} ->
+ begin match y with
+ | Obj { map = map2} ->
+ String_map.equal equal map map2
+ | _ -> false
+ end
+
diff --git a/jscomp/ext/ext_json.mli b/jscomp/ext/ext_json.mli
index 82ecc0d028..917b46da71 100644
--- a/jscomp/ext/ext_json.mli
+++ b/jscomp/ext/ext_json.mli
@@ -54,3 +54,5 @@ val test:
val query : path -> Ext_json_types.t -> status
val loc_of : Ext_json_types.t -> Ext_position.t
+
+val equal : Ext_json_types.t -> Ext_json_types.t -> bool
\ No newline at end of file
diff --git a/jscomp/ext/ext_json_write.ml b/jscomp/ext/ext_json_write.ml
new file mode 100644
index 0000000000..551f1ed794
--- /dev/null
+++ b/jscomp/ext/ext_json_write.ml
@@ -0,0 +1,86 @@
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+
+(** poor man's serialization *)
+
+let quot x =
+ "\"" ^ String.escaped x ^ "\""
+
+let rec encode_aux (x : Ext_json_types.t )
+ (buf : Buffer.t) : unit =
+ let a str = Buffer.add_string buf str in
+ match x with
+ | Null _ -> a "null"
+ | Str {str = s } -> a (quot s)
+ | Flo {flo = s} ->
+ a s (*
+ since our parsing keep the original float representation, we just dump it as is, there is no cases like [nan] *)
+ | Arr {content} ->
+ begin match content with
+ | [||] -> a "[]"
+ | _ ->
+ a "[ ";
+ encode_aux
+ (Array.unsafe_get content 0)
+ buf ;
+ for i = 1 to Array.length content - 1 do
+ a " , ";
+ encode_aux
+ (Array.unsafe_get content i)
+ buf
+ done;
+ a " ]"
+ end
+ | True _ -> a "true"
+ | False _ -> a "false"
+ | Obj {map} ->
+ if String_map.is_empty map then
+ a "{}"
+ else
+ begin
+ (*prerr_endline "WEIRD";
+ prerr_endline (string_of_int @@ String_map.cardinal map ); *)
+ a "{ ";
+ let _ : int = String_map.fold (fun k v i ->
+ if i <> 0 then begin
+ a " , "
+ end;
+ a (quot k);
+ a " : ";
+ encode_aux v buf ;
+ i + 1
+ ) map 0 in
+ a " }"
+ end
+
+
+let to_string (x : Ext_json_types.t) =
+ let buf = Buffer.create 1024 in
+ encode_aux x buf ;
+ Buffer.contents buf
+
+let to_channel (oc : out_channel) x =
+ let buf = Buffer.create 1024 in
+ encode_aux x buf ;
+ Buffer.output_buffer oc buf
diff --git a/jscomp/ext/ext_json_write.mli b/jscomp/ext/ext_json_write.mli
new file mode 100644
index 0000000000..ca9baff165
--- /dev/null
+++ b/jscomp/ext/ext_json_write.mli
@@ -0,0 +1,29 @@
+(* Copyright (C) 2015-2016 Bloomberg Finance L.P.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * In addition to the permissions granted to you by the LGPL, you may combine
+ * or link a "work that uses the Library" with a publicly distributed version
+ * of this file to produce a combined library or application, then distribute
+ * that combined work under the terms of your choosing, with no requirement
+ * to comply with the obligations normally placed on you by section 4 of the
+ * LGPL version 3 (or the corresponding section of a later version of the LGPL
+ * should you choose to use a later version).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
+
+
+val to_string : Ext_json_types.t -> string
+
+
+val to_channel : out_channel -> Ext_json_types.t -> unit
\ No newline at end of file
diff --git a/jscomp/ext/ext_string.ml b/jscomp/ext/ext_string.ml
index ac70c7bb53..2fd03f4546 100644
--- a/jscomp/ext/ext_string.ml
+++ b/jscomp/ext/ext_string.ml
@@ -364,7 +364,8 @@ let is_valid_source_name name : check_result =
match check_any_suffix_case_then_chop name [
".ml";
".re";
- ".mli"; ".mll"; ".rei"
+ ".mli";
+ ".rei"
] with
| None -> Suffix_mismatch
| Some x ->
diff --git a/jscomp/ounit_tests/ounit_array_tests.ml b/jscomp/ounit_tests/ounit_array_tests.ml
index 35b70a66fa..80d1ae796c 100644
--- a/jscomp/ounit_tests/ounit_array_tests.ml
+++ b/jscomp/ounit_tests/ounit_array_tests.ml
@@ -47,4 +47,32 @@ let suites =
[|1;2;3;4;5;6|] []
=~ [2;4;6]
end;
+
+ __LOC__ >:: begin fun _ ->
+ OUnit.assert_bool __LOC__
+ (Ext_array.for_all2_no_exn
+ (=)
+ [|1;2;3|]
+ [|1;2;3|]
+ )
+ end;
+ __LOC__ >:: begin fun _ ->
+ OUnit.assert_bool __LOC__
+ (Ext_array.for_all2_no_exn
+ (=) [||] [||]
+ );
+ OUnit.assert_bool __LOC__
+ (not @@ Ext_array.for_all2_no_exn
+ (=) [||] [|1|]
+ )
+ end
+ ;
+ __LOC__ >:: begin fun _ ->
+ OUnit.assert_bool __LOC__
+ (not (Ext_array.for_all2_no_exn
+ (=)
+ [|1;2;3|]
+ [|1;2;33|]
+ ))
+ end
]
\ No newline at end of file
diff --git a/jscomp/ounit_tests/ounit_json_tests.ml b/jscomp/ounit_tests/ounit_json_tests.ml
index 557be4af7a..7a6dcaa6e9 100644
--- a/jscomp/ounit_tests/ounit_json_tests.ml
+++ b/jscomp/ounit_tests/ounit_json_tests.ml
@@ -1,16 +1,66 @@
let ((>::),
- (>:::)) = OUnit.((>::),(>:::))
+ (>:::)) = OUnit.((>::),(>:::))
open Ext_json_parse
let (|?) m (key, cb) =
- m |> Ext_json.test key cb
+ m |> Ext_json.test key cb
+let id_parsing_serializing x =
+ let normal_s =
+ Ext_json_write.to_string ( Ext_json_parse.parse_json_from_string x )
+ in
+ let normal_ss =
+ Ext_json_write.to_string
+ (Ext_json_parse.parse_json_from_string normal_s)
+ in
+ if normal_s <> normal_ss then
+ begin
+ prerr_endline "ERROR";
+ prerr_endline normal_s ;
+ prerr_endline normal_ss ;
+ end;
+ OUnit.assert_equal ~cmp:(fun (x:string) y -> x = y) normal_s normal_ss
+
+let id_parsing_x2 x =
+ let stru = Ext_json_parse.parse_json_from_string x in
+ let normal_s = Ext_json_write.to_string stru in
+ let normal_ss = (Ext_json_parse.parse_json_from_string normal_s) in
+ if Ext_json.equal stru normal_ss then
+ true
+ else begin
+ prerr_endline "ERROR";
+ prerr_endline normal_s;
+ Format.fprintf Format.err_formatter
+ "%a@.%a@." Ext_pervasives.pp_any stru Ext_pervasives.pp_any normal_ss;
+
+ prerr_endline (Ext_json_write.to_string normal_ss);
+ false
+ end
+
+let test_data =
+ [{|
+ {}
+ |};
+ {| [] |};
+ {| [1,2,3]|};
+ {| ["x", "y", 1,2,3 ]|};
+ {| { "x" : 3, "y" : "x", "z" : [1,2,3, "x"] }|};
+ {| {"x " : true , "y" : false , "z\"" : 1} |}
+ ]
exception Parse_error
let suites =
__FILE__
>:::
[
+
+ __LOC__ >:: begin fun _ ->
+ List.iter id_parsing_serializing test_data
+ end;
+
+ __LOC__ >:: begin fun _ ->
+ List.iteri (fun i x -> OUnit.assert_bool (__LOC__ ^ string_of_int i ) (id_parsing_x2 x)) test_data
+ end;
"empty_json" >:: begin fun _ ->
let v =parse_json_from_string "{}" in
match v with
@@ -29,7 +79,7 @@ let suites =
(OUnit.assert_raises Parse_error @@ fun _ ->
try parse_json_from_string {| [,]|} with _ -> raise Parse_error);
OUnit.assert_raises Parse_error @@ fun _ ->
- try parse_json_from_string {| {,}|} with _ -> raise Parse_error
+ try parse_json_from_string {| {,}|} with _ -> raise Parse_error
end;
"two trails" >:: begin fun _ ->
(OUnit.assert_raises Parse_error @@ fun _ ->
diff --git a/jscomp/ounit_tests/ounit_string_tests.ml b/jscomp/ounit_tests/ounit_string_tests.ml
index af0272b5d4..9d46705eab 100644
--- a/jscomp/ounit_tests/ounit_string_tests.ml
+++ b/jscomp/ounit_tests/ounit_string_tests.ml
@@ -50,7 +50,7 @@ let suites =
__LOC__ >:: begin fun _ ->
OUnit.assert_bool __LOC__ @@
List.for_all (fun x -> Ext_string.is_valid_source_name x = Good)
- ["x.ml"; "x.mli"; "x.re"; "x.rei"; "x.mll";
+ ["x.ml"; "x.mli"; "x.re"; "x.rei";
"A_x.ml"; "ab.ml"; "a_.ml"; "a__.ml";
"ax.ml"];
OUnit.assert_bool __LOC__ @@ not @@
diff --git a/jscomp/test/ext_array.js b/jscomp/test/ext_array.js
index 8bcb02a4ae..535ce23851 100644
--- a/jscomp/test/ext_array.js
+++ b/jscomp/test/ext_array.js
@@ -283,6 +283,31 @@ function is_empty(arr) {
return +(arr.length === 0);
}
+function unsafe_loop(_index, len, p, xs, ys) {
+ while(true) {
+ var index = _index;
+ if (index >= len) {
+ return /* true */1;
+ } else if (Curry._2(p, xs[index], ys[index])) {
+ _index = index + 1 | 0;
+ continue ;
+
+ } else {
+ return /* false */0;
+ }
+ };
+}
+
+function for_all2_no_exn(p, xs, ys) {
+ var len_xs = xs.length;
+ var len_ys = ys.length;
+ if (len_xs === len_ys) {
+ return unsafe_loop(0, len_xs, p, xs, ys);
+ } else {
+ return /* false */0;
+ }
+}
+
exports.reverse_range = reverse_range;
exports.reverse_in_place = reverse_in_place;
exports.reverse = reverse;
@@ -301,4 +326,6 @@ exports.find_with_index = find_with_index;
exports.find_and_split = find_and_split;
exports.exists = exists;
exports.is_empty = is_empty;
+exports.unsafe_loop = unsafe_loop;
+exports.for_all2_no_exn = for_all2_no_exn;
/* No side effect */
diff --git a/jscomp/test/ext_string.js b/jscomp/test/ext_string.js
index 1dc625b624..cca48aa998 100644
--- a/jscomp/test/ext_string.js
+++ b/jscomp/test/ext_string.js
@@ -569,11 +569,8 @@ function is_valid_source_name(name) {
/* :: */[
".mli",
/* :: */[
- ".mll",
- /* :: */[
- ".rei",
- /* [] */0
- ]
+ ".rei",
+ /* [] */0
]
]
]
diff --git a/site/docsource/Build-system-support.adoc b/site/docsource/Build-system-support.adoc
index 41a38fe6b3..6f5d803661 100644
--- a/site/docsource/Build-system-support.adoc
+++ b/site/docsource/Build-system-support.adoc
@@ -349,3 +349,51 @@ make depend // <2>
Now in your working directory, type `watchman -j < build.json` and enjoy the lightning build speed.
+
+=== Customize rules (generators support, @since 1.7.4)
+
+It is quite common that programmers use some pre-processors to generate some bolierpolate code during developement.
+
+Note pre-processors can be classified as two categories, one is system-dependent which should be delayed until running on user machines, the other is system-indepdent , lex, yacc, m4, re2c, etc, which could be executed anytime.
+
+BuckleScript has built in support for conditional compilation, this section is about the second part, since it is system-indepdent, we ask users to always generate such code and check in before shipping, this would help cut the dependencies for end users.
+
+A typical example would be like this
+
+.Bsb using ocamlyacc
+[source,js]
+-----------
+{
+ "generators" : [
+ { "name" : "ocamlyacc" ,
+ "command" : "ocamlyacc $in" }
+ ],
+ ...,
+ "sources" : {
+ "dir" : "src",
+ "generators" : [
+ {
+ "name" : "ocamlyacc",
+ "edge" : ["test.ml", "test.mli", ":", "test.mly"]
+ }
+ ]
+ }
+}
+-----------
+
+
+Note `ocamlyacc` will generate in `test.ml` and `test.mli` in the same directory with `test.mly`, user should check in generated file since then users would not need run ocamlyacc again, this would apply to `menhir` as well.
+
+When users are developing current project, `bsb` will track the dependencies between `test.ml` and `test.mly` properly, when released
+as a package, `bsb` will cut such dependency, so that users will
+only need the generated `test.ml`, to help test such behavior in development mode, users could set it manually
+
+[source,js]
+-----------
+{
+ ...,
+ "cut-generators" : true
+}
+-----------
+
+Then `bsb` will not re-generate `test.ml` whenever `test.mly` changes.
\ No newline at end of file