diff --git a/bin/js/dune b/bin/js/dune new file mode 100644 index 0000000..8a81576 --- /dev/null +++ b/bin/js/dune @@ -0,0 +1,6 @@ +(executable + (name main) + (modes js) + (preprocess + (pps ppx_jane js_of_ocaml-ppx)) + (libraries react_trace base logs logs.fmt fmt fmt.tty js_of_ocaml)) diff --git a/bin/js/main.ml b/bin/js/main.ml new file mode 100644 index 0000000..6856bd6 --- /dev/null +++ b/bin/js/main.ml @@ -0,0 +1,39 @@ +open! Core +open React_trace + +let position (lexbuf : Lexing.lexbuf) : string = + let open Lexing in + let pos = lexbuf.lex_curr_p in + sprintf "%s:%d:%d" pos.pos_fname pos.pos_lnum (pos.pos_cnum - pos.pos_bol + 1) + +let parse_with_error (lexbuf : Lexing.lexbuf) : Syntax.Prog.t = + Parser.prog Lexer.read lexbuf + +let parse_program_str (program_str : string) : (Syntax.Prog.t, string) result = + let lexbuf = Lexing.from_string program_str in + match parse_with_error lexbuf with + | prog -> Ok prog + | exception Parser.Error -> + Error (sprintf "%s: syntax error" (position lexbuf)) + +let () = + Fmt_tty.setup_std_outputs (); + Logs.set_reporter (Logs_fmt.reporter ()); + Logs.set_level (Some Logs.Info); + + let open Js_of_ocaml in + Js.export_all + (object%js + method run (fuel : int) program_str = + (let open Result.Let_syntax in + let%bind prog = parse_program_str program_str in + let Interp.{ recording; _ } = + Interp.run + ?fuel:(if fuel < 1 then None else Some fuel) + ~recorder:(module Recorder) + prog + in + if Logs.err_count () > 0 then Error "error" else Ok recording) + |> (function Ok s -> s | Error s -> s) + |> Js.string + end) diff --git a/bin/js/recorder.ml b/bin/js/recorder.ml new file mode 100644 index 0000000..72f930c --- /dev/null +++ b/bin/js/recorder.ml @@ -0,0 +1,39 @@ +open Stdlib.Effect +open Stdlib.Effect.Deep +open React_trace +include Recorder_intf + +(* TODO: Replace the dummy string with an actual recording type *) +type recording = string + +let emp_recording = "empty recording" + +let event_h = + { + retc = (fun v ~recording -> (v, recording)); + exnc = raise; + effc = + (fun (type a) (eff : a t) -> + match eff with + | Evt_update_st (path, label, (v, q)) -> + Some + (fun (k : (a, _) continuation) ~(recording : recording) -> + ignore (path, label, v, q); + continue k () ~recording) + | Evt_set_dec (path, dec) -> + Some + (fun (k : (a, _) continuation) ~(recording : recording) -> + ignore (path, dec); + continue k () ~recording) + | Evt_enq_eff (path, clos) -> + Some + (fun (k : (a, _) continuation) ~(recording : recording) -> + ignore (path, clos); + continue k () ~recording) + | Evt_alloc_pt path -> + Some + (fun (k : (a, _) continuation) ~(recording : recording) -> + ignore path; + continue k () ~recording) + | _ -> None); + } diff --git a/bin/js/recorder.mli b/bin/js/recorder.mli new file mode 100644 index 0000000..fd9acfd --- /dev/null +++ b/bin/js/recorder.mli @@ -0,0 +1 @@ +include React_trace.Recorder_intf.Intf with type recording = string diff --git a/bin/dune b/bin/native/dune similarity index 89% rename from bin/dune rename to bin/native/dune index 59f7311..673a664 100644 --- a/bin/dune +++ b/bin/native/dune @@ -1,7 +1,6 @@ (executable (public_name react_trace) (name main) - (modes exe js) (preprocess (pps ppx_jane)) (libraries react_trace base logs logs.fmt fmt fmt.tty)) diff --git a/bin/main.ml b/bin/native/main.ml similarity index 95% rename from bin/main.ml rename to bin/native/main.ml index 2ec9158..718a4f6 100644 --- a/bin/main.ml +++ b/bin/native/main.ml @@ -74,7 +74,9 @@ let () = Sexp.pp_hum Stdlib.Format.std_formatter (Syntax.Prog.sexp_of_t prog) else let { Interp.steps; _ } = - Interp.run ?fuel:!opt_fuel ~report:!opt_report prog + Interp.run ?fuel:!opt_fuel ~report:!opt_report + ~recorder:(module Default_recorder) + prog in printf "\nSteps: %d\n" steps; Stdlib.exit (if Logs.err_count () > 0 then 1 else 0)) diff --git a/dune-project b/dune-project index b50717b..06e0856 100644 --- a/dune-project +++ b/dune-project @@ -27,7 +27,8 @@ (ocaml-base-compiler (= 5.2.0)) core - js_of_ocaml-compiler + js_of_ocaml + js_of_ocaml-ppx flow_parser fmt logs diff --git a/lib/default_recorder.ml b/lib/default_recorder.ml new file mode 100644 index 0000000..2a81a11 --- /dev/null +++ b/lib/default_recorder.ml @@ -0,0 +1,37 @@ +open Stdlib.Effect +open Stdlib.Effect.Deep +include Recorder_intf + +type recording = unit + +let emp_recording = () + +let event_h = + { + retc = (fun v ~recording -> (v, recording)); + exnc = raise; + effc = + (fun (type a) (eff : a t) -> + match eff with + | Evt_update_st (path, label, (v, q)) -> + Some + (fun (k : (a, _) continuation) ~(recording : recording) -> + ignore (path, label, v, q); + continue k () ~recording) + | Evt_set_dec (path, dec) -> + Some + (fun (k : (a, _) continuation) ~(recording : recording) -> + ignore (path, dec); + continue k () ~recording) + | Evt_enq_eff (path, clos) -> + Some + (fun (k : (a, _) continuation) ~(recording : recording) -> + ignore (path, clos); + continue k () ~recording) + | Evt_alloc_pt path -> + Some + (fun (k : (a, _) continuation) ~(recording : recording) -> + ignore path; + continue k () ~recording) + | _ -> None); + } diff --git a/lib/default_recorder.mli b/lib/default_recorder.mli new file mode 100644 index 0000000..5352f46 --- /dev/null +++ b/lib/default_recorder.mli @@ -0,0 +1 @@ +include Recorder_intf.Intf diff --git a/lib/interp.ml b/lib/interp.ml index f3007f3..2027d82 100644 --- a/lib/interp.ml +++ b/lib/interp.ml @@ -572,10 +572,16 @@ let step_path (path : Path.t) : bool = has_updates -type run_info = { steps : int; mem : Memory.t; treemem : Tree_mem.t } - -let run ?(fuel : int option) ?(report : bool = false) (prog : Prog.t) : run_info - = +type 'recording run_info = { + steps : int; + mem : Memory.t; + treemem : Tree_mem.t; + recording : 'recording; +} + +let run (type recording) ?(fuel : int option) ?(report : bool = false) + ~(recorder : (module Recorder_intf.Intf with type recording = recording)) + (prog : Prog.t) : recording run_info = Logger.run prog; let driver () = @@ -592,9 +598,15 @@ let run ?(fuel : int option) ?(report : bool = false) (prog : Prog.t) : run_info loop (); !cnt in + + let driver () = + let open (val recorder) in + match_with driver () event_h ~recording:emp_recording + in (* TODO: Integrate Report_box with (WIP) Recorder API *) let driver () = try_with driver () (Report_box.log_h report) in + let driver () = match_with driver () treemem_h ~treemem:Tree_mem.empty in let driver () = match_with driver () mem_h ~mem:Memory.empty in - let (steps, treemem), mem = driver () in - { steps; mem; treemem } + let ((steps, recording), treemem), mem = driver () in + { steps; mem; treemem; recording } diff --git a/lib/recorder.ml b/lib/recorder.ml deleted file mode 100644 index d583917..0000000 --- a/lib/recorder.ml +++ /dev/null @@ -1,22 +0,0 @@ -open! Core -open Syntax -open Concrete_domains -(* open Interp_effects *) - -type event = - | Evt_update_st of (Path.t * Label.t * (value * Job_q.t)) - | Evt_set_dec of (Path.t * decision) - | Evt_enq_eff of (Path.t * clos) - | Evt_alloc_pt of Path.t - -(** TODO: *) -let record = function - | Evt_update_st (path, label, (v, q)) -> ignore (path, label, v, q) - | Evt_set_dec (path, dec) -> ignore (path, dec) - | Evt_enq_eff (path, clos) -> ignore (path, clos) - | Evt_alloc_pt path -> ignore path - -type diagnostics -(** TODO *) - -let diagnostics = ref (failwith "not implemented") diff --git a/lib/recorder.mli b/lib/recorder.mli deleted file mode 100644 index 763e940..0000000 --- a/lib/recorder.mli +++ /dev/null @@ -1,15 +0,0 @@ -open! Core -open Syntax -open Concrete_domains - -type event = - | Evt_update_st of (Path.t * Label.t * (value * Job_q.t)) - | Evt_set_dec of (Path.t * decision) - | Evt_enq_eff of (Path.t * clos) - | Evt_alloc_pt of Path.t - -val record : event -> unit - -type diagnostics - -val diagnostics : diagnostics ref diff --git a/lib/recorder_intf.ml b/lib/recorder_intf.ml new file mode 100644 index 0000000..538ae84 --- /dev/null +++ b/lib/recorder_intf.ml @@ -0,0 +1,18 @@ +open! Core +open Stdlib.Effect +open Stdlib.Effect.Deep +open Syntax +open Concrete_domains + +type _ Stdlib.Effect.t += + | Evt_update_st : (Path.t * Label.t * (value * Job_q.t)) -> unit t + | Evt_set_dec : (Path.t * decision) -> unit t + | Evt_enq_eff : (Path.t * clos) -> unit t + | Evt_alloc_pt : Path.t -> unit t + +module type Intf = sig + type recording + + val emp_recording : recording + val event_h : 'a. ('a, recording:recording -> 'a * recording) handler +end diff --git a/react_trace.opam b/react_trace.opam index ad117f2..fa7123e 100644 --- a/react_trace.opam +++ b/react_trace.opam @@ -13,7 +13,8 @@ depends: [ "dune" {>= "3.15"} "ocaml-base-compiler" {= "5.2.0"} "core" - "js_of_ocaml-compiler" + "js_of_ocaml" + "js_of_ocaml-ppx" "flow_parser" "fmt" "logs" diff --git a/test/test_react_trace.ml b/test/test_react_trace.ml index 0f044b1..1cd099d 100644 --- a/test/test_react_trace.ml +++ b/test/test_react_trace.ml @@ -4,6 +4,12 @@ open React_trace let fuel = 100 +module Interp = struct + include Interp + + let run = Interp.run ~recorder:(module Default_recorder) +end + let parse_prog s = let lexbuf = Lexing.from_string s in Parser.prog Lexer.read lexbuf