Skip to content

Commit 04bc092

Browse files
authored
Merge pull request #241 from gpetiot/block-loc
Keep locations from parsing instead of recomputing the lines, providing better error messages
2 parents b028158 + e2006b7 commit 04bc092

File tree

22 files changed

+148
-185
lines changed

22 files changed

+148
-185
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
- Report `#require` directive errors (#276, @gpetiot)
1919
- Handle no such file exception: the input file and the values of options `--root` and `--prelude` are checked (#292, @gpetiot)
20+
- Keep locations from parsing instead of recomputing the lines, providing better error messages (#241, @gpetiot)
2021

2122
#### Security
2223

bin/pp.ml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ let src = Logs.Src.create "cram.pp"
2020

2121
module Log = (val Logs.src_log src : Logs.LOG)
2222

23+
let vpad_of_lines t =
24+
let rec aux i = function
25+
| h :: t when String.trim h = "" -> aux (i + 1) t
26+
| _ -> i
27+
in
28+
aux 0 t
29+
2330
let run (`Setup ()) (`File file) (`Section section) =
2431
Mdx.parse_file Normal file >>! fun t ->
2532
let t =
@@ -32,6 +39,7 @@ let run (`Setup ()) (`File file) (`Section section) =
3239
match t with
3340
| [] -> 1
3441
| _ ->
42+
let rvpad = ref 1 in
3543
List.iter
3644
(function
3745
| Mdx.Section _ | Text _ -> ()
@@ -43,7 +51,10 @@ let run (`Setup ()) (`File file) (`Section section) =
4351
match b.value with
4452
| Toplevel _ -> Fmt.pr "%a\n" pp_lines contents
4553
| OCaml _ ->
46-
Fmt.pr "%a\n%a\n" Mdx.Block.pp_line_directive (file, b.line)
54+
let vpad = vpad_of_lines contents in
55+
rvpad := vpad + !rvpad;
56+
let line = b.loc.loc_start.pos_lnum + !rvpad in
57+
Fmt.pr "%a\n%a\n" Mdx.Block.pp_line_directive (file, line)
4758
pp_lines contents
4859
| _ -> () ))
4960
t;

bin/test/main.ml

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ open Mdx
1818
open Compat
1919
open Result
2020
open Astring
21+
open Migrate_ast
2122
open Mdx.Util.Result.Infix
2223

2324
let src = Logs.Src.create "cram.test"
@@ -84,14 +85,12 @@ let run_test ?root blacklist temp_file t =
8485
match snd (Unix.waitpid [] pid) with WEXITED n -> n | _ -> 255
8586

8687
let root_dir ?root ?block () =
87-
match block with
88-
| Some t -> (
89-
match Mdx.Block.directory t with
90-
| Some d -> (
91-
match root with
92-
| Some r -> Some (r / d)
93-
| None -> Some (Filename.dirname t.file / d) )
94-
| None -> root )
88+
match (block : Block.t option) with
89+
| Some { dir = None; _ } -> root
90+
| Some { dir = Some d; loc = { loc_start = { pos_fname; _ }; _ }; _ } -> (
91+
match root with
92+
| Some r -> Some (r / d)
93+
| None -> Some (Filename.dirname pos_fname / d) )
9594
| None -> root
9695

9796
let resolve_root file dir root =
@@ -123,11 +122,10 @@ let run_cram_tests ?syntax t ?root ppf temp_file pad tests =
123122
tests;
124123
Block.pp_footer ?syntax ppf t
125124

126-
let eval_test ?block ?root c test =
127-
Log.debug (fun l ->
128-
l "eval_test %a" Fmt.(Dump.list (Fmt.fmt "%S")) (Toplevel.command test));
125+
let eval_test ?block ?root c cmd =
126+
Log.debug (fun l -> l "eval_test %a" Fmt.(Dump.list (Fmt.fmt "%S")) cmd);
129127
let root = root_dir ?root ?block () in
130-
with_dir root (fun () -> Mdx_top.eval c (Toplevel.command test))
128+
with_dir root (fun () -> Mdx_top.eval c cmd)
131129

132130
let err_eval ~cmd lines =
133131
Fmt.epr "Got an error while evaluating:\n---\n%a\n---\n%a\n%!"
@@ -137,13 +135,10 @@ let err_eval ~cmd lines =
137135
lines;
138136
exit 1
139137

140-
let eval_raw ?block ?root c ~line lines =
141-
let test =
142-
Toplevel.{ vpad = 0; hpad = 0; line; command = lines; output = [] }
143-
in
144-
match eval_test ?block ?root c test with
138+
let eval_raw ?block ?root c cmd =
139+
match eval_test ?block ?root c cmd with
145140
| Ok _ -> ()
146-
| Error e -> err_eval ~cmd:lines e
141+
| Error e -> err_eval ~cmd e
147142

148143
let split_lines lines =
149144
let aux acc s =
@@ -153,17 +148,14 @@ let split_lines lines =
153148
in
154149
List.fold_left aux [] (List.rev lines)
155150

156-
let eval_ocaml ~block ?syntax ?root c ppf ~line lines errors =
157-
let test =
158-
Toplevel.{ vpad = 0; hpad = 0; line; command = lines; output = [] }
159-
in
151+
let eval_ocaml ~block ?syntax ?root c ppf cmd errors =
160152
let update ~errors = function
161153
| { Block.value = OCaml v; _ } as b ->
162154
{ b with value = OCaml { v with errors } }
163155
(* [eval_ocaml] only called on OCaml blocks *)
164156
| _ -> assert false
165157
in
166-
match eval_test ?root ~block c test with
158+
match eval_test ?root ~block c cmd with
167159
| Ok _ -> Block.pp ?syntax ppf (update ~errors:[] block)
168160
| Error lines ->
169161
let errors =
@@ -184,8 +176,8 @@ let lines = function Ok x | Error x -> x
184176
let run_toplevel_tests ?syntax ?root c ppf tests t =
185177
Block.pp_header ?syntax ppf t;
186178
List.iter
187-
(fun test ->
188-
let lines = lines (eval_test ?root ~block:t c test) in
179+
(fun (test : Toplevel.t) ->
180+
let lines = lines (eval_test ?root ~block:t c test.command) in
189181
let lines = split_lines lines in
190182
let output =
191183
let output = List.map output_from_line lines in
@@ -304,8 +296,7 @@ let run_exn (`Setup ()) (`Non_deterministic non_deterministic)
304296
let det () =
305297
assert (syntax <> Some Cram);
306298
Mdx_top.in_env env (fun () ->
307-
eval_ocaml ~block:t ?syntax ?root c ppf ~line:t.line t.contents
308-
errors)
299+
eval_ocaml ~block:t ?syntax ?root c ppf t.contents errors)
309300
in
310301
with_non_det non_deterministic non_det ~command:print_block
311302
~output:det ~det
@@ -323,18 +314,17 @@ let run_exn (`Setup ()) (`Non_deterministic non_deterministic)
323314
| Toplevel { non_det; env } ->
324315
let tests =
325316
let syntax = Util.Option.value syntax ~default:Normal in
326-
Toplevel.of_lines ~syntax ~file:t.file ~line:t.line ~column:t.column
327-
t.contents
317+
Toplevel.of_lines ~syntax ~loc:t.loc t.contents
328318
in
329319
with_non_det non_deterministic non_det ~command:print_block
330320
~output:(fun () ->
331321
assert (syntax <> Some Cram);
332322
print_block ();
333323
List.iter
334-
(fun test ->
324+
(fun (test : Toplevel.t) ->
335325
match
336326
Mdx_top.in_env env (fun () ->
337-
eval_test ~block:t ?root c test)
327+
eval_test ~block:t ?root c test.command)
338328
with
339329
| Ok _ -> ()
340330
| Error e ->
@@ -354,7 +344,7 @@ let run_exn (`Setup ()) (`Non_deterministic non_deterministic)
354344
let buf = Buffer.create (String.length file_contents + 1024) in
355345
let ppf = Format.formatter_of_buffer buf in
356346
let envs = Document.envs items in
357-
let eval lines () = eval_raw ?root c ~line:0 lines in
347+
let eval lines () = eval_raw ?root c lines in
358348
let eval_in_env lines env = Mdx_top.in_env env (eval lines) in
359349
List.iter
360350
(function
@@ -391,8 +381,8 @@ let report_error_in_block block msg =
391381
| Cram _ -> "cram "
392382
| Toplevel _ -> "toplevel "
393383
in
394-
Fmt.epr "Error in the %scode block in %s at line %d:@]\n%s\n" kind block.file
395-
block.line msg
384+
Fmt.epr "%a: Error in the %scode block@]\n%s\n" Location.print_loc block.loc
385+
kind msg
396386

397387
let run setup non_deterministic silent_eval record_backtrace syntax silent
398388
verbose_findlib prelude prelude_str file section root force_output output :

lib/block.ml

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
open Result
1818
open Compat
19+
open Migrate_ast
1920
open Util.Result.Infix
2021

2122
module Header = struct
@@ -74,9 +75,7 @@ type value =
7475
| Include of include_value
7576

7677
type t = {
77-
line : int;
78-
column : int;
79-
file : string;
78+
loc : Location.t;
8079
section : section option;
8180
dir : string option;
8281
source_trees : string list;
@@ -111,12 +110,11 @@ let dump_value ppf = function
111110
| Toplevel _ -> Fmt.string ppf "Toplevel"
112111
| Include _ -> Fmt.string ppf "Include"
113112

114-
let dump ppf ({ file; line; column; section; labels; contents; value; _ } as b)
115-
=
113+
let dump ppf ({ loc; section; labels; contents; value; _ } as b) =
116114
Fmt.pf ppf
117-
"{@[file: %s;@ line: %d;@ column: %d;@ section: %a;@ labels: %a;@ header: \
118-
%a;@\n\
119-
\ contents: %a;@ value: %a@]}" file line column
115+
"{@[loc: %a;@ section: %a;@ labels: %a;@ header: %a;@ contents: %a;@ \
116+
value: %a@]}"
117+
Location.print_loc loc
120118
Fmt.(Dump.option dump_section)
121119
section
122120
Fmt.Dump.(list Label.pp)
@@ -130,7 +128,8 @@ let pp_lines syntax t =
130128
let pp =
131129
match syntax with
132130
| Some Syntax.Cram -> Fmt.fmt " %s"
133-
| Some Syntax.Mli -> fun ppf -> Fmt.fmt "%*s%s" ppf (t.column + 2) ""
131+
| Some Syntax.Mli ->
132+
fun ppf -> Fmt.fmt "%*s%s" ppf (t.loc.loc_start.pos_cnum + 2) ""
134133
| _ -> Fmt.string
135134
in
136135
Fmt.(list ~sep:(unit "\n") pp)
@@ -276,18 +275,16 @@ let executable_contents ~syntax b =
276275
| OCaml _ -> b.contents
277276
| Raw _ | Cram _ | Include _ -> []
278277
| Toplevel _ ->
279-
let phrases =
280-
Toplevel.of_lines ~syntax ~file:b.file ~line:b.line ~column:b.column
281-
b.contents
282-
in
278+
let phrases = Toplevel.of_lines ~syntax ~loc:b.loc b.contents in
283279
List.flatten
284280
(List.map
285-
(fun t ->
286-
match Toplevel.command t with
281+
(fun (t : Toplevel.t) ->
282+
match t.command with
287283
| [] -> []
288284
| cs ->
289285
let mk s = String.make (t.hpad + 2) ' ' ^ s in
290-
line_directive (b.file, t.line) :: List.map mk cs)
286+
line_directive (t.pos.pos_fname, t.pos.pos_lnum)
287+
:: List.map mk cs)
291288
phrases)
292289
in
293290
if contents = [] || ends_by_semi_semi contents then contents
@@ -437,8 +434,7 @@ let infer_block ~config ~header ~contents ~errors =
437434
>>= fun () ->
438435
check_no_errors errors >>| fun () -> Raw { header } )
439436

440-
let mk ~line ~file ~column ~section ~labels ~legacy_labels ~header ~contents
441-
~errors =
437+
let mk ~loc ~section ~labels ~legacy_labels ~header ~contents ~errors =
442438
let block_kind =
443439
get_label (function Block_kind x -> Some x | _ -> None) labels
444440
in
@@ -452,9 +448,7 @@ let mk ~line ~file ~column ~section ~labels ~legacy_labels ~header ~contents
452448
>>= fun value ->
453449
version_enabled config.version >>| fun version_enabled ->
454450
{
455-
line;
456-
file;
457-
column;
451+
loc;
458452
section;
459453
dir = config.dir;
460454
source_trees = config.source_trees;
@@ -469,12 +463,12 @@ let mk ~line ~file ~column ~section ~labels ~legacy_labels ~header ~contents
469463
value;
470464
}
471465

472-
let mk_include ~line ~file ~column ~section ~labels =
466+
let mk_include ~loc ~section ~labels =
473467
match get_label (function File x -> Some x | _ -> None) labels with
474468
| Some file_inc ->
475469
let header = Header.infer_from_file file_inc in
476-
mk ~line ~file ~column ~section ~labels ~legacy_labels:false ~header
477-
~contents:[] ~errors:[]
470+
mk ~loc ~section ~labels ~legacy_labels:false ~header ~contents:[]
471+
~errors:[]
478472
| None -> label_required ~label:"file" ~kind:"include"
479473

480474
let is_active ?section:s t =

lib/block.mli

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,7 @@ type section = int * string
7575
(** The type for sections. *)
7676

7777
type t = {
78-
line : int;
79-
column : int;
80-
file : string;
78+
loc : Location.t;
8179
section : section option;
8280
dir : string option;
8381
source_trees : string list;
@@ -95,9 +93,7 @@ type t = {
9593
(** The type for supported code blocks. *)
9694

9795
val mk :
98-
line:int ->
99-
file:string ->
100-
column:int ->
96+
loc:Location.t ->
10197
section:section option ->
10298
labels:Label.t list ->
10399
legacy_labels:bool ->
@@ -107,9 +103,7 @@ val mk :
107103
(t, [ `Msg of string ]) Result.result
108104

109105
val mk_include :
110-
line:int ->
111-
file:string ->
112-
column:int ->
106+
loc:Location.t ->
113107
section:section option ->
114108
labels:Label.t list ->
115109
(t, [ `Msg of string ]) Result.result

0 commit comments

Comments
 (0)