1616
1717open Util.Result.Infix
1818
19+ let loc_error ~loc fmt =
20+ Format. kasprintf
21+ (fun s -> Error (`Msg s))
22+ (" %a: invalid code block: " ^^ fmt)
23+ Stable_printer.Location. pp loc
24+
25+ let locate_error_msg ~loc s =
26+ Format. asprintf " %a: invalid code block: %s" Stable_printer.Location. pp loc s
27+
28+ let locate_errors ~loc r =
29+ Result. map_error
30+ (fun l -> List. map (fun (`Msg m ) -> `Msg (locate_error_msg ~loc m)) l)
31+ r
32+
1933module Header = struct
2034 type t = Shell of [ `Sh | `Bash ] | OCaml | Other of string
2135
@@ -41,6 +55,26 @@ module Header = struct
4155end
4256
4357type section = int * string
58+
59+ module Raw = struct
60+ type t =
61+ | Include of { loc : Location .t ; section : section option ; labels : string }
62+ | Any of {
63+ loc : Location .t ;
64+ section : section option ;
65+ header : string ;
66+ contents : string list ;
67+ label_cmt : string option ;
68+ legacy_labels : string ;
69+ errors : Output .t list ;
70+ }
71+
72+ let make ~loc ~section ~header ~contents ~label_cmt ~legacy_labels ~errors =
73+ Any { loc; section; header; contents; label_cmt; legacy_labels; errors }
74+
75+ let make_include ~loc ~section ~labels = Include { loc; section; labels }
76+ end
77+
4478type cram_value = { language : [ `Sh | `Bash ]; non_det : Label .non_det option }
4579
4680type ocaml_value = {
@@ -104,7 +138,7 @@ let dump ppf ({ loc; section; labels; contents; value; _ } as b) =
104138 Fmt. pf ppf
105139 " {@[loc: %a;@ section: %a;@ labels: %a;@ header: %a;@ contents: %a;@ \
106140 value: %a@]}"
107- Stable_printer.Location. print_loc loc
141+ Stable_printer.Location. pp loc
108142 Fmt. (Dump. option dump_section)
109143 section
110144 Fmt.Dump. (list Label. pp)
@@ -253,20 +287,20 @@ let version_enabled version =
253287
254288let get_label f (labels : Label.t list ) = Util.List. find_map f labels
255289
256- let label_not_allowed ~label ~kind =
257- Util.Result. errorf " `%s` label is not allowed for %s blocks." label kind
290+ let label_not_allowed ~loc ~ label ~kind =
291+ loc_error ~loc " `%s` label is not allowed for %s blocks." label kind
258292
259- let label_required ~label ~kind =
260- Util.Result. errorf " `%s` label is required for %s blocks." label kind
293+ let label_required ~loc ~ label ~kind =
294+ loc_error ~loc " `%s` label is required for %s blocks." label kind
261295
262- let check_not_set msg = function
263- | Some _ -> Util.Result. errorf msg
296+ let check_not_set ~ loc msg = function
297+ | Some _ -> loc_error ~loc " %s " msg
264298 | None -> Ok ()
265299
266- let check_no_errors = function
300+ let check_no_errors ~ loc = function
267301 | [] -> Ok ()
268302 | _ :: _ ->
269- Util.Result. errorf " error block cannot be attached to a non-OCaml block"
303+ loc_error ~loc " error block cannot be attached to a non-OCaml block"
270304
271305type block_config = {
272306 non_det : Label .non_det option ;
@@ -301,22 +335,22 @@ let get_block_config l =
301335 file_inc = get_label (function File x -> Some x | _ -> None ) l;
302336 }
303337
304- let mk_ocaml ~config ~contents ~errors =
338+ let mk_ocaml ~loc ~ config ~contents ~errors =
305339 let kind = " OCaml" in
306340 match config with
307341 | { file_inc = None ; part = None ; env; non_det; _ } -> (
308342 match guess_ocaml_kind contents with
309343 | `Code -> Ok (OCaml { env = Ocaml_env. mk env; non_det; errors })
310344 | `Toplevel ->
311- Util.Result. errorf " toplevel syntax is not allowed in OCaml blocks." )
312- | { file_inc = Some _ ; _ } -> label_not_allowed ~label: " file" ~kind
313- | { part = Some _ ; _ } -> label_not_allowed ~label: " part" ~kind
345+ loc_error ~loc " toplevel syntax is not allowed in OCaml blocks." )
346+ | { file_inc = Some _ ; _ } -> label_not_allowed ~loc ~ label:" file" ~kind
347+ | { part = Some _ ; _ } -> label_not_allowed ~loc ~ label:" part" ~kind
314348
315- let mk_cram ?language ~config ~header ~errors () =
349+ let mk_cram ~ loc ?language ~config ~header ~errors () =
316350 let kind = " shell" in
317351 match config with
318352 | { file_inc = None ; part = None ; env = None ; non_det; _ } ->
319- check_no_errors errors >> | fun () ->
353+ check_no_errors ~loc errors >> | fun () ->
320354 let language =
321355 Util.Option. value language
322356 ~default:
@@ -325,28 +359,27 @@ let mk_cram ?language ~config ~header ~errors () =
325359 | _ -> `Sh )
326360 in
327361 Cram { language; non_det }
328- | { file_inc = Some _ ; _ } -> label_not_allowed ~label: " file" ~kind
329- | { part = Some _ ; _ } -> label_not_allowed ~label: " part" ~kind
330- | { env = Some _ ; _ } -> label_not_allowed ~label: " env" ~kind
362+ | { file_inc = Some _ ; _ } -> label_not_allowed ~loc ~ label:" file" ~kind
363+ | { part = Some _ ; _ } -> label_not_allowed ~loc ~ label:" part" ~kind
364+ | { env = Some _ ; _ } -> label_not_allowed ~loc ~ label:" env" ~kind
331365
332- let mk_toplevel ~config ~contents ~errors =
366+ let mk_toplevel ~loc ~ config ~contents ~errors =
333367 let kind = " toplevel" in
334368 match config with
335369 | { file_inc = None ; part = None ; env; non_det; _ } -> (
336370 match guess_ocaml_kind contents with
337- | `Code ->
338- Util.Result. errorf " invalid toplevel syntax in toplevel blocks."
371+ | `Code -> loc_error ~loc " invalid toplevel syntax in toplevel blocks."
339372 | `Toplevel ->
340- check_no_errors errors >> | fun () ->
373+ check_no_errors ~loc errors >> | fun () ->
341374 Toplevel { env = Ocaml_env. mk env; non_det })
342- | { file_inc = Some _ ; _ } -> label_not_allowed ~label: " file" ~kind
343- | { part = Some _ ; _ } -> label_not_allowed ~label: " part" ~kind
375+ | { file_inc = Some _ ; _ } -> label_not_allowed ~loc ~ label:" file" ~kind
376+ | { part = Some _ ; _ } -> label_not_allowed ~loc ~ label:" part" ~kind
344377
345- let mk_include ~config ~header ~errors =
378+ let mk_include ~loc ~ config ~header ~errors =
346379 let kind = " include" in
347380 match config with
348381 | { file_inc = Some file_included ; part; non_det = None ; env = None ; _ } -> (
349- check_no_errors errors >> = fun () ->
382+ check_no_errors ~loc errors >> = fun () ->
350383 match header with
351384 | Some Header. OCaml ->
352385 let file_kind = Fk_ocaml { part_included = part } in
@@ -356,40 +389,40 @@ let mk_include ~config ~header ~errors =
356389 | None ->
357390 let file_kind = Fk_other { header } in
358391 Ok (Include { file_included; file_kind })
359- | Some _ -> label_not_allowed ~label: " part " ~kind: " non-OCaml include " )
360- )
361- | { file_inc = None ; _ } -> label_required ~label: " file" ~kind
392+ | Some _ ->
393+ label_not_allowed ~loc ~label: " part " ~kind: " non-OCaml include " ) )
394+ | { file_inc = None ; _ } -> label_required ~loc ~ label:" file" ~kind
362395 | { non_det = Some _ ; _ } ->
363- label_not_allowed ~label: " non-deterministic" ~kind
364- | { env = Some _ ; _ } -> label_not_allowed ~label: " env" ~kind
396+ label_not_allowed ~loc ~ label:" non-deterministic" ~kind
397+ | { env = Some _ ; _ } -> label_not_allowed ~loc ~ label:" env" ~kind
365398
366- let infer_block ~config ~header ~contents ~errors =
399+ let infer_block ~loc ~ config ~header ~contents ~errors =
367400 match config with
368- | { file_inc = Some _ ; _ } -> mk_include ~config ~header ~errors
401+ | { file_inc = Some _ ; _ } -> mk_include ~loc ~ config ~header ~errors
369402 | { file_inc = None ; part; _ } -> (
370403 match header with
371404 | Some (Header. Shell language ) ->
372- mk_cram ~language ~config ~header ~errors ()
405+ mk_cram ~loc ~ language ~config ~header ~errors ()
373406 | Some Header. OCaml -> (
374407 match guess_ocaml_kind contents with
375- | `Code -> mk_ocaml ~config ~contents ~errors
376- | `Toplevel -> mk_toplevel ~config ~contents ~errors )
408+ | `Code -> mk_ocaml ~loc ~ config ~contents ~errors
409+ | `Toplevel -> mk_toplevel ~loc ~ config ~contents ~errors )
377410 | _ ->
378- check_not_set " `part` label requires a `file` label." part
411+ check_not_set ~loc " `part` label requires a `file` label." part
379412 >> = fun () ->
380- check_no_errors errors >> | fun () -> Raw { header })
413+ check_no_errors ~loc errors >> | fun () -> Raw { header })
381414
382415let mk ~loc ~section ~labels ~legacy_labels ~header ~contents ~errors =
383416 let block_kind =
384417 get_label (function Block_kind x -> Some x | _ -> None ) labels
385418 in
386419 let config = get_block_config labels in
387420 (match block_kind with
388- | Some OCaml -> mk_ocaml ~config ~contents ~errors
389- | Some Cram -> mk_cram ~config ~header ~errors ()
390- | Some Toplevel -> mk_toplevel ~config ~contents ~errors
391- | Some Include -> mk_include ~config ~header ~errors
392- | None -> infer_block ~config ~header ~contents ~errors )
421+ | Some OCaml -> mk_ocaml ~loc ~ config ~contents ~errors
422+ | Some Cram -> mk_cram ~loc ~ config ~header ~errors ()
423+ | Some Toplevel -> mk_toplevel ~loc ~ config ~contents ~errors
424+ | Some Include -> mk_include ~loc ~ config ~header ~errors
425+ | None -> infer_block ~loc ~ config ~header ~contents ~errors )
393426 >> = fun value ->
394427 version_enabled config.version >> | fun version_enabled ->
395428 {
@@ -412,7 +445,27 @@ let mk_include ~loc ~section ~labels =
412445 let header = Header. infer_from_file file_inc in
413446 mk ~loc ~section ~labels ~legacy_labels: false ~header ~contents: []
414447 ~errors: []
415- | None -> label_required ~label: " file" ~kind: " include"
448+ | None -> label_required ~loc ~label: " file" ~kind: " include"
449+
450+ let parse_labels ~label_cmt ~legacy_labels =
451+ match (label_cmt, legacy_labels) with
452+ | Some label_cmt , "" ->
453+ Label. of_string label_cmt >> = fun labels -> Ok (labels, false )
454+ | Some _ , _ -> Error [ `Msg " cannot mix both block labels syntax" ]
455+ | None , l -> Label. of_string l >> = fun labels -> Ok (labels, true )
456+
457+ let from_raw raw =
458+ match raw with
459+ | Raw. Include { loc; section; labels } ->
460+ locate_errors ~loc (Label. of_string labels) >> = fun labels ->
461+ Util.Result. to_error_list @@ mk_include ~loc ~section ~labels
462+ | Raw. Any { loc; section; header; contents; label_cmt; legacy_labels; errors }
463+ ->
464+ let header = Header. of_string header in
465+ locate_errors ~loc (parse_labels ~label_cmt ~legacy_labels )
466+ >> = fun (labels , legacy_labels ) ->
467+ Util.Result. to_error_list
468+ @@ mk ~loc ~section ~header ~contents ~labels ~legacy_labels ~errors
416469
417470let is_active ?section :s t =
418471 let active =
0 commit comments