diff --git a/.envrc b/.envrc deleted file mode 100644 index 1e71ffbc6..000000000 --- a/.envrc +++ /dev/null @@ -1,4 +0,0 @@ -# shellcheck shell=bash -# For use with direnv. -# Installing nix-direnv will ensure a smoother experience. -use flake \ No newline at end of file diff --git a/compiler/catala_utils/cli.ml b/compiler/catala_utils/cli.ml index 92762f5cc..a996761cf 100644 --- a/compiler/catala_utils/cli.ml +++ b/compiler/catala_utils/cli.ml @@ -26,7 +26,8 @@ let language_code = let rl = List.map (fun (a, b) -> b, a) languages in fun l -> List.assoc l rl -let message_format_opt = ["human", Human; "gnu", GNU] +let message_format_opt = ["human", (Human : message_format_enum); "gnu", GNU] +let trace_format_opt = ["human", (Human : trace_format_enum); "json", JSON] open Cmdliner @@ -146,13 +147,41 @@ module Flags = struct standards." let trace = + let converter = + conv ~docv:"FILE" + ( (fun s -> + if s = "-" then Ok `Stdout + else if + Filename.extension s |> String.starts_with ~prefix:".catala" + then + Error (`Msg "Output trace file cannot have a .catala extension") + else Ok (`FileName (Global.raw_file s))), + fun ppf -> function + | `Stdout -> Format.pp_print_string ppf "-" + | `FileName f -> Format.pp_print_string ppf (f :> string) ) + in value - & flag - & info ["trace"; "t"] + & opt (some converter) None ~vopt:(Some `Stdout) + & info ["trace"; "t"] ~docv:"FILE" ~env:(Cmd.Env.info "CATALA_TRACE") ~doc: "Displays a trace of the interpreter's computation or generates \ - logging instructions in translate programs." + logging instructions in translate programs. If set as a flag, \ + outputs\n\ + \ trace to stdout. If $(docv) is defined, outputs the \ + trace to a file while interpreting.\n\ + \ Defining a filename does not affect code generation. \ + Cannot use .catala extension." + + let trace_format = + value + & opt (some (enum trace_format_opt)) None + & info ["trace-format"] + ~doc: + "Selects the format of trace logs emitted by the interpreter. If \ + set to $(i,human), the messages will be nicely displayed and \ + meant to be read by a human. If set to $(i, json), the messages \ + will be emitted as a JSON structured object." let plugins_dirs = let doc = "Set the given directory to be searched for backend plugins." in @@ -223,6 +252,7 @@ module Flags = struct color message_format trace + trace_format plugins_dirs disable_warnings max_prec_digits @@ -239,11 +269,34 @@ module Flags = struct | "-" -> "-" | f -> File.reverse_path ~to_dir f) in + let trace, trace_format = + match trace, trace_format with + | None, _ -> None, trace_format + | Some `Stdout, _ -> Some (lazy (Message.std_ppf ())), trace_format + | Some (`FileName f), Some _ -> + ( Some + (lazy + (Message.formatter_of_out_channel + (open_out (path_rewrite f)) + ())), + trace_format ) + | Some (`FileName f), None -> + let trace_format = + if Filename.extension (f :> file) = ".json" then JSON else Human + in + ( Some + (lazy + (Message.formatter_of_out_channel + (open_out (path_rewrite f)) + ())), + Some trace_format ) + in + let trace_format = Option.value trace_format ~default:Human in (* This sets some global refs for convenience, but most importantly returns the options record. *) Global.enforce_options ~language ~debug ~color ~message_format ~trace - ~plugins_dirs ~disable_warnings ~max_prec_digits ~path_rewrite - ~stop_on_error ~no_fail_on_assert () + ~trace_format ~plugins_dirs ~disable_warnings ~max_prec_digits + ~path_rewrite ~stop_on_error ~no_fail_on_assert () in Term.( const make @@ -252,6 +305,7 @@ module Flags = struct $ color $ message_format $ trace + $ trace_format $ plugins_dirs $ disable_warnings $ max_prec_digits diff --git a/compiler/catala_utils/global.ml b/compiler/catala_utils/global.ml index 104e8357d..795fb2176 100644 --- a/compiler/catala_utils/global.ml +++ b/compiler/catala_utils/global.ml @@ -19,6 +19,7 @@ type raw_file = file type backend_lang = En | Fr | Pl type when_enum = Auto | Always | Never type message_format_enum = Human | GNU | Lsp +type trace_format_enum = Human | JSON type 'file input_src = | FileName of 'file @@ -32,7 +33,8 @@ type options = { mutable debug : bool; mutable color : when_enum; mutable message_format : message_format_enum; - mutable trace : bool; + mutable trace : Format.formatter Lazy.t option; + mutable trace_format : trace_format_enum; mutable plugins_dirs : file list; mutable disable_warnings : bool; mutable max_prec_digits : int; @@ -53,7 +55,8 @@ let options = debug = false; color = Auto; message_format = Human; - trace = false; + trace = None; + trace_format = Human; plugins_dirs = []; disable_warnings = false; max_prec_digits = 20; @@ -69,6 +72,7 @@ let enforce_options ?color ?message_format ?trace + ?trace_format ?plugins_dirs ?disable_warnings ?max_prec_digits @@ -82,6 +86,7 @@ let enforce_options Option.iter (fun x -> options.color <- x) color; Option.iter (fun x -> options.message_format <- x) message_format; Option.iter (fun x -> options.trace <- x) trace; + Option.iter (fun x -> options.trace_format <- x) trace_format; Option.iter (fun x -> options.plugins_dirs <- x) plugins_dirs; Option.iter (fun x -> options.disable_warnings <- x) disable_warnings; Option.iter (fun x -> options.max_prec_digits <- x) max_prec_digits; diff --git a/compiler/catala_utils/global.mli b/compiler/catala_utils/global.mli index 2502beedf..7edd22bb0 100644 --- a/compiler/catala_utils/global.mli +++ b/compiler/catala_utils/global.mli @@ -32,6 +32,9 @@ type when_enum = Auto | Always | Never (** Format of error and warning messages output by the compiler. *) type message_format_enum = Human | GNU | Lsp +(** Format of trace logs *) +type trace_format_enum = Human | JSON + (** Sources for program input *) type 'file input_src = | FileName of 'file (** A file path to read from disk *) @@ -50,7 +53,8 @@ type options = private { mutable debug : bool; mutable color : when_enum; mutable message_format : message_format_enum; - mutable trace : bool; + mutable trace : Format.formatter Lazy.t option; + mutable trace_format : trace_format_enum; mutable plugins_dirs : file list; mutable disable_warnings : bool; mutable max_prec_digits : int; @@ -72,7 +76,8 @@ val enforce_options : ?debug:bool -> ?color:when_enum -> ?message_format:message_format_enum -> - ?trace:bool -> + ?trace:Format.formatter Lazy.t option -> + ?trace_format:trace_format_enum -> ?plugins_dirs:file list -> ?disable_warnings:bool -> ?max_prec_digits:int -> diff --git a/compiler/catala_utils/hash.ml b/compiler/catala_utils/hash.ml index 59fd8f359..61260e387 100644 --- a/compiler/catala_utils/hash.ml +++ b/compiler/catala_utils/hash.ml @@ -49,7 +49,7 @@ end = struct % !(monomorphize_types : bool) % (* The following may not affect the call convention, but we want it set in an homogeneous way *) - !(Global.options.trace : bool) + !(Global.options.trace <> None: bool) % !(Global.options.max_prec_digits : int) |> k diff --git a/compiler/catala_utils/message.ml b/compiler/catala_utils/message.ml index e7b00ccdf..e2c8ec9ae 100644 --- a/compiler/catala_utils/message.ml +++ b/compiler/catala_utils/message.ml @@ -66,8 +66,13 @@ let formatter_of_out_channel oc = if Lazy.force tty then Format.pp_set_margin ppf (terminal_columns ()); ppf -let std_ppf = formatter_of_out_channel stdout -let err_ppf = formatter_of_out_channel stderr +let std_ppf = + let ppf = lazy (formatter_of_out_channel stdout ()) in + fun () -> Lazy.force ppf + +let err_ppf = + let ppf = lazy (formatter_of_out_channel stderr ()) in + fun () -> Lazy.force ppf let ignore_ppf = let ppf = lazy (Format.make_formatter (fun _ _ _ -> ()) (fun () -> ())) in diff --git a/compiler/catala_utils/message.mli b/compiler/catala_utils/message.mli index 3a61da557..5bd5eab40 100644 --- a/compiler/catala_utils/message.mli +++ b/compiler/catala_utils/message.mli @@ -93,6 +93,8 @@ val pad : int -> string -> Format.formatter -> unit (* {1 More general color-enabled formatting helpers}*) +val std_ppf : unit -> Format.formatter +val err_ppf : unit -> Format.formatter val formatter_of_out_channel : out_channel -> unit -> Format.formatter (** Creates a new formatter from the given out channel, with correct handling of the ocolor tags. Actual use of escape codes in the output depends on diff --git a/compiler/catala_web_interpreter.ml b/compiler/catala_web_interpreter.ml index fa0f9b738..9e2bae7d7 100644 --- a/compiler/catala_web_interpreter.ml +++ b/compiler/catala_web_interpreter.ml @@ -21,7 +21,7 @@ let () = let options = Global.enforce_options ~input_src:(Contents (contents, "-inline-")) - ~language:(Some language) ~debug:false ~color:Never ~trace () + ~language:(Some language) ~debug:false ~color:Never ~trace: (if trace then Some (lazy Format.std_formatter) else None) () in let prg, _type_order = Passes.dcalc options ~includes:[] ~optimize:false diff --git a/compiler/dcalc/from_scopelang.ml b/compiler/dcalc/from_scopelang.ml index 051539fd2..d3b4c9ca3 100644 --- a/compiler/dcalc/from_scopelang.ml +++ b/compiler/dcalc/from_scopelang.ml @@ -127,7 +127,7 @@ let tag_with_log_entry (markings : Uid.MarkedString.info list) : 'm Ast.expr boxed = let m = mark_tany (Mark.get e) (Expr.pos e) in - if Global.options.trace then + if Global.options.trace <> None then let pos = Expr.pos e in Expr.eappop ~op:(Log (l, markings), pos) ~tys:[TAny, pos] ~args:[e] m else e diff --git a/compiler/lcalc/to_ocaml.ml b/compiler/lcalc/to_ocaml.ml index 87c7de090..aaffbfb55 100644 --- a/compiler/lcalc/to_ocaml.ml +++ b/compiler/lcalc/to_ocaml.ml @@ -340,11 +340,11 @@ let rec format_expr (ctx : decl_ctx) (fmt : Format.formatter) (e : 'm expr) : args = [arg]; _; } - when Global.options.trace -> + when Global.options.trace <> None -> Format.fprintf fmt "(log_begin_call@ %a@ %a)@ %a" format_uid_list info format_with_parens f format_with_parens arg | EAppOp { op = Log (VarDef var_def_info, info), _; args = [arg1]; _ } - when Global.options.trace -> + when Global.options.trace <> None -> Format.fprintf fmt "(log_variable_definition@ %a@ {io_input=%s;@ io_output=%b}@ (%a)@ %a)" format_uid_list info @@ -356,7 +356,7 @@ let rec format_expr (ctx : decl_ctx) (fmt : Format.formatter) (e : 'm expr) : (var_def_info.log_typ, Pos.no_pos) format_with_parens arg1 | EAppOp { op = Log (PosRecordIfTrueBool, _), _; args = [arg1]; _ } - when Global.options.trace -> + when Global.options.trace <> None -> let pos = Expr.pos e in Format.fprintf fmt "(log_decision_taken@ @[{filename = \"%s\";@ start_line=%d;@ \ @@ -365,7 +365,7 @@ let rec format_expr (ctx : decl_ctx) (fmt : Format.formatter) (e : 'm expr) : (Pos.get_end_line pos) (Pos.get_end_column pos) format_string_list (Pos.get_law_info pos) format_with_parens arg1 | EAppOp { op = Log (EndCall, info), _; args = [arg1]; _ } - when Global.options.trace -> + when Global.options.trace <> None -> Format.fprintf fmt "(log_end_call@ %a@ %a)" format_uid_list info format_with_parens arg1 | EAppOp { op = Log _, _; args = [arg1]; _ } -> @@ -482,7 +482,7 @@ let format_ctx Format.fprintf fmt "@[%a:@ %a@]" format_struct_field_name (None, struct_field) format_typ struct_field_type)) (StructField.Map.bindings struct_fields); - if Global.options.trace then + if Global.options.trace <> None then format_struct_embedding fmt (struct_name, struct_fields) in let format_enum_decl fmt (enum_name, enum_cons) = @@ -495,7 +495,7 @@ let format_ctx Format.fprintf fmt "@[| %a@ of@ %a@]" format_enum_cons_name enum_cons format_typ enum_cons_type)) (EnumConstructor.Map.bindings enum_cons); - if Global.options.trace then format_enum_embedding fmt (enum_name, enum_cons) + if Global.options.trace <> None then format_enum_embedding fmt (enum_name, enum_cons) in let is_in_type_ordering s = List.exists diff --git a/compiler/plugins/api_web.ml b/compiler/plugins/api_web.ml index d29552170..978d98bdc 100644 --- a/compiler/plugins/api_web.ml +++ b/compiler/plugins/api_web.ml @@ -475,7 +475,7 @@ let run keep_special_ops monomorphize_types _options = - let options = Global.enforce_options ~trace:true () in + let options = Global.enforce_options ~trace:(Some (lazy Format.std_formatter)) () in let prg, type_ordering, _ = Driver.Passes.lcalc options ~includes ~optimize ~check_invariants ~autotest:false ~closure_conversion ~keep_special_ops ~typed:Expr.typed diff --git a/compiler/scalc/to_python.ml b/compiler/scalc/to_python.ml index 19053e811..d77658539 100644 --- a/compiler/scalc/to_python.ml +++ b/compiler/scalc/to_python.ml @@ -297,11 +297,11 @@ let rec format_expression ctx (fmt : Format.formatter) (e : expr) : unit = f = EAppOp { op = Log (BeginCall, info), _; args = [f]; _ }, _; args = [arg]; } - when Global.options.trace -> + when Global.options.trace <> None -> Format.fprintf fmt "log_begin_call(%a,@ %a,@ %a)" format_uid_list info (format_expression ctx) f (format_expression ctx) arg | EAppOp { op = Log (VarDef var_def_info, info), _; args = [arg1]; _ } - when Global.options.trace -> + when Global.options.trace <> None -> Format.fprintf fmt "log_variable_definition(%a,@ LogIO(input_io=InputIO.%s,@ \ output_io=%s),@ %a)" @@ -313,7 +313,7 @@ let rec format_expression ctx (fmt : Format.formatter) (e : expr) : unit = (if var_def_info.log_io_output then "True" else "False") (format_expression ctx) arg1 | EAppOp { op = Log (PosRecordIfTrueBool, _), _; args = [arg1]; _ } - when Global.options.trace -> + when Global.options.trace <> None -> let pos = Mark.get e in Format.fprintf fmt "log_decision_taken(SourcePosition(filename=\"%s\",@ start_line=%d,@ \ @@ -322,7 +322,7 @@ let rec format_expression ctx (fmt : Format.formatter) (e : expr) : unit = (Pos.get_end_line pos) (Pos.get_end_column pos) format_string_list (Pos.get_law_info pos) (format_expression ctx) arg1 | EAppOp { op = Log (EndCall, info), _; args = [arg1]; _ } - when Global.options.trace -> + when Global.options.trace <> None -> Format.fprintf fmt "log_end_call(%a,@ %a)" format_uid_list info (format_expression ctx) arg1 | EAppOp { op = Log _, _; args = [arg1]; _ } -> diff --git a/compiler/scopelang/from_desugared.ml b/compiler/scopelang/from_desugared.ml index 30afdaf8d..5037d1fcd 100644 --- a/compiler/scopelang/from_desugared.ml +++ b/compiler/scopelang/from_desugared.ml @@ -37,7 +37,7 @@ let tag_with_log_entry (e : untyped Ast.expr boxed) (l : log_entry) (markings : Uid.MarkedString.info list) : untyped Ast.expr boxed = - if Global.options.trace then + if Global.options.trace <> None then Expr.eappop ~op:(Log (l, markings), Expr.pos e) ~tys:[TAny, Expr.pos e] diff --git a/compiler/shared_ast/interpreter.ml b/compiler/shared_ast/interpreter.ml index 21b5306c0..8aa9aecab 100644 --- a/compiler/shared_ast/interpreter.ml +++ b/compiler/shared_ast/interpreter.ml @@ -31,8 +31,6 @@ let is_empty_error : type a. (a, 'm) gexpr -> bool = (* TODO: we should provide a generic way to print logs, that work across the different backends: python, ocaml, javascript, and interpreter *) -let indent_str = ref "" - (** {1 Evaluation} *) let rec format_runtime_value lang ppf = function @@ -68,34 +66,43 @@ let rec format_runtime_value lang ppf = function (Array.to_list elts) | Runtime.Unembeddable -> Format.pp_print_string ppf "" -let print_log lang entry = +let print_log ppf lang level entry = let pp_infos = Format.( pp_print_list - ~pp_sep:(fun ppf () -> Format.fprintf ppf ".@,") + ~pp_sep:(fun ppf () -> fprintf ppf ".@,") pp_print_string) in + let logprintf level entry fmt = + if ppf == Message.std_ppf () then Format.fprintf ppf "[@{LOG@}] "; + Format.fprintf ppf ("@[%*s%a" ^^ fmt ^^ "@]@,") (level * 2) "" Print.log_entry entry + in match entry with | Runtime.BeginCall infos -> - Message.log "%s%a %a" !indent_str Print.log_entry BeginCall pp_infos infos; - indent_str := !indent_str ^ " " + logprintf level BeginCall " %a" pp_infos infos; + level + 1 | Runtime.EndCall infos -> - indent_str := String.sub !indent_str 0 (String.length !indent_str - 2); - Message.log "%s%a %a" !indent_str Print.log_entry EndCall pp_infos infos + let level = max 0 (level - 1) in + logprintf level EndCall " %a" pp_infos infos; + level | Runtime.VariableDefinition (infos, io, value) -> - Message.log "%s%a %a: @{%s@}" !indent_str Print.log_entry + logprintf level (VarDef { log_typ = TAny; log_io_input = io.Runtime.io_input; log_io_output = io.Runtime.io_output; }) + " %a: @{%s@}" pp_infos infos - (Message.unformat (fun ppf -> format_runtime_value lang ppf value)) + (Message.unformat (fun ppf -> format_runtime_value lang ppf value)); + level | Runtime.DecisionTaken rtpos -> let pos = Expr.runtime_to_pos rtpos in - Message.log "%s@[%a@{Definition applied@}:@,%a@]" !indent_str - Print.log_entry PosRecordIfTrueBool Pos.format_loc_text pos + logprintf level PosRecordIfTrueBool + "@[@{Definition applied@}:@,%a@]@," + Pos.format_loc_text pos; + level let rec value_to_runtime_embedded = function | ELit LUnit -> Runtime.Unit @@ -248,7 +255,7 @@ let rec evaluate_operator match op, args with | Length, [(EArray es, _)] -> ELit (LInt (Runtime.integer_of_int (List.length es))) - | Log (entry, infos), [(e, _)] when Global.options.trace -> ( + | Log (entry, infos), [(e, _)] when Global.options.trace <> None -> ( let rtinfos = List.map Uid.MarkedString.to_string infos in match entry with | BeginCall -> Runtime.log_begin_call rtinfos e @@ -915,11 +922,28 @@ let evaluate_expr_trace : Fun.protect (fun () -> evaluate_expr ctx lang e) ~finally:(fun () -> - if Global.options.trace then + match Global.options.trace with + | None -> () + | Some (lazy ppf) -> let trace = Runtime.retrieve_log () in - List.iter (print_log lang) trace - (* TODO: [Runtime.pp_events ~is_first_call:true Format.err_formatter - (Runtime.EventParser.parse_raw_events trace)] fais here, check why *)) + let output_trace fmt = + match Global.options.trace_format with + | Human -> + Format.pp_open_vbox ppf 0; + ignore @@ List.fold_left (print_log ppf lang) 0 trace; + Format.pp_close_box ppf () + | JSON -> + Format.fprintf fmt "@[[@,"; + Format.pp_print_list + ~pp_sep:(fun fmt () -> Format.fprintf fmt ",@,") + Format.pp_print_string + fmt + (List.map Runtime.Json.raw_event trace); + Format.fprintf fmt "]@]@." + in + Fun.protect + (fun () -> output_trace ppf) + ~finally:(fun () -> (Format.pp_print_flush ppf ()))) let evaluate_expr_safe : type d. diff --git a/runtimes/ocaml/runtime.ml b/runtimes/ocaml/runtime.ml index 6ce3c86c0..6761e64a9 100644 --- a/runtimes/ocaml/runtime.ml +++ b/runtimes/ocaml/runtime.ml @@ -317,26 +317,51 @@ module BufferedJson = struct str; Buffer.add_char buf '"' + let decimal buf d = + let max_decimals = 6 in + let dec_str = + let open Z in + let sign = Q.sign d in + let n = abs (Q.num d) in + let d = abs (Q.den d) in + let int_part, dec_part = div_rem n d in + bprint buf (~$sign * int_part); + Buffer.add_char buf '.'; + let dec_part = (((~$10 ** max_decimals) * dec_part) + (d / ~$2)) / d in + format ("%0" ^ string_of_int max_decimals ^ "d") dec_part + in + let rec last_non0 n = + if n <= 1 || dec_str.[n - 1] <> '0' then n else last_non0 (n - 1) + in + Buffer.add_substring buf dec_str 0 (last_non0 max_decimals) + (* Note: the output format is made for transition with what Yojson gave us, but we could change it to something nicer (e.g. objects for structures) *) let rec runtime_value buf = function - | Unit -> Buffer.add_string buf {|"Unit"|} + | Unit -> Buffer.add_string buf "{}" | Bool b -> Buffer.add_string buf (string_of_bool b) | Money m -> Buffer.add_string buf (money_to_string m) | Integer i -> Buffer.add_string buf (integer_to_string i) - | Decimal d -> - Buffer.add_string buf (decimal_to_string ~max_prec_digits:10 d) + | Decimal d -> decimal buf d | Date d -> quote buf (date_to_string d) | Duration d -> quote buf (duration_to_string d) | Enum (name, (constr, v)) -> - Printf.bprintf buf {|[["%s"],["%s",%a]]|} name constr runtime_value v + Printf.bprintf buf + {|{"kind": "enum", "name": "%s", "constructor": "%s", "value": %a}|} + name constr runtime_value v | Struct (name, elts) -> - Printf.bprintf buf {|["%s",[%a]]|} name + Printf.bprintf buf {|{"kind": "struct", "name": "%s", "fields": {%a}}|} + name (list (fun buf (cstr, v) -> - Printf.bprintf buf {|"%s":%a|} cstr runtime_value v)) + Printf.bprintf buf {|"%s": %a|} cstr runtime_value v)) elts - | Array elts | Tuple elts -> - Printf.bprintf buf "[%a]" (list runtime_value) (Array.to_list elts) + | (Array elts | Tuple elts) as v -> + Printf.bprintf buf {|{"kind": %s, "value":[%a]}|} + (match v with + | Array _ -> "\"array\"" + | Tuple _ -> "\"tuple\"" + | _ -> assert false) + (list runtime_value) (Array.to_list elts) | Unembeddable -> Buffer.add_string buf {|"unembeddable"|} let information buf info = Printf.bprintf buf "[%a]" (list quote) info @@ -380,6 +405,26 @@ module BufferedJson = struct Printf.bprintf buf {|,"fun_inputs":[%a]|} (list var_def) fc.fun_inputs; Printf.bprintf buf {|,"body":[%a]|} (list event) fc.body; Printf.bprintf buf {|,"output":%a}|} var_def fc.output + + and raw_event buf = function + | BeginCall name -> + Printf.bprintf buf {|{"event": "BeginCall", "name": "%s"}|} + (String.concat "." name) + | EndCall name -> + Printf.bprintf buf {|{"event": "EndCall", "name": "%s"}|} + (String.concat "." name) + | VariableDefinition (name, io, value) -> + Printf.bprintf buf + {|{ + "event": "VariableDefinition", + "name": "%s", + "io": %a, + "value": %a + }|} + (String.concat "." name) io_log io runtime_value value + | DecisionTaken source_pos -> + Printf.bprintf buf {|{"event": "DecisionTaken", "pos": %a}|} + source_position source_pos end module Json = struct @@ -393,6 +438,7 @@ module Json = struct let runtime_value = str runtime_value let io_log = str io_log let event = str event + let raw_event = str raw_event end let log_ref : raw_event list ref = ref [] diff --git a/runtimes/ocaml/runtime.mli b/runtimes/ocaml/runtime.mli index 47f856f94..3a3f1276e 100644 --- a/runtimes/ocaml/runtime.mli +++ b/runtimes/ocaml/runtime.mli @@ -252,6 +252,7 @@ module Json : sig (* val information: information -> string *) val event : event -> string + val raw_event : raw_event -> string end val pp_events : ?is_first_call:bool -> Format.formatter -> event list -> unit diff --git a/tests/scope/good/scope_call3.catala_en b/tests/scope/good/scope_call3.catala_en index 2cd176529..d615ca94f 100644 --- a/tests/scope/good/scope_call3.catala_en +++ b/tests/scope/good/scope_call3.catala_en @@ -67,7 +67,7 @@ $ catala Interpret -t -s HousingComputation --debug 7 │ definition f of x equals (output of RentComputation).f of x │ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ [LOG] ≔ RentComputation.direct. - output: RentComputation { -- f: } + output: RentComputation { -- f: } [LOG] ← RentComputation.direct [LOG] → RentComputation.f [LOG] ≔ RentComputation.f.input0: 1