@@ -23,23 +23,43 @@ let invoke_driver model_name model flags =
2323
2424let wrap_warnings ~warnings =
2525 ( " warnings"
26- , Js.Unsafe. inject (Js. array (List. to_array (List. map ~f: Js. string warnings)))
26+ , Js.Unsafe. coerce (Js. array (List. to_array (List. map ~f: Js. string warnings)))
2727 )
2828
2929let wrap_error ~warnings e =
3030 Js.Unsafe. obj
31- [| (" errors" , Js.Unsafe. inject (Array. map ~f: Js. string [| e |]))
31+ [| ( " errors"
32+ , (* NB: The "0" entry is due to a historical mistake that led
33+ the first entry always being a 0 (this element is a 'tag' used by jsoo
34+ internally, but was not meant to be exposed to the user).
35+ For backward compatibility with existing consumers
36+ of stanc.js we have to keep this behavior.
37+ *)
38+ Js.Unsafe. coerce (Js. array (Array. map ~f: Js. string [| " 0" ; e |])) )
3239 ; wrap_warnings ~warnings |]
3340
34- let wrap_result ?printed_filename ~code ~warnings res =
41+ (* * similar to [Fmt.str_like] but directly sets style
42+ rendering rather than copying from another ppf *)
43+ let str_color ~color_output =
44+ let buf = Buffer. create 64 in
45+ let ppf = Format. formatter_of_buffer buf in
46+ Fmt. set_style_renderer ppf (if color_output then `Ansi_tty else `None );
47+ let flush ppf =
48+ Format. pp_print_flush ppf () ;
49+ let s = Buffer. contents buf in
50+ Buffer. reset buf;
51+ s in
52+ Format. kfprintf flush ppf
53+
54+ let wrap_result ?printed_filename ~color_output ~code ~warnings res =
3555 match res with
3656 | Result. Ok s ->
3757 Js.Unsafe. obj
38- [| (" result" , Js.Unsafe. inject (Js. string s)); wrap_warnings ~warnings
58+ [| (" result" , Js.Unsafe. coerce (Js. string s)); wrap_warnings ~warnings
3959 |]
4060 | Error e ->
4161 let e =
42- Fmt. str " %a"
62+ str_color ~color_output " %a"
4363 (Errors. pp ?printed_filename ?code:(Some (Js.to_string code )))
4464 e in
4565 wrap_error ~warnings e
@@ -66,7 +86,7 @@ let checked_to_array ~name value =
6686 (Js.Unsafe. meth_call
6787 (Js.Unsafe. pure_js_expr " Array" )
6888 " isArray"
69- [| Js.Unsafe. inject value |]))
89+ [| Js.Unsafe. coerce value |]))
7090 then
7191 Error
7292 (Fmt. str
@@ -105,9 +125,10 @@ let get_includes includes : string String.Map.t * string list =
105125 (Fmt. str " Warning: stanc.js failed to parse included file mapping:@ %s" )
106126 warnings )
107127
108- (* * Turn our array of flags into a Driver.Flats.t *)
109- let process_flags (flags : 'a Js.opt ) includes : (Driver.Flags. t , string ) result
110- =
128+ type flags = {driver_flags : Driver.Flags .t ; color_output : bool }
129+
130+ (* * Turn our array of flags into a Driver.Flags.t *)
131+ let process_flags (flags : 'a Js.opt ) includes : (flags, string) result =
111132 let open Result in
112133 let open Common.Let_syntax.Result in
113134 let + flags =
@@ -124,70 +145,77 @@ let process_flags (flags : 'a Js.opt) includes : (Driver.Flags.t, string) result
124145 Some ocaml_flags in
125146 match flags with
126147 | None ->
127- {Driver.Flags. default with include_source= Include_files. InMemory includes}
148+ { driver_flags=
149+ { Driver.Flags. default with
150+ include_source= Include_files. InMemory includes }
151+ ; color_output= false }
128152 | Some flags ->
129153 let is_flag_set flag = Array. mem ~equal: String. equal flags flag in
130154 let flag_val flag =
131155 let prefix = flag ^ " =" in
132156 Array. find_map flags ~f: (String. chop_prefix ~prefix ) in
133- { optimization_level=
134- (if is_flag_set " O0" then Optimize. O0
135- else if is_flag_set " O1" || is_flag_set " O" then Optimize. O1
136- else if is_flag_set " Oexperimental" then Optimize. Oexperimental
137- else Optimize. O0 )
138- ; allow_undefined= is_flag_set " allow-undefined"
139- ; functions_only= is_flag_set " functions-only"
140- ; standalone_functions= is_flag_set " standalone-functions"
141- ; use_opencl= is_flag_set " use-opencl"
142- ; include_source= Include_files. InMemory includes
143- ; info= is_flag_set " info"
144- ; version= is_flag_set " version"
145- ; auto_format= is_flag_set " auto-format" || is_flag_set " print-canonical"
146- ; debug_settings=
147- { print_ast= is_flag_set " debug-ast"
148- ; print_typed_ast= is_flag_set " debug-typed-ast"
149- ; print_mir=
150- (if is_flag_set " debug-mir" then Basic
151- else if is_flag_set " debug-mir-pretty" then Pretty
152- else Off )
153- ; print_transformed_mir=
154- (if is_flag_set " debug-transformed-mir" then Basic
155- else if is_flag_set " debug-transformed-mir-pretty" then Pretty
156- else Off )
157- ; print_optimized_mir=
158- (if is_flag_set " debug-optimized-mir" then Basic
159- else if is_flag_set " debug-optimized-mir-pretty" then Pretty
160- else Off )
161- ; print_mem_patterns= is_flag_set " debug-mem-patterns"
162- ; force_soa= None
163- ; print_lir= is_flag_set " debug-lir"
164- ; debug_generate_data= is_flag_set " debug-generate-data"
165- ; debug_generate_inits= is_flag_set " debug-generate-inits"
166- ; debug_data_json= flag_val " debug-data-json" }
167- ; line_length=
168- flag_val " max-line-length"
169- |> Option. map ~f: int_of_string
170- |> Option. value ~default: 78
171- ; canonicalizer_settings=
172- (if is_flag_set " print-canonical" then Canonicalize. legacy
173- else
174- match flag_val " canonicalize" with
175- | None -> Canonicalize. none
176- | Some s ->
177- let parse settings s =
178- match String. lowercase s with
179- | "deprecations" ->
180- Canonicalize. {settings with deprecations= true }
181- | "parentheses" -> {settings with parentheses= true }
182- | "braces" -> {settings with braces= true }
183- | "strip-comments" -> {settings with strip_comments= true }
184- | "includes" -> {settings with inline_includes= true }
185- | _ -> settings in
186- List. fold ~f: parse ~init: Canonicalize. none
187- (String. split ~on: ',' s))
188- ; warn_pedantic= is_flag_set " warn-pedantic"
189- ; warn_uninitialized= is_flag_set " warn-uninitialized"
190- ; filename_in_msg= flag_val " filename-in-msg" }
157+ { driver_flags=
158+ { optimization_level=
159+ (if is_flag_set " O0" then Optimize. O0
160+ else if is_flag_set " O1" || is_flag_set " O" then Optimize. O1
161+ else if is_flag_set " Oexperimental" then Optimize. Oexperimental
162+ else Optimize. O0 )
163+ ; allow_undefined= is_flag_set " allow-undefined"
164+ ; functions_only= is_flag_set " functions-only"
165+ ; standalone_functions= is_flag_set " standalone-functions"
166+ ; use_opencl= is_flag_set " use-opencl"
167+ ; include_source= Include_files. InMemory includes
168+ ; info= is_flag_set " info"
169+ ; version= is_flag_set " version"
170+ ; auto_format=
171+ is_flag_set " auto-format" || is_flag_set " print-canonical"
172+ ; debug_settings=
173+ { print_ast= is_flag_set " debug-ast"
174+ ; print_typed_ast= is_flag_set " debug-typed-ast"
175+ ; print_mir=
176+ (if is_flag_set " debug-mir" then Basic
177+ else if is_flag_set " debug-mir-pretty" then Pretty
178+ else Off )
179+ ; print_transformed_mir=
180+ (if is_flag_set " debug-transformed-mir" then Basic
181+ else if is_flag_set " debug-transformed-mir-pretty" then
182+ Pretty
183+ else Off )
184+ ; print_optimized_mir=
185+ (if is_flag_set " debug-optimized-mir" then Basic
186+ else if is_flag_set " debug-optimized-mir-pretty" then Pretty
187+ else Off )
188+ ; print_mem_patterns= is_flag_set " debug-mem-patterns"
189+ ; force_soa= None
190+ ; print_lir= is_flag_set " debug-lir"
191+ ; debug_generate_data= is_flag_set " debug-generate-data"
192+ ; debug_generate_inits= is_flag_set " debug-generate-inits"
193+ ; debug_data_json= flag_val " debug-data-json" }
194+ ; line_length=
195+ flag_val " max-line-length"
196+ |> Option. map ~f: int_of_string
197+ |> Option. value ~default: 78
198+ ; canonicalizer_settings=
199+ (if is_flag_set " print-canonical" then Canonicalize. legacy
200+ else
201+ match flag_val " canonicalize" with
202+ | None -> Canonicalize. none
203+ | Some s ->
204+ let parse settings s =
205+ match String. lowercase s with
206+ | "deprecations" ->
207+ Canonicalize. {settings with deprecations= true }
208+ | "parentheses" -> {settings with parentheses= true }
209+ | "braces" -> {settings with braces= true }
210+ | "strip-comments" -> {settings with strip_comments= true }
211+ | "includes" -> {settings with inline_includes= true }
212+ | _ -> settings in
213+ List. fold ~f: parse ~init: Canonicalize. none
214+ (String. split ~on: ',' s))
215+ ; warn_pedantic= is_flag_set " warn-pedantic"
216+ ; warn_uninitialized= is_flag_set " warn-uninitialized"
217+ ; filename_in_msg= flag_val " filename-in-msg" }
218+ ; color_output= is_flag_set " color-output" }
191219
192220(* * Handle conversion of JS <-> OCaml values invoke driver *)
193221let stan2cpp_wrapped name code flags includes =
@@ -196,18 +224,19 @@ let stan2cpp_wrapped name code flags includes =
196224 let compilation_result =
197225 let * name = checked_to_string ~name: " name" name in
198226 let * code = checked_to_string ~name: " code" code in
199- let * driver_flags = process_flags flags includes in
227+ let * { driver_flags; color_output} = process_flags flags includes in
200228 let + result, warnings =
201229 Common.ICE. with_exn_message (fun () ->
202230 invoke_driver name code driver_flags) in
203- (result, warnings, driver_flags.filename_in_msg) in
231+ (result, warnings, driver_flags.filename_in_msg, color_output ) in
204232 match compilation_result with
205- | Ok (result , warnings , printed_filename ) ->
233+ | Ok (result , warnings , printed_filename , color_output ) ->
206234 let warnings =
207235 include_reader_warnings
208- @ List. map ~f: (Fmt. str " %a" (Warnings. pp ?printed_filename)) warnings
209- in
210- wrap_result ?printed_filename ~code result ~warnings
236+ @ List. map
237+ ~f: (str_color ~color_output " %a" (Warnings. pp ?printed_filename))
238+ warnings in
239+ wrap_result ?printed_filename ~color_output ~code result ~warnings
211240 | Error non_compilation_error (* either an ICE or malformed JS input *) ->
212241 wrap_error ~warnings: include_reader_warnings non_compilation_error
213242
0 commit comments