From e5704083f12b463263f2eefb776ecce44bc9caae Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Tue, 16 Apr 2019 14:39:31 +0800 Subject: [PATCH 01/16] add macro system for transforming runtime code --- compiler/lib/driver.ml | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index 4e7fe42e65..1bf2b641f1 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -284,6 +284,46 @@ let link ~standalone ~linkall ~export_runtime (js : Javascript.source_elements) in Linker.link js linkinfos +let macro recurse fallthrough = + let module J = Javascript in + function + | "BLOCK", (tag: J.expression) :: args -> + let tag = Some tag in + let len = Some (J.ENum (string_of_int (List.length args))) in + let args = List.map ~f:(fun a -> Some (recurse a)) args in + J.EArr (tag :: len :: args) + | "TAG", [e] -> J.EAccess (recurse e, J.ENum "0") + | "LENGTH", [e] -> J.EDot (recurse e, "length") + | "FIELD", [e; J.ENum n] -> + let idx = int_of_string n in + let adjusted = J.ENum (string_of_int (idx + 1)) in + J.EAccess (recurse e, adjusted) + | "FIELD", [e; idx] -> + let adjusted = J.EBin (J.Plus, J.ENum "1", recurse idx) in + J.EAccess (recurse e, adjusted) + | "ISBLOCK", [_] -> failwith "what is this?" + | "BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _ -> + assert false; + | _ -> fallthrough () + + +class macro_mapper = object (m) + inherit Js_traverse.map as super + + method expression x = + let module J = Javascript in + let fallthrough () = super#expression x in + let recurse = m#expression in + match x with + | J.ECall (J.EVar (J.S {name; _}), args, _) -> + macro recurse fallthrough (name, args) + | _ -> fallthrough () +end + +let run_macro js = + let trav = new macro_mapper in + trav#program js + let check_js js = let t = Timer.make () in if times () then Format.eprintf "Start Checks...@."; @@ -453,6 +493,7 @@ let f >> Generate_closure.f >> deadcode' >> generate d ~exported_runtime + >> run_macro >> link ~standalone ~linkall ~export_runtime:dynlink >> pack ~global >> coloring From c2780ad9980bcc124938db75c1daddb6fa5db5f3 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Tue, 16 Apr 2019 15:52:45 +0800 Subject: [PATCH 02/16] add macro tests --- compiler/lib/driver.ml | 54 ++++++++++--------- compiler/lib/driver.mli | 4 ++ compiler/tests/expect_tests/macro.ml | 77 ++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 25 deletions(-) create mode 100644 compiler/tests/expect_tests/macro.ml diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index 1bf2b641f1..29c186cd64 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -287,38 +287,38 @@ let link ~standalone ~linkall ~export_runtime (js : Javascript.source_elements) let macro recurse fallthrough = let module J = Javascript in function - | "BLOCK", (tag: J.expression) :: args -> - let tag = Some tag in - let len = Some (J.ENum (string_of_int (List.length args))) in - let args = List.map ~f:(fun a -> Some (recurse a)) args in - J.EArr (tag :: len :: args) - | "TAG", [e] -> J.EAccess (recurse e, J.ENum "0") + | "BLOCK", (tag : J.expression) :: args -> + let tag = Some tag in + let args = List.map ~f:(fun a -> Some (recurse a)) args in + J.EArr (tag :: args) + | "TAG", [e] -> J.EAccess (recurse e, J.ENum "0") | "LENGTH", [e] -> J.EDot (recurse e, "length") | "FIELD", [e; J.ENum n] -> - let idx = int_of_string n in - let adjusted = J.ENum (string_of_int (idx + 1)) in - J.EAccess (recurse e, adjusted) + let idx = int_of_string n in + let adjusted = J.ENum (string_of_int (idx + 1)) in + J.EAccess (recurse e, adjusted) | "FIELD", [e; idx] -> - let adjusted = J.EBin (J.Plus, J.ENum "1", recurse idx) in - J.EAccess (recurse e, adjusted) + let adjusted = J.EBin (J.Plus, J.ENum "1", recurse idx) in + J.EAccess (recurse e, adjusted) | "ISBLOCK", [_] -> failwith "what is this?" - | "BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _ -> - assert false; + | ("BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _) as s -> + let s, _ = s in + failwith (Format.sprintf "macro %s called with inappropriate arguments" s) | _ -> fallthrough () +class macro_mapper = + object (m) + inherit Js_traverse.map as super -class macro_mapper = object (m) - inherit Js_traverse.map as super - - method expression x = - let module J = Javascript in - let fallthrough () = super#expression x in - let recurse = m#expression in - match x with - | J.ECall (J.EVar (J.S {name; _}), args, _) -> - macro recurse fallthrough (name, args) - | _ -> fallthrough () -end + method expression x = + let module J = Javascript in + let fallthrough () = super#expression x in + let recurse = m#expression in + match x with + | J.ECall (J.EVar (J.S {name; _}), args, _) -> + macro recurse fallthrough (name, args) + | _ -> fallthrough () + end let run_macro js = let trav = new macro_mapper in @@ -507,3 +507,7 @@ let from_string prims s formatter = let profiles = [1, o1; 2, o2; 3, o3] let profile i = try Some (List.assoc i profiles) with Not_found -> None + +module For_testing = struct + let macro = run_macro +end diff --git a/compiler/lib/driver.mli b/compiler/lib/driver.mli index c7c6cb9823..0de3b589f5 100644 --- a/compiler/lib/driver.mli +++ b/compiler/lib/driver.mli @@ -38,3 +38,7 @@ val from_string : string array -> string -> Pretty_print.t -> unit val profiles : (int * profile) list val profile : int -> profile option + +module For_testing : sig + val macro : Javascript.program -> Javascript.program +end diff --git a/compiler/tests/expect_tests/macro.ml b/compiler/tests/expect_tests/macro.ml new file mode 100644 index 0000000000..b48fddac03 --- /dev/null +++ b/compiler/tests/expect_tests/macro.ml @@ -0,0 +1,77 @@ +module Jsoo = Js_of_ocaml_compiler + +let print_macro_transformed source = + let buffer = Buffer.create (String.length source) in + let pp = Jsoo.Pretty_print.to_buffer buffer in + Jsoo.Pretty_print.set_compact pp false; + let parsed = Util.parse_js source in + let transformed = Jsoo.Driver.For_testing.macro parsed in + Jsoo.Js_output.program pp transformed; + print_endline (Buffer.contents buffer) + +let print_macro_transformed source = + try print_macro_transformed source with Failure s -> Format.printf "failure: %s" s + +let%expect_test "BLOCK()" = + print_macro_transformed "BLOCK()"; + [%expect {| failure: macro BLOCK called with inappropriate arguments |}] + +let%expect_test "TAG()" = + print_macro_transformed "TAG()"; + [%expect {| failure: macro TAG called with inappropriate arguments |}] + +let%expect_test "LENGTH()" = + print_macro_transformed "LENGTH()"; + [%expect {| failure: macro LENGTH called with inappropriate arguments |}] + +let%expect_test "FIELD()" = + print_macro_transformed "FIELD()"; + [%expect {| failure: macro FIELD called with inappropriate arguments |}] + +let%expect_test "ISBLOCK()" = + print_macro_transformed "ISBLOCK()"; + [%expect {| failure: macro ISBLOCK called with inappropriate arguments |}] + +let%expect_test "BLOCK(1)" = + print_macro_transformed "BLOCK(1)"; + [%expect {| [1]; |}] + +let%expect_test "BLOCK(tag)" = + print_macro_transformed "BLOCK(tag)"; + [%expect {| [tag]; |}] + +let%expect_test "BLOCK(1, a)" = + print_macro_transformed "BLOCK(1, a)"; + [%expect {| [1,a]; |}] + +let%expect_test "BLOCK(1, a, b, c)" = + print_macro_transformed "BLOCK(1, a, b, c)"; + [%expect {| [1,a,b,c]; |}] + +let%expect_test "TAG(a)" = + print_macro_transformed "TAG(a)"; + [%expect {| a[0]; |}] + +let%expect_test "LENGTH(a)" = + print_macro_transformed "LENGTH(a)"; + [%expect {| a.length; |}] + +let%expect_test "FIELD(a)" = + print_macro_transformed "FIELD(a)"; + [%expect {| failure: macro FIELD called with inappropriate arguments |}] + +let%expect_test "FIELD(a, b)" = + print_macro_transformed "FIELD(a, b)"; + [%expect {| a[1 + b]; |}] + +let%expect_test "FIELD(a, b << 5)" = + print_macro_transformed "FIELD(a, b << 5)"; + [%expect {| a[1 + (b << 5)]; |}] + +let%expect_test "FIELD(a, 0)" = + print_macro_transformed "FIELD(a, 0)"; + [%expect {| a[1]; |}] + +let%expect_test "ISBLOCK(a)" = + print_macro_transformed "ISBLOCK(a)"; + [%expect {| failure: what is this? |}] From 7f0ea387b6653009d8d7a834e7f094f4b8c8ed7d Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Tue, 16 Apr 2019 16:10:23 +0800 Subject: [PATCH 03/16] _ --- compiler/lib/driver.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index 29c186cd64..2d40743f0e 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -287,7 +287,7 @@ let link ~standalone ~linkall ~export_runtime (js : Javascript.source_elements) let macro recurse fallthrough = let module J = Javascript in function - | "BLOCK", (tag : J.expression) :: args -> + | "BLOCK", tag :: args -> let tag = Some tag in let args = List.map ~f:(fun a -> Some (recurse a)) args in J.EArr (tag :: args) From 7105d59bbcdf6fb17d6dc9de6ef8d673748aa286 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Tue, 16 Apr 2019 17:25:17 +0800 Subject: [PATCH 04/16] _ --- compiler/lib/driver.ml | 16 ++++++++++++---- compiler/tests/expect_tests/macro.ml | 6 +++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index 2d40743f0e..621d8835a0 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -286,21 +286,29 @@ let link ~standalone ~linkall ~export_runtime (js : Javascript.source_elements) let macro recurse fallthrough = let module J = Javascript in + let zero, one = J.ENum "0", J.ENum "1" in function + | "BLOCK", [_] -> + failwith (Format.sprintf "macro BLOCK called with inappropriate arguments") | "BLOCK", tag :: args -> let tag = Some tag in let args = List.map ~f:(fun a -> Some (recurse a)) args in J.EArr (tag :: args) - | "TAG", [e] -> J.EAccess (recurse e, J.ENum "0") - | "LENGTH", [e] -> J.EDot (recurse e, "length") + | "TAG", [e] -> J.EAccess (recurse e, zero) + | "LENGTH", [e] -> + let underlying = J.EDot (recurse e, "length") in + J.EBin (J.Minus, underlying, one) | "FIELD", [e; J.ENum n] -> let idx = int_of_string n in let adjusted = J.ENum (string_of_int (idx + 1)) in J.EAccess (recurse e, adjusted) | "FIELD", [e; idx] -> - let adjusted = J.EBin (J.Plus, J.ENum "1", recurse idx) in + let adjusted = J.EBin (J.Plus, one, recurse idx) in J.EAccess (recurse e, adjusted) - | "ISBLOCK", [_] -> failwith "what is this?" + | "ISBLOCK", [e] -> J.EBin + ( J.EqEq + , J.EUn (J.Typeof, J.EAccess (recurse e, zero)) + , J.EStr ("number", `Utf8) ) | ("BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _) as s -> let s, _ = s in failwith (Format.sprintf "macro %s called with inappropriate arguments" s) diff --git a/compiler/tests/expect_tests/macro.ml b/compiler/tests/expect_tests/macro.ml index b48fddac03..580ba6d4b0 100644 --- a/compiler/tests/expect_tests/macro.ml +++ b/compiler/tests/expect_tests/macro.ml @@ -34,11 +34,11 @@ let%expect_test "ISBLOCK()" = let%expect_test "BLOCK(1)" = print_macro_transformed "BLOCK(1)"; - [%expect {| [1]; |}] + [%expect {| failure: macro BLOCK called with inappropriate arguments |}] let%expect_test "BLOCK(tag)" = print_macro_transformed "BLOCK(tag)"; - [%expect {| [tag]; |}] + [%expect {| failure: macro BLOCK called with inappropriate arguments |}] let%expect_test "BLOCK(1, a)" = print_macro_transformed "BLOCK(1, a)"; @@ -54,7 +54,7 @@ let%expect_test "TAG(a)" = let%expect_test "LENGTH(a)" = print_macro_transformed "LENGTH(a)"; - [%expect {| a.length; |}] + [%expect {| a.length - 1; |}] let%expect_test "FIELD(a)" = print_macro_transformed "FIELD(a)"; From f7089cf9c9c016e509be9982ec9441fdd90ee644 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Wed, 17 Apr 2019 13:02:41 +0800 Subject: [PATCH 05/16] _ --- compiler/lib/driver.ml | 15 +++++++-------- compiler/tests/expect_tests/macro.ml | 6 +++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index 621d8835a0..63eaaefc3f 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -288,9 +288,7 @@ let macro recurse fallthrough = let module J = Javascript in let zero, one = J.ENum "0", J.ENum "1" in function - | "BLOCK", [_] -> - failwith (Format.sprintf "macro BLOCK called with inappropriate arguments") - | "BLOCK", tag :: args -> + | "BLOCK", tag :: args when List.length args > 0 -> let tag = Some tag in let args = List.map ~f:(fun a -> Some (recurse a)) args in J.EArr (tag :: args) @@ -299,15 +297,16 @@ let macro recurse fallthrough = let underlying = J.EDot (recurse e, "length") in J.EBin (J.Minus, underlying, one) | "FIELD", [e; J.ENum n] -> - let idx = int_of_string n in - let adjusted = J.ENum (string_of_int (idx + 1)) in - J.EAccess (recurse e, adjusted) + let idx = int_of_string n in + let adjusted = J.ENum (string_of_int (idx + 1)) in + J.EAccess (recurse e, adjusted) + | "FIELD", [_; J.EUn(J.Neg, _)] -> failwith "Negative field indexes are not allowed" ; | "FIELD", [e; idx] -> let adjusted = J.EBin (J.Plus, one, recurse idx) in J.EAccess (recurse e, adjusted) | "ISBLOCK", [e] -> J.EBin - ( J.EqEq - , J.EUn (J.Typeof, J.EAccess (recurse e, zero)) + ( J.NotEqEq + , J.EUn (J.Typeof, recurse e ) , J.EStr ("number", `Utf8) ) | ("BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _) as s -> let s, _ = s in diff --git a/compiler/tests/expect_tests/macro.ml b/compiler/tests/expect_tests/macro.ml index 580ba6d4b0..af07f8cace 100644 --- a/compiler/tests/expect_tests/macro.ml +++ b/compiler/tests/expect_tests/macro.ml @@ -72,6 +72,10 @@ let%expect_test "FIELD(a, 0)" = print_macro_transformed "FIELD(a, 0)"; [%expect {| a[1]; |}] +let%expect_test "FIELD(a, -1)" = + print_macro_transformed "FIELD(a, -1)"; + [%expect {| failure: Negative field indexes are not allowed |}] + let%expect_test "ISBLOCK(a)" = print_macro_transformed "ISBLOCK(a)"; - [%expect {| failure: what is this? |}] + [%expect {| typeof a !== "number"; |}] From 45a88e72f05b99bf50f70bf0dd19cd40a3d9baef Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Wed, 17 Apr 2019 17:46:29 +0800 Subject: [PATCH 06/16] move macro expansion to initial processing of runtime files --- compiler/js_of_ocaml.ml | 2 +- compiler/lib/driver.ml | 52 ---------------------------- compiler/lib/driver.mli | 4 --- compiler/lib/linker.ml | 7 ++-- compiler/lib/linker.mli | 2 +- compiler/lib/macro.ml | 48 +++++++++++++++++++++++++ compiler/lib/macro.mli | 1 + compiler/tests/expect_tests/macro.ml | 2 +- runtime/unix.js | 10 +++--- 9 files changed, 61 insertions(+), 67 deletions(-) create mode 100644 compiler/lib/macro.ml create mode 100644 compiler/lib/macro.mli diff --git a/compiler/js_of_ocaml.ml b/compiler/js_of_ocaml.ml index 331e992ebc..373f8a28c5 100644 --- a/compiler/js_of_ocaml.ml +++ b/compiler/js_of_ocaml.ml @@ -122,7 +122,7 @@ let f `Keep with Not_found -> `Skip) in - Linker.load_files runtime_files; + Linker.load_files runtime_files ~runtime_transform:Macro.f; let paths = try List.append include_dir [Findlib.find_pkg_dir "stdlib"] with Not_found -> include_dir diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index 63eaaefc3f..4e7fe42e65 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -284,53 +284,6 @@ let link ~standalone ~linkall ~export_runtime (js : Javascript.source_elements) in Linker.link js linkinfos -let macro recurse fallthrough = - let module J = Javascript in - let zero, one = J.ENum "0", J.ENum "1" in - function - | "BLOCK", tag :: args when List.length args > 0 -> - let tag = Some tag in - let args = List.map ~f:(fun a -> Some (recurse a)) args in - J.EArr (tag :: args) - | "TAG", [e] -> J.EAccess (recurse e, zero) - | "LENGTH", [e] -> - let underlying = J.EDot (recurse e, "length") in - J.EBin (J.Minus, underlying, one) - | "FIELD", [e; J.ENum n] -> - let idx = int_of_string n in - let adjusted = J.ENum (string_of_int (idx + 1)) in - J.EAccess (recurse e, adjusted) - | "FIELD", [_; J.EUn(J.Neg, _)] -> failwith "Negative field indexes are not allowed" ; - | "FIELD", [e; idx] -> - let adjusted = J.EBin (J.Plus, one, recurse idx) in - J.EAccess (recurse e, adjusted) - | "ISBLOCK", [e] -> J.EBin - ( J.NotEqEq - , J.EUn (J.Typeof, recurse e ) - , J.EStr ("number", `Utf8) ) - | ("BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _) as s -> - let s, _ = s in - failwith (Format.sprintf "macro %s called with inappropriate arguments" s) - | _ -> fallthrough () - -class macro_mapper = - object (m) - inherit Js_traverse.map as super - - method expression x = - let module J = Javascript in - let fallthrough () = super#expression x in - let recurse = m#expression in - match x with - | J.ECall (J.EVar (J.S {name; _}), args, _) -> - macro recurse fallthrough (name, args) - | _ -> fallthrough () - end - -let run_macro js = - let trav = new macro_mapper in - trav#program js - let check_js js = let t = Timer.make () in if times () then Format.eprintf "Start Checks...@."; @@ -500,7 +453,6 @@ let f >> Generate_closure.f >> deadcode' >> generate d ~exported_runtime - >> run_macro >> link ~standalone ~linkall ~export_runtime:dynlink >> pack ~global >> coloring @@ -514,7 +466,3 @@ let from_string prims s formatter = let profiles = [1, o1; 2, o2; 3, o3] let profile i = try Some (List.assoc i profiles) with Not_found -> None - -module For_testing = struct - let macro = run_macro -end diff --git a/compiler/lib/driver.mli b/compiler/lib/driver.mli index 0de3b589f5..c7c6cb9823 100644 --- a/compiler/lib/driver.mli +++ b/compiler/lib/driver.mli @@ -38,7 +38,3 @@ val from_string : string array -> string -> Pretty_print.t -> unit val profiles : (int * profile) list val profile : int -> profile option - -module For_testing : sig - val macro : Javascript.program -> Javascript.program -end diff --git a/compiler/lib/linker.ml b/compiler/lib/linker.ml index 10b9680bfe..6bb618d032 100644 --- a/compiler/lib/linker.ml +++ b/compiler/lib/linker.ml @@ -281,7 +281,7 @@ let find_named_value code = ignore (p#program code); !all -let add_file f = +let add_file f ~runtime_transform = List.iter (parse_file f) ~f:(fun {provides; requires; version_constraint; weakdef; code} -> @@ -297,6 +297,7 @@ let add_file f = match provides with | None -> always_included := {filename = f; program = code} :: !always_included | Some (pi, name, kind, ka) -> + let code = runtime_transform code in let module J = Javascript in let rec find = function | [] -> None @@ -352,8 +353,8 @@ let check_deps () = ()) code_pieces -let load_files l = - List.iter l ~f:add_file; +let load_files l ~runtime_transform = + List.iter l ~f:(add_file ~runtime_transform); check_deps () (* resolve *) diff --git a/compiler/lib/linker.mli b/compiler/lib/linker.mli index a81cd26676..bd31de01ee 100644 --- a/compiler/lib/linker.mli +++ b/compiler/lib/linker.mli @@ -31,7 +31,7 @@ type fragment = val parse_file : string -> fragment list -val load_files : string list -> unit +val load_files : string list -> runtime_transform:(Javascript.program -> Javascript.program) -> unit type state diff --git a/compiler/lib/macro.ml b/compiler/lib/macro.ml new file mode 100644 index 0000000000..c6dbd994bb --- /dev/null +++ b/compiler/lib/macro.ml @@ -0,0 +1,48 @@ +open Stdlib + +let macro recurse fallthrough = + let module J = Javascript in + let zero, one = J.ENum "0", J.ENum "1" in + function + | "BLOCK", tag :: args when List.length args > 0 -> + let tag = Some tag in + let args = List.map ~f:(fun a -> Some (recurse a)) args in + J.EArr (tag :: args) + | "TAG", [e] -> J.EAccess (recurse e, zero) + | "LENGTH", [e] -> + let underlying = J.EDot (recurse e, "length") in + J.EBin (J.Minus, underlying, one) + | "FIELD", [e; J.ENum n] -> + let idx = int_of_string n in + let adjusted = J.ENum (string_of_int (idx + 1)) in + J.EAccess (recurse e, adjusted) + | "FIELD", [_; J.EUn(J.Neg, _)] -> failwith "Negative field indexes are not allowed" ; + | "FIELD", [e; idx] -> + let adjusted = J.EBin (J.Plus, one, recurse idx) in + J.EAccess (recurse e, adjusted) + | "ISBLOCK", [e] -> J.EBin + ( J.NotEqEq + , J.EUn (J.Typeof, recurse e ) + , J.EStr ("number", `Utf8) ) + | ("BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _) as s -> + let s, _ = s in + failwith (Format.sprintf "macro %s called with inappropriate arguments" s) + | _ -> fallthrough () + +class macro_mapper = + object (m) + inherit Js_traverse.map as super + + method expression x = + let module J = Javascript in + let fallthrough () = super#expression x in + let recurse = m#expression in + match x with + | J.ECall (J.EVar (J.S {name; _}), args, _) -> + macro recurse fallthrough (name, args) + | _ -> fallthrough () + end + +let f js = + let trav = new macro_mapper in + trav#program js diff --git a/compiler/lib/macro.mli b/compiler/lib/macro.mli new file mode 100644 index 0000000000..83a8b911e7 --- /dev/null +++ b/compiler/lib/macro.mli @@ -0,0 +1 @@ +val f : Javascript.program -> Javascript.program diff --git a/compiler/tests/expect_tests/macro.ml b/compiler/tests/expect_tests/macro.ml index af07f8cace..cac49d9627 100644 --- a/compiler/tests/expect_tests/macro.ml +++ b/compiler/tests/expect_tests/macro.ml @@ -5,7 +5,7 @@ let print_macro_transformed source = let pp = Jsoo.Pretty_print.to_buffer buffer in Jsoo.Pretty_print.set_compact pp false; let parsed = Util.parse_js source in - let transformed = Jsoo.Driver.For_testing.macro parsed in + let transformed = Jsoo.Macro.f parsed in Jsoo.Js_output.program pp transformed; print_endline (Buffer.contents buffer) diff --git a/runtime/unix.js b/runtime/unix.js index e30b2b6b08..aecc6c0ed4 100644 --- a/runtime/unix.js +++ b/runtime/unix.js @@ -15,10 +15,10 @@ function unix_gmtime (t) { var d_num = d.getTime(); var januaryfirst = (new Date(Date.UTC(d.getUTCFullYear(), 0, 1))).getTime(); var doy = Math.floor((d_num - januaryfirst) / 86400000); - return [0, d.getUTCSeconds(), d.getUTCMinutes(), d.getUTCHours(), + return BLOCK(0, d.getUTCSeconds(), d.getUTCMinutes(), d.getUTCHours(), d.getUTCDate(), d.getUTCMonth(), d.getUTCFullYear() - 1900, d.getUTCDay(), doy, - false | 0 /* for UTC daylight savings time is false */] + false | 0 /* for UTC daylight savings time is false */) } //Provides: unix_localtime @@ -30,10 +30,10 @@ function unix_localtime (t) { var jan = new Date(d.getFullYear(), 0, 1); var jul = new Date(d.getFullYear(), 6, 1); var stdTimezoneOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset()); - return [0, d.getSeconds(), d.getMinutes(), d.getHours(), + return BLOCK(0, d.getSeconds(), d.getMinutes(), d.getHours(), d.getDate(), d.getMonth(), d.getFullYear() - 1900, d.getDay(), doy, - (d.getTimezoneOffset() < stdTimezoneOffset) | 0 /* daylight savings time field. */] + (d.getTimezoneOffset() < stdTimezoneOffset) | 0 /* daylight savings time field. */) } //Provides: unix_mktime @@ -42,7 +42,7 @@ function unix_mktime(tm){ var d = (new Date(tm[6]+1900,tm[5],tm[4],tm[3],tm[2],tm[1])).getTime(); var t = Math.floor(d / 1000); var tm2 = unix_localtime(t); - return [0,t,tm2]; + return BLOCK(0,t,tm2); } //Provides: win_startup const From 5df3d59a0d0de34091e30cc255a1abf07c6f24fb Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Wed, 17 Apr 2019 17:58:40 +0800 Subject: [PATCH 07/16] add copyright --- compiler/lib/macro.mli | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/compiler/lib/macro.mli b/compiler/lib/macro.mli index 83a8b911e7..1d67c8500c 100644 --- a/compiler/lib/macro.mli +++ b/compiler/lib/macro.mli @@ -1 +1,20 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2019 Ty Overby, Jane Street Group LLC + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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 f : Javascript.program -> Javascript.program From e0ff1f8598a56740c691b98262e62943532f71cb Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Thu, 18 Apr 2019 15:42:14 +0800 Subject: [PATCH 08/16] macro in correct place --- compiler/lib/linker.mli | 3 ++- compiler/lib/macro.ml | 18 ++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/lib/linker.mli b/compiler/lib/linker.mli index bd31de01ee..2c8cb66ce8 100644 --- a/compiler/lib/linker.mli +++ b/compiler/lib/linker.mli @@ -31,7 +31,8 @@ type fragment = val parse_file : string -> fragment list -val load_files : string list -> runtime_transform:(Javascript.program -> Javascript.program) -> unit +val load_files : + string list -> runtime_transform:(Javascript.program -> Javascript.program) -> unit type state diff --git a/compiler/lib/macro.ml b/compiler/lib/macro.ml index c6dbd994bb..41ac4421ef 100644 --- a/compiler/lib/macro.ml +++ b/compiler/lib/macro.ml @@ -10,20 +10,18 @@ let macro recurse fallthrough = J.EArr (tag :: args) | "TAG", [e] -> J.EAccess (recurse e, zero) | "LENGTH", [e] -> - let underlying = J.EDot (recurse e, "length") in - J.EBin (J.Minus, underlying, one) + let underlying = J.EDot (recurse e, "length") in + J.EBin (J.Minus, underlying, one) | "FIELD", [e; J.ENum n] -> - let idx = int_of_string n in - let adjusted = J.ENum (string_of_int (idx + 1)) in - J.EAccess (recurse e, adjusted) - | "FIELD", [_; J.EUn(J.Neg, _)] -> failwith "Negative field indexes are not allowed" ; + let idx = int_of_string n in + let adjusted = J.ENum (string_of_int (idx + 1)) in + J.EAccess (recurse e, adjusted) + | "FIELD", [_; J.EUn (J.Neg, _)] -> failwith "Negative field indexes are not allowed" | "FIELD", [e; idx] -> let adjusted = J.EBin (J.Plus, one, recurse idx) in J.EAccess (recurse e, adjusted) - | "ISBLOCK", [e] -> J.EBin - ( J.NotEqEq - , J.EUn (J.Typeof, recurse e ) - , J.EStr ("number", `Utf8) ) + | "ISBLOCK", [e] -> + J.EBin (J.NotEqEq, J.EUn (J.Typeof, recurse e), J.EStr ("number", `Utf8)) | ("BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _) as s -> let s, _ = s in failwith (Format.sprintf "macro %s called with inappropriate arguments" s) From 7acceb5850c9075667ef26ca5859f029944bcc06 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Thu, 18 Apr 2019 15:43:57 +0800 Subject: [PATCH 09/16] add end-to-end tests --- compiler/tests/expect_tests/dune | 4 +- compiler/tests/expect_tests/format_intf.ml | 31 +++ compiler/tests/expect_tests/integration.ml | 74 +++++++ compiler/tests/expect_tests/util.ml | 201 ++++++++++++------ compiler/tests/expect_tests/util.mli | 11 +- .../variable_declaration_output.ml | 15 +- 6 files changed, 261 insertions(+), 75 deletions(-) create mode 100644 compiler/tests/expect_tests/format_intf.ml create mode 100644 compiler/tests/expect_tests/integration.ml diff --git a/compiler/tests/expect_tests/dune b/compiler/tests/expect_tests/dune index c16d58e2ba..9e7a608e73 100644 --- a/compiler/tests/expect_tests/dune +++ b/compiler/tests/expect_tests/dune @@ -1,6 +1,8 @@ (library (name expect_tests) (libraries js_of_ocaml_compiler unix ocaml-compiler-libs.bytecomp) - (inline_tests) + (inline_tests + (flags -allow-output-patterns) + (deps (file ../../js_of_ocaml.exe))) (preprocess (pps ppx_expect))) diff --git a/compiler/tests/expect_tests/format_intf.ml b/compiler/tests/expect_tests/format_intf.ml new file mode 100644 index 0000000000..a4aec66a0b --- /dev/null +++ b/compiler/tests/expect_tests/format_intf.ml @@ -0,0 +1,31 @@ +module type S = sig + type ocaml_source + type js_source + + type ocaml_file + type js_file + type cmo_file + type bc_file + + val read_js: js_file -> js_source + val read_ocaml: ocaml_file -> ocaml_source + + val write_js: js_source -> js_file + val write_ocaml: ocaml_source -> ocaml_file + + val js_source_of_string: string -> js_source + val ocaml_source_of_string: string -> ocaml_source + + val string_of_js_source: js_source -> string + val string_of_ocaml_source: ocaml_source -> string + + val path_of_ocaml_file: ocaml_file -> string + val path_of_js_file: js_file -> string + val path_of_cmo_file: cmo_file -> string + val path_of_bc_file: bc_file -> string + + val ocaml_file_of_path: string -> ocaml_file + val js_file_of_path: string -> js_file + val cmo_file_of_path: string -> cmo_file + val bc_file_of_path: string -> bc_file +end diff --git a/compiler/tests/expect_tests/integration.ml b/compiler/tests/expect_tests/integration.ml new file mode 100644 index 0000000000..4061a4413c --- /dev/null +++ b/compiler/tests/expect_tests/integration.ml @@ -0,0 +1,74 @@ +open Util + +let%expect_test _ = + {| console.log("hello world") |} + |> Util.Format.js_source_of_string + |> Util.Format.write_js + |> Util.run_javascript + |> print_endline; + [%expect {| hello world |}] + +let compile_and_run s = + s + |> Format.ocaml_source_of_string + |> Format.write_ocaml + |> compile_ocaml_to_bc + |> compile_bc_to_javascript + |> run_javascript + |> print_endline + +let%expect_test _ = + compile_and_run {| print_endline "hello world" |}; + [%expect {| hello world |}] + +let%expect_test _ = + compile_and_run {| print_float (Unix.time ()) |}; + [%expect {| [0-9]+\. (regexp) |}] + +let%expect_test _ = + compile_and_run {| print_float (Unix.gettimeofday ()) |}; + [%expect {| [0-9]+\.[0-9]* (regexp) |}] + +let%expect_test _ = + compile_and_run {| + open Unix + let {tm_sec; tm_min; tm_hour; tm_mday; tm_mon; tm_year; tm_wday; tm_yday; tm_isdst} + = gmtime (time ()) ;; + + print_int tm_sec; + print_char '\n'; + + print_int tm_min; + print_char '\n'; + + print_int tm_hour; + print_char '\n'; + + print_int tm_mday; + print_char '\n'; + + print_int tm_mon; + print_char '\n'; + + print_int tm_year; + print_char '\n'; + + print_int tm_wday; + print_char '\n'; + + print_int tm_yday; + print_char '\n'; + + print_endline (if tm_isdst then "true" else "false"); + |}; + [%expect {| + [0-9]+ (regexp) + [0-9]+ (regexp) + [0-9]+ (regexp) + [0-9]+ (regexp) + [0-9]+ (regexp) + [0-9]+ (regexp) + [0-9]+ (regexp) + [0-9]+ (regexp) + true\|false (regexp) + |}] diff --git a/compiler/tests/expect_tests/util.ml b/compiler/tests/expect_tests/util.ml index 0e6eb66ebe..165a44a915 100644 --- a/compiler/tests/expect_tests/util.ml +++ b/compiler/tests/expect_tests/util.ml @@ -16,78 +16,146 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -open Js_of_ocaml_compiler -open Js_of_ocaml_compiler.Stdlib - -let parse_js source = Parse_js.(parse (lexer_from_string source)) - -let rev_prop accessor name value = - let past = accessor () in - if past = value - then fun () -> () - else if value - then ( - Config.Flag.enable name; - fun () -> Config.Flag.disable name) - else ( - Config.Flag.disable name; - fun () -> Config.Flag.enable name) - -let print_compiled_js ?(pretty = true) cmo_channel = - let program, _, debug_data, _ = - Parse_bytecode.from_channel ~debug:`Names cmo_channel - in - let buffer = Buffer.create 100 in - let pp = Pretty_print.to_buffer buffer in - let silence_compiler () = - let prev = !Stdlib.quiet in - Stdlib.quiet := true; - fun () -> Stdlib.quiet := prev - in - let props = - if pretty - then - Config.Flag. - [ rev_prop shortvar "shortvar" false - ; rev_prop pretty "pretty" true - ; silence_compiler () ] - else - Config.Flag. - [ rev_prop shortvar "shortvar" true - ; rev_prop pretty "pretty" false - ; silence_compiler () ] +module Jsoo = Js_of_ocaml_compiler + +module Format: Format_intf.S = struct + type ocaml_source = string + type js_source = string + + type ocaml_file = string + type js_file = string + type cmo_file = string + type bc_file = string + + let read_file file = + let channel_to_string c_in = + let good_round_number = 1024 in + let buffer = Buffer.create good_round_number in + let rec loop () = + Buffer.add_channel buffer c_in good_round_number; + loop () + in + (try loop () with End_of_file -> ()); + Buffer.contents buffer + in + let channel = open_in file in + let res = channel_to_string channel in + close_in channel; + res + + let write_file ~suffix contents = + let temp_file = Filename.temp_file "jsoo_test" suffix in + let channel = open_out temp_file in + Printf.fprintf channel "%s" contents; + close_out channel; + temp_file + + let read_js = read_file + let read_ocaml = read_file + + let write_js = write_file ~suffix:".js" + let write_ocaml = write_file ~suffix:".ml" + + let id x = x + + let js_source_of_string = id + let ocaml_source_of_string = id + let string_of_js_source = id + let string_of_ocaml_source = id + + let path_of_ocaml_file = id + let path_of_js_file = id + let path_of_cmo_file = id + let path_of_bc_file = id + + let ocaml_file_of_path = id + let js_file_of_path = id + let cmo_file_of_path = id + let bc_file_of_path = id +end + +let parse_js file = + let open Jsoo.Parse_js in + file + |> Format.read_js + |> Format.string_of_js_source + |> lexer_from_string + |> parse + +let channel_to_string c_in = + let good_round_number = 1024 in + let buffer = Buffer.create good_round_number in + let rec loop () = + Buffer.add_channel buffer c_in good_round_number; + loop () in - (try Driver.f pp debug_data program - with e -> - List.iter props ~f:(fun f -> f ()); - raise e); - List.iter props ~f:(fun f -> f ()); + (try loop () with End_of_file -> ()); Buffer.contents buffer -let compile_ocaml_to_bytecode source = - let temp_file = Filename.temp_file "jsoo_test" ".ml" in - let out = open_out temp_file in - Printf.fprintf out "%s" source; - close_out out; - let prev_debug = !Clflags.debug in - Clflags.debug := true; - Compile.implementation Format.std_formatter temp_file temp_file; - Clflags.debug := prev_debug; - open_in (Format.sprintf "%s.cmo" temp_file) +let exec_to_string_exn ~cmd = + let proc_result_ok std_out = + let open Unix in + function + | WEXITED 0 -> () + | WEXITED i -> print_endline std_out; failwith (Stdlib.Format.sprintf "process exited with error code %d" i) + | WSIGNALED i -> print_endline std_out; failwith (Stdlib.Format.sprintf "process signaled with signal number %d" i) + | WSTOPPED i -> print_endline std_out; failwith (Stdlib.Format.sprintf "process stopped with signal number %d" i) + in + let proc_in = Unix.open_process_in cmd in + let results = channel_to_string proc_in in + proc_result_ok results (Unix.close_process_in proc_in); + results + +let run_javascript file = + exec_to_string_exn ~cmd:(Stdlib.Format.sprintf "node %s" (Format.path_of_js_file file)) + +let compile_to_javascript ~pretty file = + let out_file = Filename.temp_file "jsoo_test" ".js" in + let extra_args = if pretty then "--pretty" else "" in + let cmd = + (Stdlib.Format.sprintf "../../js_of_ocaml.exe %s %s -o %s" extra_args file out_file) in + let stdout = exec_to_string_exn ~cmd in + print_string stdout; + (* this print shouldn't do anything, so if something weird happens, we'll get the results + here *) + Format.js_file_of_path out_file + +let compile_bc_to_javascript ?(pretty=true) file = + Format.path_of_bc_file file + |> compile_to_javascript ~pretty + +let compile_cmo_to_javascript ?(pretty=true) file = + Format.path_of_cmo_file file + |> compile_to_javascript ~pretty + +let compile_ocaml_to_cmo file = + let out_file = Filename.temp_file "jsoo_test" ".cmo" in + let _ = exec_to_string_exn ~cmd:( + Stdlib.Format.sprintf "ocamlfind ocamlc -c -g %s -o %s" (Format.path_of_ocaml_file file) + out_file) in + Format.cmo_file_of_path out_file + +let compile_ocaml_to_bc file = + let out_file = Filename.temp_file "jsoo_test" ".bc" in + let _ = exec_to_string_exn ~cmd:( + Stdlib.Format.sprintf "ocamlfind ocamlc -g -linkpkg -package unix %s -o %s" (Format.path_of_ocaml_file file) + out_file) in + Format.bc_file_of_path out_file type find_result = - { expressions : Javascript.expression list - ; statements : Javascript.statement list - ; var_decls : Javascript.variable_declaration list } + + { expressions : Jsoo.Javascript.expression list + ; statements : Jsoo.Javascript.statement list + ; var_decls : Jsoo.Javascript.variable_declaration list } type finder_fun = - { expression : Javascript.expression -> unit - ; statement : Javascript.statement -> unit - ; variable_decl : Javascript.variable_declaration -> unit } + { expression : Jsoo.Javascript.expression -> unit + ; statement : Jsoo.Javascript.statement -> unit + ; variable_decl : Jsoo.Javascript.variable_declaration -> unit } class finder ff = object - inherit Js_traverse.map as super + inherit Jsoo.Js_traverse.map as super method! variable_declaration v = ff.variable_decl v; @@ -118,9 +186,10 @@ let find_javascript {statements = !statements; expressions = !expressions; var_decls = !var_decls} let expression_to_string ?(compact = false) e = - let e = [Javascript.Statement (Javascript.Expression_statement e), Javascript.N] in + let module J = Jsoo.Javascript in + let e = [J.Statement (J.Expression_statement e), J.N] in let buffer = Buffer.create 17 in - let pp = Pretty_print.to_buffer buffer in - Pretty_print.set_compact pp compact; - Js_output.program pp e; + let pp = Jsoo.Pretty_print.to_buffer buffer in + Jsoo.Pretty_print.set_compact pp compact; + Jsoo.Js_output.program pp e; Buffer.contents buffer diff --git a/compiler/tests/expect_tests/util.mli b/compiler/tests/expect_tests/util.mli index 07240c8a8a..4bb8971a34 100644 --- a/compiler/tests/expect_tests/util.mli +++ b/compiler/tests/expect_tests/util.mli @@ -19,11 +19,14 @@ open Js_of_ocaml_compiler -val parse_js : string -> Javascript.program +module Format: Format_intf.S -val compile_ocaml_to_bytecode : string -> in_channel - -val print_compiled_js : ?pretty:bool -> in_channel -> string +val parse_js : Format.js_file -> Javascript.program +val compile_ocaml_to_cmo : Format.ocaml_file -> Format.cmo_file +val compile_ocaml_to_bc : Format.ocaml_file -> Format.bc_file +val compile_cmo_to_javascript : ?pretty:bool -> Format.cmo_file -> Format.js_file +val compile_bc_to_javascript : ?pretty:bool -> Format.bc_file -> Format.js_file +val run_javascript: Format.js_file -> string type find_result = { expressions : Javascript.expression list diff --git a/compiler/tests/expect_tests/variable_declaration_output.ml b/compiler/tests/expect_tests/variable_declaration_output.ml index 85f972e32c..c23ee84fd5 100644 --- a/compiler/tests/expect_tests/variable_declaration_output.ml +++ b/compiler/tests/expect_tests/variable_declaration_output.ml @@ -28,14 +28,22 @@ let print_var_decl program n = | _ -> false) program in - print_string (Format.sprintf "var %s = " n); + print_string (Stdlib.Format.sprintf "var %s = " n); match var_decls with | [(_, Some (expression, _))] -> print_string (expression_to_string expression) | _ -> print_endline "not found" let%expect_test _ = - let cmo = - compile_ocaml_to_bytecode + let compile s = + s + |> Format.ocaml_source_of_string + |> Format.write_ocaml + |> Util.compile_ocaml_to_cmo + |> Util.compile_cmo_to_javascript ~pretty:true + |> Util.parse_js + in + + let program = compile {| let lr = ref (List.init 2 Obj.repr) let black_box v = lr := (Obj.repr v) :: !lr @@ -55,7 +63,6 @@ let%expect_test _ = print_int ((List.length !lr) + (List.length !lr)) |} in - let program = parse_js (print_compiled_js ~pretty:true cmo) in print_var_decl program "ex"; print_var_decl program "ax"; print_var_decl program "bx"; From 79bc7931637bf5f39f8cf451a23c658bc4a5c341 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Thu, 18 Apr 2019 17:15:10 +0800 Subject: [PATCH 10/16] many old regression tests are now expect_tests --- compiler/tests/GI507.ml | 34 -------- compiler/tests/build_path_prefix_map/dune | 1 + compiler/tests/common.ml | 48 ------------ compiler/tests/dune | 21 ++--- compiler/tests/expect_tests/dune | 8 -- compiler/tests/integration.ml | 22 ++++++ .../tests/integration/integration_util.ml | 9 +++ .../tests/integration/regression/gl507.ml | 11 +++ .../tests/integration/regression/is_int.ml | 17 ++++ .../integration/regression/match_with_exn.ml | 23 ++++++ .../integration/regression/mutable_closure.ml | 59 ++++++++++++++ .../tests/integration/regression/obj_dup.ml | 41 ++++++++++ .../integration/regression/side_effect.ml | 25 ++++++ .../tests/integration/regression/tailcall.ml | 15 ++++ .../integration.ml => integration/time.ml} | 24 +----- compiler/tests/is_int.ml | 20 ----- .../{expect_tests => }/js_parser_printer.ml | 0 compiler/tests/main.ml | 26 ------- compiler/tests/match_with_exn.ml | 45 ----------- compiler/tests/mutable_closure.ml | 78 ------------------- compiler/tests/obj_dup.ml | 13 ---- compiler/tests/side_effect.ml | 42 ---------- .../tests/{expect_tests => }/static_eval.ml | 0 compiler/tests/tailcall.ml | 33 -------- .../{expect_tests => util}/format_intf.ml | 0 compiler/tests/{expect_tests => util}/util.ml | 2 +- .../tests/{expect_tests => util}/util.mli | 0 .../variable_declaration_output.ml | 0 tools/toplevel_expect/dune | 2 +- 29 files changed, 235 insertions(+), 384 deletions(-) delete mode 100644 compiler/tests/GI507.ml delete mode 100644 compiler/tests/common.ml delete mode 100644 compiler/tests/expect_tests/dune create mode 100644 compiler/tests/integration.ml create mode 100644 compiler/tests/integration/integration_util.ml create mode 100644 compiler/tests/integration/regression/gl507.ml create mode 100644 compiler/tests/integration/regression/is_int.ml create mode 100644 compiler/tests/integration/regression/match_with_exn.ml create mode 100644 compiler/tests/integration/regression/mutable_closure.ml create mode 100644 compiler/tests/integration/regression/obj_dup.ml create mode 100644 compiler/tests/integration/regression/side_effect.ml create mode 100644 compiler/tests/integration/regression/tailcall.ml rename compiler/tests/{expect_tests/integration.ml => integration/time.ml} (68%) delete mode 100644 compiler/tests/is_int.ml rename compiler/tests/{expect_tests => }/js_parser_printer.ml (100%) delete mode 100644 compiler/tests/main.ml delete mode 100644 compiler/tests/match_with_exn.ml delete mode 100644 compiler/tests/mutable_closure.ml delete mode 100644 compiler/tests/obj_dup.ml delete mode 100644 compiler/tests/side_effect.ml rename compiler/tests/{expect_tests => }/static_eval.ml (100%) delete mode 100644 compiler/tests/tailcall.ml rename compiler/tests/{expect_tests => util}/format_intf.ml (100%) rename compiler/tests/{expect_tests => util}/util.ml (98%) rename compiler/tests/{expect_tests => util}/util.mli (100%) rename compiler/tests/{expect_tests => }/variable_declaration_output.ml (100%) diff --git a/compiler/tests/GI507.ml b/compiler/tests/GI507.ml deleted file mode 100644 index 09875a0057..0000000000 --- a/compiler/tests/GI507.ml +++ /dev/null @@ -1,34 +0,0 @@ -(* Js_of_ocaml compiler - * http://www.ocsigen.org/js_of_ocaml/ - * Copyright (C) 2017 Hugo Heuzard - * - * 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, with linking exception; - * either version 2.1 of the License, or (at your option) any 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. - *) - -(* https://github.com/ocsigen/js_of_ocaml/issues/507 - * Missing parentheses around "-1" in generated code #507 *) - -open Common - -let log_stop = log_start "Missing parentheses around \"-1\" in generated code" - -let _ = - let r = ref 0.0 in - for _ = 1 to 100 do - r := !r -. (-1.0 *. !r) - done; - () - -let _ = log_stop () diff --git a/compiler/tests/build_path_prefix_map/dune b/compiler/tests/build_path_prefix_map/dune index ba5ee23abc..e15321fbf5 100644 --- a/compiler/tests/build_path_prefix_map/dune +++ b/compiler/tests/build_path_prefix_map/dune @@ -7,6 +7,7 @@ (names setup_env) (libraries unix)) +(include_subdirs no) (rule (targets generated.map generated.js) diff --git a/compiler/tests/common.ml b/compiler/tests/common.ml deleted file mode 100644 index 7750bd51a5..0000000000 --- a/compiler/tests/common.ml +++ /dev/null @@ -1,48 +0,0 @@ -(* Js_of_ocaml example - * http://www.ocsigen.org/js_of_ocaml/ - * Copyright (C) 2010 Jérôme Vouillon - * Laboratoire PPS - CNRS Université Paris Diderot - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any 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 success_count_all = ref 0 - -let test_count_all = ref 0 - -let success_count = ref 0 - -let test_count = ref 0 - -let log_success () = - incr success_count; - incr test_count - -let log_failure s = - incr test_count; - Format.printf "\tFAILURE: %s\n" s - -let log_start s = - Format.printf "START: %s\n" s; - let log_stop () : unit = - success_count_all := !success_count_all + !success_count; - test_count_all := !test_count_all + !test_count; - Format.printf "STOP: %s\n" s - in - log_stop - -let raw_log x = Format.printf "\t\t %s" x - -let log s = raw_log s diff --git a/compiler/tests/dune b/compiler/tests/dune index 119b4e80ef..ef4a17a0b1 100644 --- a/compiler/tests/dune +++ b/compiler/tests/dune @@ -1,14 +1,9 @@ -(executable - (name main)) +(library + (name expect_tests) + (libraries js_of_ocaml_compiler unix) + (inline_tests + (flags -allow-output-patterns) + (deps (file ../js_of_ocaml.exe))) + (preprocess (pps ppx_expect))) -(rule - (targets main.js) - (action (run %{bin:js_of_ocaml} - --enable with-js-error - --no-runtime %{lib:js_of_ocaml-compiler:runtime.js} - %{dep:main.bc} -o %{targets})) - ) - -(alias - (name runtest) - (action (run node %{dep:main.js}))) +(include_subdirs unqualified) diff --git a/compiler/tests/expect_tests/dune b/compiler/tests/expect_tests/dune deleted file mode 100644 index 9e7a608e73..0000000000 --- a/compiler/tests/expect_tests/dune +++ /dev/null @@ -1,8 +0,0 @@ -(library - (name expect_tests) - (libraries js_of_ocaml_compiler unix ocaml-compiler-libs.bytecomp) - (inline_tests - (flags -allow-output-patterns) - (deps (file ../../js_of_ocaml.exe))) - (preprocess (pps ppx_expect))) - diff --git a/compiler/tests/integration.ml b/compiler/tests/integration.ml new file mode 100644 index 0000000000..562f907cb5 --- /dev/null +++ b/compiler/tests/integration.ml @@ -0,0 +1,22 @@ +open Util + +let%expect_test _ = + {| console.log("hello world") |} + |> Util.Format.js_source_of_string + |> Util.Format.write_js + |> Util.run_javascript + |> print_endline; + [%expect {| hello world |}] + +let compile_and_run s = + s + |> Format.ocaml_source_of_string + |> Format.write_ocaml + |> compile_ocaml_to_bc + |> compile_bc_to_javascript + |> run_javascript + |> print_endline + +let%expect_test _ = + compile_and_run {| print_endline "hello world" |}; + [%expect {| hello world |}] diff --git a/compiler/tests/integration/integration_util.ml b/compiler/tests/integration/integration_util.ml new file mode 100644 index 0000000000..a5a4dfdbfe --- /dev/null +++ b/compiler/tests/integration/integration_util.ml @@ -0,0 +1,9 @@ +open Util +let compile_and_run s = + s + |> Format.ocaml_source_of_string + |> Format.write_ocaml + |> compile_ocaml_to_bc + |> compile_bc_to_javascript + |> run_javascript + |> print_endline diff --git a/compiler/tests/integration/regression/gl507.ml b/compiler/tests/integration/regression/gl507.ml new file mode 100644 index 0000000000..86a7d1bec2 --- /dev/null +++ b/compiler/tests/integration/regression/gl507.ml @@ -0,0 +1,11 @@ + +let%expect_test _ = Integration_util.compile_and_run {| + let _ = + let r = ref 0.0 in + for _ = 1 to 100 do + r := !r -. (-1.0 *. !r) + done; + (); + print_endline "Success!" + |}; + [%expect {| Success! |}] diff --git a/compiler/tests/integration/regression/is_int.ml b/compiler/tests/integration/regression/is_int.ml new file mode 100644 index 0000000000..67aeffbd5a --- /dev/null +++ b/compiler/tests/integration/regression/is_int.ml @@ -0,0 +1,17 @@ +let%expect_test _ = Integration_util.compile_and_run {| + let r = ref false + let f x = match Obj.is_int x with + | true -> r := true; true + | false -> r := false; false + + let print_bool b = print_endline (string_of_bool b) + let () = + print_string "[not (is_int 1)]: "; + print_bool (not (f (Obj.repr 1))); + print_string "[is_int (1,2,3)]: "; + print_bool (f (Obj.repr (1, 2, 3))) + |}; + [%expect {| + [not (is_int 1)]: false + [is_int (1,2,3)]: false + |}] diff --git a/compiler/tests/integration/regression/match_with_exn.ml b/compiler/tests/integration/regression/match_with_exn.ml new file mode 100644 index 0000000000..7d156f97ff --- /dev/null +++ b/compiler/tests/integration/regression/match_with_exn.ml @@ -0,0 +1,23 @@ +let%expect_test _ = Integration_util.compile_and_run {| + exception A + exception B of int + + let a_exn () = raise A + + (* Make sure that [a] doesn't look constant *) + let a () = if Random.int 1 + 1 = 0 then 2 else 4 + + let b_exn () = raise (B 2) + + (* https://github.com/ocsigen/js_of_ocaml/issues/400 + * match .. with exception is no compiled properly *) + let () = + assert ( + try + match a () with + | exception (A | B _) -> true + | _n -> b_exn () + with B _ -> true); + print_endline "Success!" +|}; + [%expect "Success!"] diff --git a/compiler/tests/integration/regression/mutable_closure.ml b/compiler/tests/integration/regression/mutable_closure.ml new file mode 100644 index 0000000000..0b0ab7cda4 --- /dev/null +++ b/compiler/tests/integration/regression/mutable_closure.ml @@ -0,0 +1,59 @@ +let%expect_test _ = Integration_util.compile_and_run {| + let log_success () = print_endline "Success!" + let log_failure = Printf.printf "Failure! %s" + + let direct = ref [] + + let indirect = ref [] + + let () = + for i = 0 to 3 do + let rec f = function + | 0 -> i + | -1 -> g (-2) (* deadcode or infinite loop *) + | n -> g (pred n) + and g = function + | 0 -> i + | -1 -> f (-2) (* deadcode or infinite loop *) + | n -> f (pred n) + in + direct := f i :: !direct; + indirect := (fun () -> f i) :: !indirect + done; + let indirect = List.map (fun f -> f ()) !indirect in + let direct = !direct in + assert (indirect = direct) + + let () = + let delayed = ref (fun () -> ()) in + for i = 1 to 2 do + let rec f n = function + | 0 -> assert (i = n) + | j -> + delayed := + let prev = !delayed in + fun () -> + prev (); + f (succ n + i - i) (pred j) + in + f 0 i + done; + !delayed () + + let _ = + let l_fun = ref [] in + let l_var = ref [] in + let l_base = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] in + for i = 0 to 10 do + l_fun := (fun () -> i) :: !l_fun; + l_var := i :: !l_var + done; + let sum l = List.fold_left ( + ) 0 l in + let sum_base = sum l_base in + if sum !l_var <> sum_base + then log_failure "l_var" + else if sum (List.map (fun f -> f ()) !l_fun) <> sum_base + then log_failure "l_fun" + else log_success () +|}; +[%expect "Success!"] diff --git a/compiler/tests/integration/regression/obj_dup.ml b/compiler/tests/integration/regression/obj_dup.ml new file mode 100644 index 0000000000..633229f0ea --- /dev/null +++ b/compiler/tests/integration/regression/obj_dup.ml @@ -0,0 +1,41 @@ +let%expect_test _ = Integration_util.compile_and_run {| + let print_bool b = print_endline (string_of_bool b) + let () = + let s = "Hello" in + let s' : string = Obj.obj (Obj.dup (Obj.repr s)) in + print_bool (s = s'); + print_bool (s != s') + + let () = + let s = Bytes.of_string "Hello" in + let s' : bytes = Obj.obj (Obj.dup (Obj.repr s)) in + print_bool (s = s'); + print_bool (s != s'); + Bytes.set s' 1 'a'; + print_bool (s <> s') + |}; + [%expect {| + true + true + true + true + true + |}] + +let%expect_test _ = Integration_util.compile_and_run {| + let r = ref false + let f x = match Obj.is_int x with + | true -> r := true; true + | false -> r := false; false + + let print_bool b = print_endline (string_of_bool b) + let () = + print_string "[not (is_int 1)]: "; + print_bool (not (f (Obj.repr 1))); + print_string "[is_int (1,2,3)]: "; + print_bool (f (Obj.repr (1, 2, 3))) + |}; + [%expect {| + [not (is_int 1)]: false + [is_int (1,2,3)]: false + |}] diff --git a/compiler/tests/integration/regression/side_effect.ml b/compiler/tests/integration/regression/side_effect.ml new file mode 100644 index 0000000000..ffd163f69a --- /dev/null +++ b/compiler/tests/integration/regression/side_effect.ml @@ -0,0 +1,25 @@ +let%expect_test _ =Integration_util.compile_and_run {| + let i = ref 0 + let log_success () = print_endline "Success!" + let log_failure = Printf.printf "Failure! %s" + + let side_effect yes label = + if yes + then ( + Printf.printf "Side effect: %s\n%!" label; + incr i); + 0 + + let _ = side_effect false "this is only to avoid inlining" + + let f = + match side_effect true "Should only see this once" with + | 0 | 1 | 2 -> Printf.printf "Please don't optimize this away\n%!" + | _ -> Printf.printf "Or this\n%!" + + let _ = if !i = 1 then log_success () else log_failure "side effect computed twice" + |}; + [%expect {| + Side effect: Should only see this once + Please don't optimize this away + Success! |}] diff --git a/compiler/tests/integration/regression/tailcall.ml b/compiler/tests/integration/regression/tailcall.ml new file mode 100644 index 0000000000..f4198e2777 --- /dev/null +++ b/compiler/tests/integration/regression/tailcall.ml @@ -0,0 +1,15 @@ + let%expect_test _ = Integration_util.compile_and_run {| + let log_success () = print_endline "Success!" + let log_failure = Printf.printf "Failure! %s" + + let _ = + let rec odd x = if x = 0 then false else even (x - 1) + and even x = if x = 0 then true else odd (x - 1) in + assert (odd 1 <> even 1); + try + ignore (odd 5000); + log_success () + with _ -> log_failure "too much recursion" + |}; + [%expect {| Success! |}] + diff --git a/compiler/tests/expect_tests/integration.ml b/compiler/tests/integration/time.ml similarity index 68% rename from compiler/tests/expect_tests/integration.ml rename to compiler/tests/integration/time.ml index 4061a4413c..7eca44d948 100644 --- a/compiler/tests/expect_tests/integration.ml +++ b/compiler/tests/integration/time.ml @@ -1,25 +1,4 @@ -open Util - -let%expect_test _ = - {| console.log("hello world") |} - |> Util.Format.js_source_of_string - |> Util.Format.write_js - |> Util.run_javascript - |> print_endline; - [%expect {| hello world |}] - -let compile_and_run s = - s - |> Format.ocaml_source_of_string - |> Format.write_ocaml - |> compile_ocaml_to_bc - |> compile_bc_to_javascript - |> run_javascript - |> print_endline - -let%expect_test _ = - compile_and_run {| print_endline "hello world" |}; - [%expect {| hello world |}] +open Integration_util let%expect_test _ = compile_and_run {| print_float (Unix.time ()) |}; @@ -72,3 +51,4 @@ let%expect_test _ = [0-9]+ (regexp) true\|false (regexp) |}] + diff --git a/compiler/tests/is_int.ml b/compiler/tests/is_int.ml deleted file mode 100644 index 6240481202..0000000000 --- a/compiler/tests/is_int.ml +++ /dev/null @@ -1,20 +0,0 @@ -open Common - -let log_stop = log_start "Is_int test suite" - -let r = ref false - -let f x = - match Obj.is_int x with - | true -> - r := true; - true - | false -> - r := false; - false - -let () = - if not (f (Obj.repr 1)) then log_failure "[is_int 1] should be true"; - if f (Obj.repr (1, 2, 3)) then log_failure "[is_int (1,2,3)] should be false" - -let _ = log_stop () diff --git a/compiler/tests/expect_tests/js_parser_printer.ml b/compiler/tests/js_parser_printer.ml similarity index 100% rename from compiler/tests/expect_tests/js_parser_printer.ml rename to compiler/tests/js_parser_printer.ml diff --git a/compiler/tests/main.ml b/compiler/tests/main.ml deleted file mode 100644 index a5821ad721..0000000000 --- a/compiler/tests/main.ml +++ /dev/null @@ -1,26 +0,0 @@ -(* Js_of_ocaml compiler - * http://www.ocsigen.org/js_of_ocaml/ - * Copyright (C) 2017 Hugo Heuzard - * - * 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, with linking exception; - * either version 2.1 of the License, or (at your option) any 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. - *) - -module Side_effect = Side_effect -module Tailcall = Tailcall -module GI507 = GI507 -module Match_with_exn = Match_with_exn -module Mutable_closure = Mutable_closure -module Obj_dup = Obj_dup -module Is_int = Is_int diff --git a/compiler/tests/match_with_exn.ml b/compiler/tests/match_with_exn.ml deleted file mode 100644 index ecb25fb67d..0000000000 --- a/compiler/tests/match_with_exn.ml +++ /dev/null @@ -1,45 +0,0 @@ -(* Js_of_ocaml compiler - * http://www.ocsigen.org/js_of_ocaml/ - * Copyright (C) 2017 Hugo Heuzard - * - * 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, with linking exception; - * either version 2.1 of the License, or (at your option) any 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. - *) - -open Common - -let log_stop = log_start "match .. with exception" - -exception A - -exception B of int - -let a_exn () = raise A - -(* Make sure that [a] doesn't look constant *) -let a () = if Random.int 1 + 1 = 0 then 2 else 4 - -let b_exn () = raise (B 2) - -(* https://github.com/ocsigen/js_of_ocaml/issues/400 - * match .. with exception is no compiled properly *) -let () = - assert ( - try - match a () with - | exception (A | B _) -> true - | _n -> b_exn () - with B _ -> true) - -let _ = log_stop () diff --git a/compiler/tests/mutable_closure.ml b/compiler/tests/mutable_closure.ml deleted file mode 100644 index 025073c0b7..0000000000 --- a/compiler/tests/mutable_closure.ml +++ /dev/null @@ -1,78 +0,0 @@ -(* Js_of_ocaml compiler - * http://www.ocsigen.org/js_of_ocaml/ - * Copyright (C) 2017 Hugo Heuzard - * - * 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, with linking exception; - * either version 2.1 of the License, or (at your option) any 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. - *) - -open Common - -let log_stop = log_start "Closure test suite (2)" - -let direct = ref [] - -let indirect = ref [] - -let () = - for i = 0 to 3 do - let rec f = function - | 0 -> i - | -1 -> g (-2) (* deadcode or infinite loop *) - | n -> g (pred n) - and g = function - | 0 -> i - | -1 -> f (-2) (* deadcode or infinite loop *) - | n -> f (pred n) - in - direct := f i :: !direct; - indirect := (fun () -> f i) :: !indirect - done; - let indirect = List.map (fun f -> f ()) !indirect in - let direct = !direct in - assert (indirect = direct) - -let () = - let delayed = ref (fun () -> ()) in - for i = 1 to 2 do - let rec f n = function - | 0 -> assert (i = n) - | j -> - delayed := - let prev = !delayed in - fun () -> - prev (); - f (succ n + i - i) (pred j) - in - f 0 i - done; - !delayed () - -let _ = - let l_fun = ref [] in - let l_var = ref [] in - let l_base = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] in - for i = 0 to 10 do - l_fun := (fun () -> i) :: !l_fun; - l_var := i :: !l_var - done; - let sum l = List.fold_left ( + ) 0 l in - let sum_base = sum l_base in - if sum !l_var <> sum_base - then log_failure "l_var" - else if sum (List.map (fun f -> f ()) !l_fun) <> sum_base - then log_failure "l_fun" - else log_success () - -let () = log_stop () diff --git a/compiler/tests/obj_dup.ml b/compiler/tests/obj_dup.ml deleted file mode 100644 index 38c715f8f8..0000000000 --- a/compiler/tests/obj_dup.ml +++ /dev/null @@ -1,13 +0,0 @@ -let () = - let s = "Hello" in - let s' : string = Obj.obj (Obj.dup (Obj.repr s)) in - assert (s = s'); - assert (s != s') - -let () = - let s = Bytes.of_string "Hello" in - let s' : bytes = Obj.obj (Obj.dup (Obj.repr s)) in - assert (s = s'); - assert (s != s'); - Bytes.set s' 1 'a'; - assert (s <> s') diff --git a/compiler/tests/side_effect.ml b/compiler/tests/side_effect.ml deleted file mode 100644 index a35bfe59a4..0000000000 --- a/compiler/tests/side_effect.ml +++ /dev/null @@ -1,42 +0,0 @@ -(* Js_of_ocaml compiler - * http://www.ocsigen.org/js_of_ocaml/ - * Copyright (C) 2017 Hugo Heuzard - * - * 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, with linking exception; - * either version 2.1 of the License, or (at your option) any 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. - *) - -open Common - -let log_stop = log_start "Side effect test suite" - -let i = ref 0 - -let side_effect yes label = - if yes - then ( - Printf.printf "Side effect: %s\n%!" label; - incr i); - 0 - -let _ = side_effect false "this is only to avoid inlining" - -let f = - match side_effect true "Should only see this once" with - | 0 | 1 | 2 -> Printf.printf "Please don't optimize this away\n%!" - | _ -> Printf.printf "Or this\n%!" - -let _ = if !i = 1 then log_success () else log_failure "side effect computed twice" - -let _ = log_stop () diff --git a/compiler/tests/expect_tests/static_eval.ml b/compiler/tests/static_eval.ml similarity index 100% rename from compiler/tests/expect_tests/static_eval.ml rename to compiler/tests/static_eval.ml diff --git a/compiler/tests/tailcall.ml b/compiler/tests/tailcall.ml deleted file mode 100644 index 9df776b61d..0000000000 --- a/compiler/tests/tailcall.ml +++ /dev/null @@ -1,33 +0,0 @@ -(* Js_of_ocaml example - * http://www.ocsigen.org/js_of_ocaml/ - * Copyright (C) 2013 Hugo Heuzard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any 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. - *) - -open Common - -let log_stop = log_start "Tailcall test suite" - -let _ = - let rec odd x = if x = 0 then false else even (x - 1) - and even x = if x = 0 then true else odd (x - 1) in - assert (odd 1 <> even 1); - try - ignore (odd 5000); - log_success () - with _ -> log_failure "too much recursion" - -let () = log_stop () diff --git a/compiler/tests/expect_tests/format_intf.ml b/compiler/tests/util/format_intf.ml similarity index 100% rename from compiler/tests/expect_tests/format_intf.ml rename to compiler/tests/util/format_intf.ml diff --git a/compiler/tests/expect_tests/util.ml b/compiler/tests/util/util.ml similarity index 98% rename from compiler/tests/expect_tests/util.ml rename to compiler/tests/util/util.ml index 4338435b8d..a20b87d70f 100644 --- a/compiler/tests/expect_tests/util.ml +++ b/compiler/tests/util/util.ml @@ -113,7 +113,7 @@ let compile_to_javascript ~pretty file = let out_file = Filename.temp_file "jsoo_test" ".js" in let extra_args = if pretty then "--pretty" else "" in let cmd = - (Stdlib.Format.sprintf "../../js_of_ocaml.exe %s %s -o %s" extra_args file out_file) in + (Stdlib.Format.sprintf "../js_of_ocaml.exe %s %s -o %s" extra_args file out_file) in let stdout = exec_to_string_exn ~cmd in print_string stdout; (* this print shouldn't do anything, so if something weird happens, we'll get the results diff --git a/compiler/tests/expect_tests/util.mli b/compiler/tests/util/util.mli similarity index 100% rename from compiler/tests/expect_tests/util.mli rename to compiler/tests/util/util.mli diff --git a/compiler/tests/expect_tests/variable_declaration_output.ml b/compiler/tests/variable_declaration_output.ml similarity index 100% rename from compiler/tests/expect_tests/variable_declaration_output.ml rename to compiler/tests/variable_declaration_output.ml diff --git a/tools/toplevel_expect/dune b/tools/toplevel_expect/dune index 24ce41e246..125aacc9d0 100644 --- a/tools/toplevel_expect/dune +++ b/tools/toplevel_expect/dune @@ -1,6 +1,6 @@ (library (name toplevel_expect_test) - (libraries compiler-libs.common compiler-libs.toplevel)) + (libraries)) (rule (targets toplevel_expect_test.ml) From 756e56e17346db31f37190f5d9153da9a1236eb3 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Thu, 18 Apr 2019 17:28:53 +0800 Subject: [PATCH 11/16] _ --- compiler/tests/end_to_end.ml | 41 +++++++++++ compiler/tests/integration.ml | 22 ------ .../tests/integration/integration_util.ml | 20 ++++++ .../tests/integration/regression/gl507.ml | 26 ++++++- .../tests/integration/regression/is_int.ml | 26 ++++++- .../integration/regression/match_with_exn.ml | 27 ++++++- .../integration/regression/mutable_closure.ml | 26 ++++++- .../tests/integration/regression/obj_dup.ml | 31 +++++++- .../integration/regression/side_effect.ml | 30 +++++++- .../tests/integration/regression/tailcall.ml | 29 +++++++- compiler/tests/integration/time.ml | 26 ++++++- compiler/tests/static_eval.ml | 4 +- compiler/tests/util/format_intf.ml | 46 +++++++----- compiler/tests/util/util.ml | 71 +++++++++++++------ compiler/tests/util/util.mli | 9 ++- compiler/tests/variable_declaration_output.ml | 6 +- 16 files changed, 358 insertions(+), 82 deletions(-) create mode 100644 compiler/tests/end_to_end.ml delete mode 100644 compiler/tests/integration.ml diff --git a/compiler/tests/end_to_end.ml b/compiler/tests/end_to_end.ml new file mode 100644 index 0000000000..d26d9cb54d --- /dev/null +++ b/compiler/tests/end_to_end.ml @@ -0,0 +1,41 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +open Util + +let%expect_test _ = + {| console.log("hello world") |} + |> Util.Format.js_source_of_string + |> Util.Format.write_js + |> Util.run_javascript + |> print_endline; + [%expect {| hello world |}] + +let compile_and_run s = + s + |> Format.ocaml_source_of_string + |> Format.write_ocaml + |> compile_ocaml_to_bc + |> compile_bc_to_javascript + |> run_javascript + |> print_endline + +let%expect_test _ = + compile_and_run {| print_endline "hello world" |}; + [%expect {| hello world |}] diff --git a/compiler/tests/integration.ml b/compiler/tests/integration.ml deleted file mode 100644 index 562f907cb5..0000000000 --- a/compiler/tests/integration.ml +++ /dev/null @@ -1,22 +0,0 @@ -open Util - -let%expect_test _ = - {| console.log("hello world") |} - |> Util.Format.js_source_of_string - |> Util.Format.write_js - |> Util.run_javascript - |> print_endline; - [%expect {| hello world |}] - -let compile_and_run s = - s - |> Format.ocaml_source_of_string - |> Format.write_ocaml - |> compile_ocaml_to_bc - |> compile_bc_to_javascript - |> run_javascript - |> print_endline - -let%expect_test _ = - compile_and_run {| print_endline "hello world" |}; - [%expect {| hello world |}] diff --git a/compiler/tests/integration/integration_util.ml b/compiler/tests/integration/integration_util.ml index a5a4dfdbfe..0b28ae0642 100644 --- a/compiler/tests/integration/integration_util.ml +++ b/compiler/tests/integration/integration_util.ml @@ -1,4 +1,24 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + open Util + let compile_and_run s = s |> Format.ocaml_source_of_string diff --git a/compiler/tests/integration/regression/gl507.ml b/compiler/tests/integration/regression/gl507.ml index 86a7d1bec2..105f66bc38 100644 --- a/compiler/tests/integration/regression/gl507.ml +++ b/compiler/tests/integration/regression/gl507.ml @@ -1,5 +1,29 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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%expect_test _ = Integration_util.compile_and_run {| +(* https://github.com/ocsigen/js_of_ocaml/issues/507 *) +(* https://github.com/ocsigen/js_of_ocaml/commit/e2f465dd1ac03da706ae086da37794184db21d31 *) + +let%expect_test _ = + Integration_util.compile_and_run + {| let _ = let r = ref 0.0 in for _ = 1 to 100 do diff --git a/compiler/tests/integration/regression/is_int.ml b/compiler/tests/integration/regression/is_int.ml index 67aeffbd5a..c25a9f1623 100644 --- a/compiler/tests/integration/regression/is_int.ml +++ b/compiler/tests/integration/regression/is_int.ml @@ -1,4 +1,28 @@ -let%expect_test _ = Integration_util.compile_and_run {| +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +(* https://github.com/ocsigen/js_of_ocaml/issues/739 *) + +let%expect_test _ = + Integration_util.compile_and_run + {| let r = ref false let f x = match Obj.is_int x with | true -> r := true; true diff --git a/compiler/tests/integration/regression/match_with_exn.ml b/compiler/tests/integration/regression/match_with_exn.ml index 7d156f97ff..2518230116 100644 --- a/compiler/tests/integration/regression/match_with_exn.ml +++ b/compiler/tests/integration/regression/match_with_exn.ml @@ -1,4 +1,29 @@ -let%expect_test _ = Integration_util.compile_and_run {| +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +(* https://github.com/ocsigen/js_of_ocaml/issues/400 *) +(* https://github.com/ocsigen/js_of_ocaml/pull/402 *) + +let%expect_test _ = + Integration_util.compile_and_run + {| exception A exception B of int diff --git a/compiler/tests/integration/regression/mutable_closure.ml b/compiler/tests/integration/regression/mutable_closure.ml index 0b0ab7cda4..1c8130accc 100644 --- a/compiler/tests/integration/regression/mutable_closure.ml +++ b/compiler/tests/integration/regression/mutable_closure.ml @@ -1,4 +1,26 @@ -let%expect_test _ = Integration_util.compile_and_run {| +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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%expect_test _ = + Integration_util.compile_and_run + {| let log_success () = print_endline "Success!" let log_failure = Printf.printf "Failure! %s" @@ -56,4 +78,4 @@ let%expect_test _ = Integration_util.compile_and_run {| then log_failure "l_fun" else log_success () |}; -[%expect "Success!"] + [%expect "Success!"] diff --git a/compiler/tests/integration/regression/obj_dup.ml b/compiler/tests/integration/regression/obj_dup.ml index 633229f0ea..353d270945 100644 --- a/compiler/tests/integration/regression/obj_dup.ml +++ b/compiler/tests/integration/regression/obj_dup.ml @@ -1,4 +1,29 @@ -let%expect_test _ = Integration_util.compile_and_run {| +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +(* https://github.com/ocsigen/js_of_ocaml/issues/666 *) +(* https://github.com/ocsigen/js_of_ocaml/pull/725 *) + +let%expect_test _ = + Integration_util.compile_and_run + {| let print_bool b = print_endline (string_of_bool b) let () = let s = "Hello" in @@ -22,7 +47,9 @@ let%expect_test _ = Integration_util.compile_and_run {| true |}] -let%expect_test _ = Integration_util.compile_and_run {| +let%expect_test _ = + Integration_util.compile_and_run + {| let r = ref false let f x = match Obj.is_int x with | true -> r := true; true diff --git a/compiler/tests/integration/regression/side_effect.ml b/compiler/tests/integration/regression/side_effect.ml index ffd163f69a..e9829d6876 100644 --- a/compiler/tests/integration/regression/side_effect.ml +++ b/compiler/tests/integration/regression/side_effect.ml @@ -1,4 +1,29 @@ -let%expect_test _ =Integration_util.compile_and_run {| +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +(* https://github.com/ocsigen/js_of_ocaml/issues/177 *) +(* https://github.com/ocsigen/js_of_ocaml/pull/178 *) + +let%expect_test _ = + Integration_util.compile_and_run + {| let i = ref 0 let log_success () = print_endline "Success!" let log_failure = Printf.printf "Failure! %s" @@ -19,7 +44,8 @@ let%expect_test _ =Integration_util.compile_and_run {| let _ = if !i = 1 then log_success () else log_failure "side effect computed twice" |}; - [%expect {| + [%expect + {| Side effect: Should only see this once Please don't optimize this away Success! |}] diff --git a/compiler/tests/integration/regression/tailcall.ml b/compiler/tests/integration/regression/tailcall.ml index f4198e2777..8a0ce839be 100644 --- a/compiler/tests/integration/regression/tailcall.ml +++ b/compiler/tests/integration/regression/tailcall.ml @@ -1,4 +1,28 @@ - let%expect_test _ = Integration_util.compile_and_run {| +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +(* https://github.com/ocsigen/js_of_ocaml/commit/a1a24b53e3e25af30b30e2e1779991db1055143e *) + +let%expect_test _ = + Integration_util.compile_and_run + {| let log_success () = print_endline "Success!" let log_failure = Printf.printf "Failure! %s" @@ -11,5 +35,4 @@ log_success () with _ -> log_failure "too much recursion" |}; - [%expect {| Success! |}] - + [%expect {| Success! |}] diff --git a/compiler/tests/integration/time.ml b/compiler/tests/integration/time.ml index 7eca44d948..caaddcfee4 100644 --- a/compiler/tests/integration/time.ml +++ b/compiler/tests/integration/time.ml @@ -1,3 +1,22 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + open Integration_util let%expect_test _ = @@ -9,7 +28,8 @@ let%expect_test _ = [%expect {| [0-9]+\.[0-9]* (regexp) |}] let%expect_test _ = - compile_and_run {| + compile_and_run + {| open Unix let {tm_sec; tm_min; tm_hour; tm_mday; tm_mon; tm_year; tm_wday; tm_yday; tm_isdst} = gmtime (time ()) ;; @@ -40,7 +60,8 @@ let%expect_test _ = print_endline (if tm_isdst then "true" else "false"); |}; - [%expect {| + [%expect + {| [0-9]+ (regexp) [0-9]+ (regexp) [0-9]+ (regexp) @@ -51,4 +72,3 @@ let%expect_test _ = [0-9]+ (regexp) true\|false (regexp) |}] - diff --git a/compiler/tests/static_eval.ml b/compiler/tests/static_eval.ml index e985819107..7953289e76 100644 --- a/compiler/tests/static_eval.ml +++ b/compiler/tests/static_eval.ml @@ -28,7 +28,9 @@ let run_test s = |> parse_js let%expect_test "static eval of string get" = - let program = run_test {| + let program = + run_test + {| let lr = ref [] let black_box v = lr := (Obj.repr v) :: !lr diff --git a/compiler/tests/util/format_intf.ml b/compiler/tests/util/format_intf.ml index a4aec66a0b..5379227103 100644 --- a/compiler/tests/util/format_intf.ml +++ b/compiler/tests/util/format_intf.ml @@ -1,31 +1,45 @@ module type S = sig type ocaml_source + type js_source type ocaml_file + type js_file + type cmo_file + type bc_file - val read_js: js_file -> js_source - val read_ocaml: ocaml_file -> ocaml_source + val read_js : js_file -> js_source + + val read_ocaml : ocaml_file -> ocaml_source + + val write_js : js_source -> js_file + + val write_ocaml : ocaml_source -> ocaml_file + + val js_source_of_string : string -> js_source + + val ocaml_source_of_string : string -> ocaml_source + + val string_of_js_source : js_source -> string + + val string_of_ocaml_source : ocaml_source -> string + + val path_of_ocaml_file : ocaml_file -> string + + val path_of_js_file : js_file -> string + + val path_of_cmo_file : cmo_file -> string - val write_js: js_source -> js_file - val write_ocaml: ocaml_source -> ocaml_file + val path_of_bc_file : bc_file -> string - val js_source_of_string: string -> js_source - val ocaml_source_of_string: string -> ocaml_source + val ocaml_file_of_path : string -> ocaml_file - val string_of_js_source: js_source -> string - val string_of_ocaml_source: ocaml_source -> string + val js_file_of_path : string -> js_file - val path_of_ocaml_file: ocaml_file -> string - val path_of_js_file: js_file -> string - val path_of_cmo_file: cmo_file -> string - val path_of_bc_file: bc_file -> string + val cmo_file_of_path : string -> cmo_file - val ocaml_file_of_path: string -> ocaml_file - val js_file_of_path: string -> js_file - val cmo_file_of_path: string -> cmo_file - val bc_file_of_path: string -> bc_file + val bc_file_of_path : string -> bc_file end diff --git a/compiler/tests/util/util.ml b/compiler/tests/util/util.ml index a20b87d70f..95d54ae223 100644 --- a/compiler/tests/util/util.ml +++ b/compiler/tests/util/util.ml @@ -18,13 +18,17 @@ *) module Jsoo = Js_of_ocaml_compiler -module Format: Format_intf.S = struct +module Format : Format_intf.S = struct type ocaml_source = string + type js_source = string type ocaml_file = string + type js_file = string + type cmo_file = string + type bc_file = string let read_file file = @@ -51,36 +55,43 @@ module Format: Format_intf.S = struct temp_file let read_js = read_file + let read_ocaml = read_file let write_js = write_file ~suffix:".js" + let write_ocaml = write_file ~suffix:".ml" let id x = x let js_source_of_string = id + let ocaml_source_of_string = id + let string_of_js_source = id + let string_of_ocaml_source = id let path_of_ocaml_file = id + let path_of_js_file = id + let path_of_cmo_file = id + let path_of_bc_file = id let ocaml_file_of_path = id + let js_file_of_path = id + let cmo_file_of_path = id + let bc_file_of_path = id end let parse_js file = let open Jsoo.Parse_js in - file - |> Format.read_js - |> Format.string_of_js_source - |> lexer_from_string - |> parse + file |> Format.read_js |> Format.string_of_js_source |> lexer_from_string |> parse let channel_to_string c_in = let good_round_number = 1024 in @@ -97,9 +108,15 @@ let exec_to_string_exn ~cmd = let open Unix in function | WEXITED 0 -> () - | WEXITED i -> print_endline std_out; failwith (Stdlib.Format.sprintf "process exited with error code %d" i) - | WSIGNALED i -> print_endline std_out; failwith (Stdlib.Format.sprintf "process signaled with signal number %d" i) - | WSTOPPED i -> print_endline std_out; failwith (Stdlib.Format.sprintf "process stopped with signal number %d" i) + | WEXITED i -> + print_endline std_out; + failwith (Stdlib.Format.sprintf "process exited with error code %d" i) + | WSIGNALED i -> + print_endline std_out; + failwith (Stdlib.Format.sprintf "process signaled with signal number %d" i) + | WSTOPPED i -> + print_endline std_out; + failwith (Stdlib.Format.sprintf "process stopped with signal number %d" i) in let proc_in = Unix.open_process_in cmd in let results = channel_to_string proc_in in @@ -113,37 +130,45 @@ let compile_to_javascript ~pretty file = let out_file = Filename.temp_file "jsoo_test" ".js" in let extra_args = if pretty then "--pretty" else "" in let cmd = - (Stdlib.Format.sprintf "../js_of_ocaml.exe %s %s -o %s" extra_args file out_file) in + Stdlib.Format.sprintf "../js_of_ocaml.exe %s %s -o %s" extra_args file out_file + in let stdout = exec_to_string_exn ~cmd in print_string stdout; (* this print shouldn't do anything, so if something weird happens, we'll get the results here *) Format.js_file_of_path out_file -let compile_bc_to_javascript ?(pretty=true) file = - Format.path_of_bc_file file - |> compile_to_javascript ~pretty +let compile_bc_to_javascript ?(pretty = true) file = + Format.path_of_bc_file file |> compile_to_javascript ~pretty -let compile_cmo_to_javascript ?(pretty=true) file = - Format.path_of_cmo_file file - |> compile_to_javascript ~pretty +let compile_cmo_to_javascript ?(pretty = true) file = + Format.path_of_cmo_file file |> compile_to_javascript ~pretty let compile_ocaml_to_cmo file = let out_file = Filename.temp_file "jsoo_test" ".cmo" in - let _ = exec_to_string_exn ~cmd:( - Stdlib.Format.sprintf "ocamlfind ocamlc -c -g %s -o %s" (Format.path_of_ocaml_file file) - out_file) in + let _ = + exec_to_string_exn + ~cmd: + (Stdlib.Format.sprintf + "ocamlfind ocamlc -c -g %s -o %s" + (Format.path_of_ocaml_file file) + out_file) + in Format.cmo_file_of_path out_file let compile_ocaml_to_bc file = let out_file = Filename.temp_file "jsoo_test" ".bc" in - let _ = exec_to_string_exn ~cmd:( - Stdlib.Format.sprintf "ocamlfind ocamlc -g -linkpkg -package unix %s -o %s" (Format.path_of_ocaml_file file) - out_file) in + let _ = + exec_to_string_exn + ~cmd: + (Stdlib.Format.sprintf + "ocamlfind ocamlc -g -linkpkg -package unix %s -o %s" + (Format.path_of_ocaml_file file) + out_file) + in Format.bc_file_of_path out_file type find_result = - { expressions : Jsoo.Javascript.expression list ; statements : Jsoo.Javascript.statement list ; var_decls : Jsoo.Javascript.variable_declaration list } diff --git a/compiler/tests/util/util.mli b/compiler/tests/util/util.mli index c002bdf49c..0f5ef773ae 100644 --- a/compiler/tests/util/util.mli +++ b/compiler/tests/util/util.mli @@ -19,14 +19,19 @@ open Js_of_ocaml_compiler -module Format: Format_intf.S +module Format : Format_intf.S val parse_js : Format.js_file -> Javascript.program + val compile_ocaml_to_cmo : Format.ocaml_file -> Format.cmo_file + val compile_ocaml_to_bc : Format.ocaml_file -> Format.bc_file + val compile_cmo_to_javascript : ?pretty:bool -> Format.cmo_file -> Format.js_file + val compile_bc_to_javascript : ?pretty:bool -> Format.bc_file -> Format.js_file -val run_javascript: Format.js_file -> string + +val run_javascript : Format.js_file -> string type find_result = { expressions : Javascript.expression list diff --git a/compiler/tests/variable_declaration_output.ml b/compiler/tests/variable_declaration_output.ml index 35592e6ec6..fb36926612 100644 --- a/compiler/tests/variable_declaration_output.ml +++ b/compiler/tests/variable_declaration_output.ml @@ -27,9 +27,9 @@ let%expect_test _ = |> Util.compile_ocaml_to_cmo |> Util.compile_cmo_to_javascript ~pretty:true |> Util.parse_js - in - - let program = compile + in + let program = + compile {| let lr = ref (List.init 2 Obj.repr) let black_box v = lr := (Obj.repr v) :: !lr From 9bba1bc704ba8e4181c88002d3b10572ef25ec2b Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Wed, 24 Apr 2019 13:13:56 +0800 Subject: [PATCH 12/16] _ --- compiler/tests/dune | 4 +++- compiler/tests/{expect_tests => }/macro.ml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) rename compiler/tests/{expect_tests => }/macro.ml (96%) diff --git a/compiler/tests/dune b/compiler/tests/dune index ef4a17a0b1..988fdabe2b 100644 --- a/compiler/tests/dune +++ b/compiler/tests/dune @@ -3,7 +3,9 @@ (libraries js_of_ocaml_compiler unix) (inline_tests (flags -allow-output-patterns) - (deps (file ../js_of_ocaml.exe))) + (deps + (file ../js_of_ocaml.exe) + (file ../../runtime/runtime.js))) (preprocess (pps ppx_expect))) (include_subdirs unqualified) diff --git a/compiler/tests/expect_tests/macro.ml b/compiler/tests/macro.ml similarity index 96% rename from compiler/tests/expect_tests/macro.ml rename to compiler/tests/macro.ml index cac49d9627..eb102eac26 100644 --- a/compiler/tests/expect_tests/macro.ml +++ b/compiler/tests/macro.ml @@ -4,6 +4,7 @@ let print_macro_transformed source = let buffer = Buffer.create (String.length source) in let pp = Jsoo.Pretty_print.to_buffer buffer in Jsoo.Pretty_print.set_compact pp false; + let source = (source |> Util.Format.js_source_of_string|> Util.Format.write_js) in let parsed = Util.parse_js source in let transformed = Jsoo.Macro.f parsed in Jsoo.Js_output.program pp transformed; From 197d86d81198f788da857b5e6d95b0309641f579 Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Thu, 25 Apr 2019 14:56:12 +0800 Subject: [PATCH 13/16] fixup weird merge issues --- compiler/tests/end_to_end.ml | 32 ++++++++++++++++++++ compiler/tests/match_with_exn.ml | 48 ++++++++++++++++++++++++++++++ compiler/tests/side_effect.ml | 51 ++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 compiler/tests/end_to_end.ml create mode 100644 compiler/tests/match_with_exn.ml create mode 100644 compiler/tests/side_effect.ml diff --git a/compiler/tests/end_to_end.ml b/compiler/tests/end_to_end.ml new file mode 100644 index 0000000000..b7bf703757 --- /dev/null +++ b/compiler/tests/end_to_end.ml @@ -0,0 +1,32 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +open Util + +let%expect_test _ = + {| console.log("hello world") |} + |> Filetype.js_text_of_string + |> Filetype.write_js + |> run_javascript + |> print_endline; + [%expect {| hello world |}] + +let%expect_test _ = + compile_and_run {| print_endline "hello world" |}; + [%expect {| hello world |}] diff --git a/compiler/tests/match_with_exn.ml b/compiler/tests/match_with_exn.ml new file mode 100644 index 0000000000..cd09b8c6e8 --- /dev/null +++ b/compiler/tests/match_with_exn.ml @@ -0,0 +1,48 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +(* https://github.com/ocsigen/js_of_ocaml/issues/400 *) +(* https://github.com/ocsigen/js_of_ocaml/pull/402 *) + +let%expect_test _ = + Util.compile_and_run + {| + exception A + exception B of int + + let a_exn () = raise A + + (* Make sure that [a] doesn't look constant *) + let a () = if Random.int 1 + 1 = 0 then 2 else 4 + + let b_exn () = raise (B 2) + + (* https://github.com/ocsigen/js_of_ocaml/issues/400 + * match .. with exception is no compiled properly *) + let () = + assert ( + try + match a () with + | exception (A | B _) -> true + | _n -> b_exn () + with B _ -> true); + print_endline "Success!" +|}; + [%expect "Success!"] diff --git a/compiler/tests/side_effect.ml b/compiler/tests/side_effect.ml new file mode 100644 index 0000000000..3424898ecc --- /dev/null +++ b/compiler/tests/side_effect.ml @@ -0,0 +1,51 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2017 Hugo Heuzard + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + +(* https://github.com/ocsigen/js_of_ocaml/issues/177 *) +(* https://github.com/ocsigen/js_of_ocaml/pull/178 *) + +let%expect_test _ = + Util.compile_and_run + {| + let i = ref 0 + let log_success () = print_endline "Success!" + let log_failure = Printf.printf "Failure! %s" + + let side_effect yes label = + if yes + then ( + Printf.printf "Side effect: %s\n%!" label; + incr i); + 0 + + let _ = side_effect false "this is only to avoid inlining" + + let f = + match side_effect true "Should only see this once" with + | 0 | 1 | 2 -> Printf.printf "Please don't optimize this away\n%!" + | _ -> Printf.printf "Or this\n%!" + + let _ = if !i = 1 then log_success () else log_failure "side effect computed twice" + |}; + [%expect + {| + Side effect: Should only see this once + Please don't optimize this away + Success! |}] From 7b0c1cbd4ca64c3066595af71487ad6de3c694bd Mon Sep 17 00:00:00 2001 From: Ty Overby Date: Thu, 25 Apr 2019 15:02:33 +0800 Subject: [PATCH 14/16] _ --- compiler/tests/util/format_intf.ml | 45 ------------------------------ 1 file changed, 45 deletions(-) delete mode 100644 compiler/tests/util/format_intf.ml diff --git a/compiler/tests/util/format_intf.ml b/compiler/tests/util/format_intf.ml deleted file mode 100644 index 5379227103..0000000000 --- a/compiler/tests/util/format_intf.ml +++ /dev/null @@ -1,45 +0,0 @@ -module type S = sig - type ocaml_source - - type js_source - - type ocaml_file - - type js_file - - type cmo_file - - type bc_file - - val read_js : js_file -> js_source - - val read_ocaml : ocaml_file -> ocaml_source - - val write_js : js_source -> js_file - - val write_ocaml : ocaml_source -> ocaml_file - - val js_source_of_string : string -> js_source - - val ocaml_source_of_string : string -> ocaml_source - - val string_of_js_source : js_source -> string - - val string_of_ocaml_source : ocaml_source -> string - - val path_of_ocaml_file : ocaml_file -> string - - val path_of_js_file : js_file -> string - - val path_of_cmo_file : cmo_file -> string - - val path_of_bc_file : bc_file -> string - - val ocaml_file_of_path : string -> ocaml_file - - val js_file_of_path : string -> js_file - - val cmo_file_of_path : string -> cmo_file - - val bc_file_of_path : string -> bc_file -end From 1ad8262b53227b22e9f02bd0fb8782f29ba6fcc6 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Thu, 25 Apr 2019 15:16:48 +0800 Subject: [PATCH 15/16] cleanup --- compiler/js_of_ocaml.ml | 2 +- compiler/lib/linker.ml | 8 +++--- compiler/lib/linker.mli | 3 +-- compiler/lib/macro.ml | 57 +++++++++++++++++++---------------------- compiler/tests/macro.ml | 2 +- 5 files changed, 33 insertions(+), 39 deletions(-) diff --git a/compiler/js_of_ocaml.ml b/compiler/js_of_ocaml.ml index 373f8a28c5..331e992ebc 100644 --- a/compiler/js_of_ocaml.ml +++ b/compiler/js_of_ocaml.ml @@ -122,7 +122,7 @@ let f `Keep with Not_found -> `Skip) in - Linker.load_files runtime_files ~runtime_transform:Macro.f; + Linker.load_files runtime_files; let paths = try List.append include_dir [Findlib.find_pkg_dir "stdlib"] with Not_found -> include_dir diff --git a/compiler/lib/linker.ml b/compiler/lib/linker.ml index 6bb618d032..850c7c289c 100644 --- a/compiler/lib/linker.ml +++ b/compiler/lib/linker.ml @@ -281,7 +281,7 @@ let find_named_value code = ignore (p#program code); !all -let add_file f ~runtime_transform = +let add_file f = List.iter (parse_file f) ~f:(fun {provides; requires; version_constraint; weakdef; code} -> @@ -297,7 +297,7 @@ let add_file f ~runtime_transform = match provides with | None -> always_included := {filename = f; program = code} :: !always_included | Some (pi, name, kind, ka) -> - let code = runtime_transform code in + let code = Macro.f code in let module J = Javascript in let rec find = function | [] -> None @@ -353,8 +353,8 @@ let check_deps () = ()) code_pieces -let load_files l ~runtime_transform = - List.iter l ~f:(add_file ~runtime_transform); +let load_files l = + List.iter l ~f:add_file; check_deps () (* resolve *) diff --git a/compiler/lib/linker.mli b/compiler/lib/linker.mli index 2c8cb66ce8..a81cd26676 100644 --- a/compiler/lib/linker.mli +++ b/compiler/lib/linker.mli @@ -31,8 +31,7 @@ type fragment = val parse_file : string -> fragment list -val load_files : - string list -> runtime_transform:(Javascript.program -> Javascript.program) -> unit +val load_files : string list -> unit type state diff --git a/compiler/lib/macro.ml b/compiler/lib/macro.ml index 41ac4421ef..6f42bd7160 100644 --- a/compiler/lib/macro.ml +++ b/compiler/lib/macro.ml @@ -1,31 +1,6 @@ open Stdlib -let macro recurse fallthrough = - let module J = Javascript in - let zero, one = J.ENum "0", J.ENum "1" in - function - | "BLOCK", tag :: args when List.length args > 0 -> - let tag = Some tag in - let args = List.map ~f:(fun a -> Some (recurse a)) args in - J.EArr (tag :: args) - | "TAG", [e] -> J.EAccess (recurse e, zero) - | "LENGTH", [e] -> - let underlying = J.EDot (recurse e, "length") in - J.EBin (J.Minus, underlying, one) - | "FIELD", [e; J.ENum n] -> - let idx = int_of_string n in - let adjusted = J.ENum (string_of_int (idx + 1)) in - J.EAccess (recurse e, adjusted) - | "FIELD", [_; J.EUn (J.Neg, _)] -> failwith "Negative field indexes are not allowed" - | "FIELD", [e; idx] -> - let adjusted = J.EBin (J.Plus, one, recurse idx) in - J.EAccess (recurse e, adjusted) - | "ISBLOCK", [e] -> - J.EBin (J.NotEqEq, J.EUn (J.Typeof, recurse e), J.EStr ("number", `Utf8)) - | ("BLOCK", _ | "TAG", _ | "LENGTH", _ | "FIELD", _ | "ISBLOCK", _) as s -> - let s, _ = s in - failwith (Format.sprintf "macro %s called with inappropriate arguments" s) - | _ -> fallthrough () +let zero, one = Javascript.ENum "0", Javascript.ENum "1" class macro_mapper = object (m) @@ -33,12 +8,32 @@ class macro_mapper = method expression x = let module J = Javascript in - let fallthrough () = super#expression x in - let recurse = m#expression in match x with - | J.ECall (J.EVar (J.S {name; _}), args, _) -> - macro recurse fallthrough (name, args) - | _ -> fallthrough () + | J.ECall (J.EVar (J.S {name; _}), args, _) -> ( + match name, args with + | "BLOCK", tag :: (_ :: _ as args) -> + let tag = Some tag in + let args = List.map ~f:(fun a -> Some (m#expression a)) args in + J.EArr (tag :: args) + | "TAG", [e] -> J.EAccess (m#expression e, zero) + | "LENGTH", [e] -> + let underlying = J.EDot (m#expression e, "length") in + J.EBin (J.Minus, underlying, one) + | "FIELD", [e; J.ENum n] -> + let idx = int_of_string n in + let adjusted = J.ENum (string_of_int (idx + 1)) in + J.EAccess (m#expression e, adjusted) + | "FIELD", [_; J.EUn (J.Neg, _)] -> + failwith "Negative field indexes are not allowed" + | "FIELD", [e; idx] -> + let adjusted = J.EBin (J.Plus, one, m#expression idx) in + J.EAccess (m#expression e, adjusted) + | "ISBLOCK", [e] -> + J.EBin (J.NotEqEq, J.EUn (J.Typeof, m#expression e), J.EStr ("number", `Utf8)) + | ("BLOCK" | "TAG" | "LENGTH" | "FIELD" | "ISBLOCK"), _ -> + failwith (Format.sprintf "macro %s called with inappropriate arguments" name) + | _ -> super#expression x) + | _ -> super#expression x end let f js = diff --git a/compiler/tests/macro.ml b/compiler/tests/macro.ml index 56f289d1ff..d6a6aa6129 100644 --- a/compiler/tests/macro.ml +++ b/compiler/tests/macro.ml @@ -4,7 +4,7 @@ let print_macro_transformed source = let buffer = Buffer.create (String.length source) in let pp = Jsoo.Pretty_print.to_buffer buffer in Jsoo.Pretty_print.set_compact pp false; - let source = (source |> Util.Filetype.js_text_of_string|> Util.Filetype.write_js) in + let source = source |> Util.Filetype.js_text_of_string |> Util.Filetype.write_js in let parsed = Util.parse_js source in let transformed = Jsoo.Macro.f parsed in Jsoo.Js_output.program pp transformed; From 2e9f891c283f1f24ffcd6b0773bf348630f69cdf Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Sat, 27 Apr 2019 20:52:44 +0800 Subject: [PATCH 16/16] tune --- compiler/lib/macro.ml | 46 +++++++++++++++++++++++++---------------- compiler/tests/macro.ml | 31 +++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/compiler/lib/macro.ml b/compiler/lib/macro.ml index 6f42bd7160..29de3d3c16 100644 --- a/compiler/lib/macro.ml +++ b/compiler/lib/macro.ml @@ -1,6 +1,23 @@ -open Stdlib +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2019 Ty Overby, Jane Street Group LLC + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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 zero, one = Javascript.ENum "0", Javascript.ENum "1" +open Stdlib class macro_mapper = object (m) @@ -11,25 +28,18 @@ class macro_mapper = match x with | J.ECall (J.EVar (J.S {name; _}), args, _) -> ( match name, args with - | "BLOCK", tag :: (_ :: _ as args) -> - let tag = Some tag in - let args = List.map ~f:(fun a -> Some (m#expression a)) args in - J.EArr (tag :: args) - | "TAG", [e] -> J.EAccess (m#expression e, zero) - | "LENGTH", [e] -> - let underlying = J.EDot (m#expression e, "length") in - J.EBin (J.Minus, underlying, one) + | "BLOCK", J.ENum tag :: (_ :: _ as args) -> + let tag = Int32.to_int (J.Num.to_int32 tag) in + let args = List.map args ~f:m#expression in + Mlvalue.Block.make ~tag ~args + | "TAG", [e] -> Mlvalue.Block.tag (m#expression e) + | "LENGTH", [e] -> Mlvalue.Array.length (m#expression e) | "FIELD", [e; J.ENum n] -> - let idx = int_of_string n in - let adjusted = J.ENum (string_of_int (idx + 1)) in - J.EAccess (m#expression e, adjusted) + let idx = Int32.to_int (J.Num.to_int32 n) in + Mlvalue.Block.field (m#expression e) idx | "FIELD", [_; J.EUn (J.Neg, _)] -> failwith "Negative field indexes are not allowed" - | "FIELD", [e; idx] -> - let adjusted = J.EBin (J.Plus, one, m#expression idx) in - J.EAccess (m#expression e, adjusted) - | "ISBLOCK", [e] -> - J.EBin (J.NotEqEq, J.EUn (J.Typeof, m#expression e), J.EStr ("number", `Utf8)) + | "ISBLOCK", [e] -> Mlvalue.is_block (m#expression e) | ("BLOCK" | "TAG" | "LENGTH" | "FIELD" | "ISBLOCK"), _ -> failwith (Format.sprintf "macro %s called with inappropriate arguments" name) | _ -> super#expression x) diff --git a/compiler/tests/macro.ml b/compiler/tests/macro.ml index d6a6aa6129..5ea117a242 100644 --- a/compiler/tests/macro.ml +++ b/compiler/tests/macro.ml @@ -1,3 +1,22 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2019 Ty Overby + * + * 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, with linking exception; + * either version 2.1 of the License, or (at your option) any 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. +*) + module Jsoo = Js_of_ocaml_compiler let print_macro_transformed source = @@ -49,6 +68,14 @@ let%expect_test "BLOCK(1, a, b, c)" = print_macro_transformed "BLOCK(1, a, b, c)"; [%expect {| [1,a,b,c]; |}] +let%expect_test "BLOCK(077, a)" = + print_macro_transformed "BLOCK(077, a)"; + [%expect {| [63,a]; |}] + +let%expect_test "BLOCK(0779, a)" = + print_macro_transformed "BLOCK(0779, a)"; + [%expect {| [779,a]; |}] + let%expect_test "TAG(a)" = print_macro_transformed "TAG(a)"; [%expect {| a[0]; |}] @@ -63,11 +90,11 @@ let%expect_test "FIELD(a)" = let%expect_test "FIELD(a, b)" = print_macro_transformed "FIELD(a, b)"; - [%expect {| a[1 + b]; |}] + [%expect {| failure: macro FIELD called with inappropriate arguments |}] let%expect_test "FIELD(a, b << 5)" = print_macro_transformed "FIELD(a, b << 5)"; - [%expect {| a[1 + (b << 5)]; |}] + [%expect {| failure: macro FIELD called with inappropriate arguments |}] let%expect_test "FIELD(a, 0)" = print_macro_transformed "FIELD(a, 0)";