Skip to content

Commit eaa2e1b

Browse files
committed
refactor(cram): lex locations in cram tests
We add support for lexing locations in cram tests. Signed-off-by: Ali Caglayan <[email protected]>
1 parent 4e044e3 commit eaa2e1b

File tree

5 files changed

+499
-94
lines changed

5 files changed

+499
-94
lines changed

src/dune_rules/cram/cram_exec.ml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,16 @@ let cram_stanzas =
6363
let rec loop acc conflict_state =
6464
match Cram_lexer.block lexbuf with
6565
| None -> List.rev acc
66-
| Some s ->
66+
| Some (loc, block) ->
6767
let conflict_state =
68-
match s with
68+
match block with
6969
| Command _ -> conflict_state
7070
| Comment lines ->
7171
(match conflict_markers with
7272
| Ignore -> conflict_state
7373
| Error -> List.fold_left lines ~init:conflict_state ~f:find_conflict)
7474
in
75-
loop (s :: acc) conflict_state
75+
loop ((loc, block) :: acc) conflict_state
7676
in
7777
loop [] `No_conflict
7878
;;
@@ -485,7 +485,7 @@ let run_cram_test env ~src ~script ~cram_stanzas ~temp_dir ~cwd ~timeout =
485485

486486
let run_produce_correction ~conflict_markers ~src ~env ~script ~timeout lexbuf =
487487
let temp_dir = make_temp_dir ~script in
488-
let cram_stanzas = cram_stanzas lexbuf ~conflict_markers in
488+
let cram_stanzas = cram_stanzas lexbuf ~conflict_markers |> List.map ~f:snd in
489489
let cwd = Path.parent_exn script in
490490
let env = make_run_env env ~temp_dir ~cwd in
491491
let open Fiber.O in
@@ -506,7 +506,7 @@ let run_and_produce_output ~conflict_markers ~src ~env ~dir:cwd ~script ~dst ~ti
506506
let script_contents = Io.read_file ~binary:false script in
507507
let lexbuf = Lexbuf.from_string script_contents ~fname:(Path.to_string script) in
508508
let temp_dir = make_temp_dir ~script in
509-
let cram_stanzas = cram_stanzas lexbuf ~conflict_markers in
509+
let cram_stanzas = cram_stanzas lexbuf ~conflict_markers |> List.map ~f:snd in
510510
(* We don't want the ".cram.run.t" dir around when executing the script. *)
511511
Path.rm_rf (Path.parent_exn script);
512512
let env = make_run_env env ~temp_dir ~cwd in
@@ -599,6 +599,7 @@ module Make_script = struct
599599
Io.read_file ~binary:false src
600600
|> Lexbuf.from_string ~fname:(Path.to_string src)
601601
|> cram_stanzas ~conflict_markers
602+
|> List.map ~f:snd
602603
|> List.filter_map ~f:(function
603604
| Cram_lexer.Comment _ -> None
604605
| Command s -> Some s)
@@ -642,6 +643,7 @@ module Diff = struct
642643
let current_stanzas =
643644
Lexbuf.from_string ~fname:(Path.to_string script) current
644645
|> cram_stanzas ~conflict_markers:Ignore
646+
|> List.map ~f:snd
645647
in
646648
let rec loop acc current expected =
647649
match current with

src/dune_rules/cram/cram_exec.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ val diff : src:Path.t -> output:Path.t -> Action.t
2323
val action : Path.t -> Action.t
2424

2525
module For_tests : sig
26-
val cram_stanzas : Lexing.lexbuf -> string list Cram_lexer.block list
26+
val cram_stanzas : Lexing.lexbuf -> (Loc.t * string list Cram_lexer.block) list
2727
val dyn_of_block : string list Cram_lexer.block -> Dyn.t
2828
end

src/dune_rules/cram/cram_lexer.mli

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
open Import
2+
13
(** .t file parser *)
24

35
(** A command or comment. Output blocks are skipped *)
46
type 'command block =
57
| Command of 'command
68
| Comment of string list
79

8-
val block : Lexing.lexbuf -> string list block option
10+
val block : Lexing.lexbuf -> (Loc.t * string list block) option

src/dune_rules/cram/cram_lexer.mll

Lines changed: 131 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,146 @@
11
{
2+
open Import
3+
24
type 'command block =
35
| Command of 'command
46
| Comment of string list
5-
}
67

7-
let eol = '\n' | eof
8+
(* Creates location from lexbuf *)
9+
let loc lexbuf =
10+
Loc.create ~start:(Lexing.lexeme_start_p lexbuf) ~stop:(Lexing.lexeme_end_p lexbuf)
11+
[@@inline]
12+
13+
(* Adjusts the start position by an offset *)
14+
let adjust_start_cnum offset loc =
15+
let start = Loc.start loc in
16+
let start = { start with pos_cnum = start.pos_cnum + offset } in
17+
Loc.set_start loc start
18+
[@@inline]
819

9-
let blank = [' ' '\t' '\r' '\012']
20+
(* Creates location for " $ " pattern, adjusting past the " $ " prefix *)
21+
let loc_of_dollar lexbuf =
22+
loc lexbuf |> adjust_start_cnum 2
23+
[@@inline]
24+
25+
(* Gets position before consuming newline *)
26+
let pos_before_newline lexbuf =
27+
let pos = Lexing.lexeme_end_p lexbuf in
28+
{ pos with pos_cnum = pos.pos_cnum - 1 }
29+
[@@inline]
30+
31+
(* Creates comment from string list accumulator *)
32+
let create_comment_from_acc loc acc =
33+
match acc with
34+
| [] -> None
35+
| _ -> Some (loc, Comment (List.rev acc))
36+
[@@inline]
37+
}
38+
39+
let nonspace = [^' ' '\n']
40+
let not_nl = [^'\n']
1041

1142
rule block = parse
1243
| eof { None }
13-
| " $ " ([^'\n']* as str) eol
14-
{ Some (command_cont [str] lexbuf) }
15-
| " " [^'\n']* eol
16-
{ output [] lexbuf }
17-
| ' '? as str eol
18-
{ comment [str] lexbuf }
19-
| ' '? [^' ' '\n'] [^'\n']* as str eol
20-
{ comment [str] lexbuf }
21-
22-
and comment acc = parse
44+
| " $ " ([^'\n']* as str)
45+
{ eol_then_command_or_finish (loc_of_dollar lexbuf) str lexbuf }
46+
| " > " ([^'\n']* as str)
47+
{ after_comment_line (loc lexbuf) [ " > " ^ str ] lexbuf }
48+
| " >"
49+
{ after_comment_line (loc lexbuf) [ " >" ] lexbuf }
50+
| " " [^'\n']*
51+
{ after_output_line (loc lexbuf) lexbuf }
52+
| ' ' ((nonspace not_nl*) as rest)
53+
{ after_comment_line (loc lexbuf) [ " " ^ rest ] lexbuf }
54+
| ' ' '\n'
55+
{ let loc = loc lexbuf in
56+
let loc = Loc.set_stop loc (pos_before_newline lexbuf) in
57+
Lexing.new_line lexbuf;
58+
comment loc [ " " ] lexbuf }
59+
| ' '
60+
{ comment (loc lexbuf) [ " " ] lexbuf }
61+
| '\n'
62+
{ let loc = loc lexbuf in
63+
let loc = Loc.set_stop loc (Loc.start loc) in
64+
Lexing.new_line lexbuf;
65+
comment loc [ "" ] lexbuf }
66+
| nonspace not_nl* as str
67+
{ after_comment_line (loc lexbuf) [str] lexbuf }
68+
69+
and after_comment_line loc content = parse
70+
| '\n' { Lexing.new_line lexbuf; comment loc content lexbuf }
71+
| eof { comment loc content lexbuf }
72+
73+
and after_output_line loc = parse
74+
| '\n' { Lexing.new_line lexbuf; output loc [] lexbuf }
75+
| eof { output loc [] lexbuf }
76+
77+
and eol_then_command_or_finish loc str = parse
78+
| '\n' { Lexing.new_line lexbuf; Some (command_cont loc [ str ] lexbuf) }
79+
| eof { Some (loc, Command [ str ]) }
80+
81+
and comment loc acc = parse
2382
| eof
24-
{ match acc with
25-
| [] -> None
26-
| _ -> Some (Comment (List.rev acc))
27-
}
28-
| ' '? as str eol
29-
{ comment (str :: acc) lexbuf }
30-
| ' '? [^' ' '\n'] [^'\n']* as str eol
31-
{ comment (str :: acc) lexbuf }
32-
| ""
33-
{ Some (Comment (List.rev acc)) }
83+
{ create_comment_from_acc loc acc }
84+
| ' ' ((nonspace not_nl*) as rest)
85+
{ let loc = Loc.set_stop loc (Lexing.lexeme_end_p lexbuf) in
86+
after_comment_line_in_comment loc (" " ^ rest) acc lexbuf }
87+
| ' ' '\n'
88+
{ let loc = Loc.set_stop loc (pos_before_newline lexbuf) in
89+
Lexing.new_line lexbuf;
90+
comment loc (" " :: acc) lexbuf }
91+
| '\n'
92+
{ let loc = Loc.set_stop loc (Lexing.lexeme_start_p lexbuf) in
93+
Lexing.new_line lexbuf;
94+
comment loc ("" :: acc) lexbuf }
95+
| nonspace not_nl* as str
96+
{ let loc = Loc.set_stop loc (Lexing.lexeme_end_p lexbuf) in
97+
after_comment_line_in_comment loc str acc lexbuf }
98+
| "" { create_comment_from_acc loc acc }
3499

35-
and output maybe_comment = parse
100+
and after_comment_line_in_comment loc str acc = parse
101+
| '\n' { Lexing.new_line lexbuf; comment loc (str :: acc) lexbuf }
102+
| eof { comment loc (str :: acc) lexbuf }
103+
104+
and output loc maybe_comment = parse
36105
| eof
37-
{ match maybe_comment with
38-
| [] -> None
39-
| l -> Some (Comment (List.rev l))
40-
}
41-
| ' ' eof
42-
{ Some (Comment (List.rev (" " :: maybe_comment))) }
43-
| " "? eof
44-
{ None }
45-
| " " eol
46-
{ output [] lexbuf }
47-
| ' '? as s eol
48-
{ output (s :: maybe_comment) lexbuf }
49-
| " $" eol
50-
{ output [] lexbuf }
51-
| " " '$' [^' ' '\n'] [^'\n']* eol
52-
{ output [] lexbuf }
53-
| " " [^'$' '\n'] [^'\n']* eol
54-
{ output [] lexbuf }
106+
{ let loc = Loc.set_stop loc (Lexing.lexeme_start_p lexbuf) in
107+
create_comment_from_acc loc maybe_comment }
108+
| " $ " ([^'\n']* as str)
109+
{ eol_then_command_or_finish (loc_of_dollar lexbuf) str lexbuf }
110+
| ' ' ((nonspace not_nl*) as rest)
111+
{ check_eol_for_output loc ((" " ^ rest) :: maybe_comment) lexbuf }
112+
| ' ' '\n'
113+
{ Lexing.new_line lexbuf;
114+
output loc (" " :: maybe_comment) lexbuf }
115+
| " " [^'\n']*
116+
{ after_output_line_in_output loc maybe_comment lexbuf }
55117
| ""
56118
{ match maybe_comment with
57-
| [] -> block lexbuf
58-
| l -> comment l lexbuf
59-
}
60-
61-
and command_cont acc = parse
62-
| " > " ([^'\n']* as str) eol
63-
{ command_cont (str :: acc) lexbuf }
64-
| " >" eol
65-
{ command_cont ("" :: acc) lexbuf }
119+
| [] -> block lexbuf
120+
| l ->
121+
let loc = Loc.set_stop loc (Lexing.lexeme_start_p lexbuf) in
122+
comment loc l lexbuf }
123+
124+
and after_output_line_in_output loc maybe_comment = parse
125+
| '\n' { Lexing.new_line lexbuf; output loc maybe_comment lexbuf }
126+
| eof { output loc maybe_comment lexbuf }
127+
128+
and check_eol_for_output loc maybe_comment = parse
129+
| '\n' { Lexing.new_line lexbuf; output loc maybe_comment lexbuf }
130+
| eof {
131+
let loc = Loc.set_stop loc (Lexing.lexeme_start_p lexbuf) in
132+
Some (loc, Comment (List.rev maybe_comment)) }
133+
134+
and command_cont loc acc = parse
135+
| " > " ([^'\n']* as str)
136+
{ let loc = Loc.set_stop loc (Lexing.lexeme_end_p lexbuf) in
137+
eol_then_continue_or_finish loc str acc lexbuf }
138+
| " >"
139+
{ let loc = Loc.set_stop loc (Lexing.lexeme_end_p lexbuf) in
140+
eol_then_continue_or_finish loc "" acc lexbuf }
66141
| ""
67-
{ Command (List.rev acc) }
142+
{ (loc, Command (List.rev acc)) }
143+
144+
and eol_then_continue_or_finish loc content acc = parse
145+
| '\n' { Lexing.new_line lexbuf; command_cont loc (content :: acc) lexbuf }
146+
| eof { (loc, Command (List.rev (content :: acc))) }

0 commit comments

Comments
 (0)