33 Buffer. add_string dst (Lexing. lexeme lexbuf)
44 ;;
55
6+ let add_lexeme_opt dst lexbuf =
7+ match dst with
8+ | None -> ()
9+ | Some dst -> add_lexeme dst lexbuf
10+ ;;
11+
12+ let add_char_opt dst c =
13+ match dst with
14+ | None -> ()
15+ | Some dst -> Buffer. add_char dst c
16+ ;;
17+
618 let append_char s c =
719 let len = String. length s in
820 let bytes = Bytes. create (len + 1 ) in
3547 | "<>" -> ocaml_version <> rhs
3648 | _ -> failwith " invalid operator in [%%if]"
3749 ;;
38-
39- let update_end_depth depth = function
40- | "begin" | "object" | "sig" | "struct" -> depth + 1
41- | "end" when depth > 0 -> depth - 1
42- | _ -> depth
43- ;;
4450}
4551
4652let blank = [' ' '\t' '\n' '\r' ]*
@@ -62,14 +68,25 @@ rule pp_lex dst = parse
6268 | " let%expect_test" { skip_expect_test (pp_lex dst) 0 lexbuf }
6369 | " let%test_module" { skip_test_module (pp_lex dst) 0 lexbuf }
6470 | " [%%if" { copy_conditional dst lexbuf; pp_lex dst lexbuf }
65- | '"' { add_lexeme dst lexbuf; copy_string dst (pp_lex dst) lexbuf }
71+ | '"' {
72+ add_lexeme dst lexbuf;
73+ string_literal (Some dst) (pp_lex dst) lexbuf
74+ }
6675 | (char_literal as c) { Buffer. add_string dst c; pp_lex dst lexbuf }
6776 | '{' (quoted_string_id as id) '|'
6877 {
6978 add_lexeme dst lexbuf;
70- copy_quoted_string dst (pp_lex dst) (quoted_string_end id) " " lexbuf
79+ quoted_string
80+ (Some dst)
81+ (pp_lex dst)
82+ (quoted_string_end id)
83+ " "
84+ lexbuf
85+ }
86+ | " (*" {
87+ add_lexeme dst lexbuf;
88+ comment (Some dst) (pp_lex dst) 1 lexbuf
7189 }
72- | " (*" { add_lexeme dst lexbuf; copy_comment dst (pp_lex dst) 1 lexbuf }
7390 | _ as c { Buffer. add_char dst c; pp_lex dst lexbuf }
7491 | eof { () }
7592
@@ -78,19 +95,28 @@ and skip_expect_test k end_depth = parse
7895 {
7996 if end_depth = 0 then k lexbuf else skip_expect_test k end_depth lexbuf
8097 }
81- | '"' { skip_string (skip_expect_test k end_depth) lexbuf }
98+ | '"' { string_literal None (skip_expect_test k end_depth) lexbuf }
8299 | char_literal { skip_expect_test k end_depth lexbuf }
83100 | '{' (quoted_string_id as id) '|'
84101 {
85- skip_quoted_string
102+ quoted_string
103+ None
86104 (skip_expect_test k end_depth)
87105 (quoted_string_end id)
88106 " "
89107 lexbuf
90108 }
91- | " (*" { skip_comment (skip_expect_test k end_depth) 1 lexbuf }
92- | (lower_ident as id)
93- { skip_expect_test k (update_end_depth end_depth id) lexbuf }
109+ | " (*" { comment None (skip_expect_test k end_depth) 1 lexbuf }
110+ | (" begin" | " object" | " sig" | " struct" )
111+ { skip_expect_test k (end_depth + 1 ) lexbuf }
112+ | " end"
113+ {
114+ skip_expect_test
115+ k
116+ (if end_depth = 0 then 0 else end_depth - 1 )
117+ lexbuf
118+ }
119+ | lower_ident { skip_expect_test k end_depth lexbuf }
94120 | _ { skip_expect_test k end_depth lexbuf }
95121 | eof { failwith " unterminated let%expect_test" }
96122
@@ -102,17 +128,18 @@ and skip_test_module k depth = parse
102128 then skip_expect_test k 0 lexbuf
103129 else skip_test_module k (depth - 1 ) lexbuf
104130 }
105- | '"' { skip_string (skip_test_module k depth) lexbuf }
131+ | '"' { string_literal None (skip_test_module k depth) lexbuf }
106132 | char_literal { skip_test_module k depth lexbuf }
107133 | '{' (quoted_string_id as id) '|'
108134 {
109- skip_quoted_string
135+ quoted_string
136+ None
110137 (skip_test_module k depth)
111138 (quoted_string_end id)
112139 " "
113140 lexbuf
114141 }
115- | " (*" { skip_comment (skip_test_module k depth) 1 lexbuf }
142+ | " (*" { comment None (skip_test_module k depth) 1 lexbuf }
116143 | _ { skip_test_module k depth lexbuf }
117144 | eof { failwith " unterminated let%test_module" }
118145
@@ -164,8 +191,8 @@ and copy_branches then_branch else_branch current seen_else = parse
164191 | " [%%endif]" { () }
165192 | '"' {
166193 add_lexeme current lexbuf;
167- copy_string
168- current
194+ string_literal
195+ ( Some current)
169196 (copy_branches then_branch else_branch current seen_else)
170197 lexbuf
171198 }
@@ -177,17 +204,17 @@ and copy_branches then_branch else_branch current seen_else = parse
177204 | '{' (quoted_string_id as id) '|'
178205 {
179206 add_lexeme current lexbuf;
180- copy_quoted_string
181- current
207+ quoted_string
208+ ( Some current)
182209 (copy_branches then_branch else_branch current seen_else)
183210 (quoted_string_end id)
184211 " "
185212 lexbuf
186213 }
187214 | " (*" {
188215 add_lexeme current lexbuf;
189- copy_comment
190- current
216+ comment
217+ ( Some current)
191218 (copy_branches then_branch else_branch current seen_else)
192219 1
193220 lexbuf
@@ -199,88 +226,58 @@ and copy_branches then_branch else_branch current seen_else = parse
199226 }
200227 | eof { failwith " unterminated [%%if]" }
201228
202- and skip_string k = parse
203- | '"' { k lexbuf }
204- | '\\' _ { skip_string k lexbuf }
205- | _ { skip_string k lexbuf }
206- | eof { failwith " unterminated string literal" }
207-
208- and skip_quoted_string k terminator recent = parse
209- | _ as c
210- {
211- (* We keep a sliding suffix to recognize the closing [|id}]. This still
212- does O(String.length terminator) work per body character, so
213- [skip_quoted_string] and [copy_quoted_string] are worst-case quadratic
214- in inputs with extremely long quoted-string tags. That cost manifests
215- while scanning the body of [{|...|}] and [{id|...|id}] literals. *)
216- let next = append_char recent c in
217- if next = terminator
218- then k lexbuf
219- else
220- skip_quoted_string
221- k
222- terminator
223- (keep_recent next ~limit: (String. length terminator - 1 ))
224- lexbuf
225- }
226- | eof { failwith " unterminated quoted string literal" }
227-
228- and skip_comment k depth = parse
229- | " (*" { skip_comment k (depth + 1 ) lexbuf }
230- | " *)" {
231- if depth = 1
232- then k lexbuf
233- else skip_comment k (depth - 1 ) lexbuf
234- }
235- | _ { skip_comment k depth lexbuf }
236- | eof { failwith " unterminated comment" }
237-
238- and copy_string dst k = parse
229+ and string_literal dst k = parse
239230 | '"' {
240- add_lexeme dst lexbuf;
231+ add_lexeme_opt dst lexbuf;
241232 k lexbuf
242233 }
243- | ' \\' _ {
244- add_lexeme dst lexbuf;
245- copy_string dst k lexbuf
234+ | [ ^ '"' ' \\'] + {
235+ add_lexeme_opt dst lexbuf;
236+ string_literal dst k lexbuf
246237 }
247- | _ {
248- add_lexeme dst lexbuf;
249- copy_string dst k lexbuf
238+ | '\\' _ {
239+ add_lexeme_opt dst lexbuf;
240+ string_literal dst k lexbuf
250241 }
251242 | eof { failwith " unterminated string literal" }
252243
253- and copy_quoted_string dst k terminator recent = parse
244+ and quoted_string dst k terminator recent = parse
254245 | _ as c
255246 {
256- Buffer. add_char dst c;
247+ (* We keep a sliding suffix to recognize the closing [|id}]. This still
248+ does O(String.length terminator) work per body character, so
249+ [quoted_string] is worst-case quadratic in inputs with extremely long
250+ quoted-string tags. That cost manifests while scanning the body of
251+ [{|...|}] and [{id|...|id}] literals. *)
252+ add_char_opt dst c;
257253 let next = append_char recent c in
258254 if next = terminator
259255 then k lexbuf
260256 else
261- copy_quoted_string
262- dst
263- k
264- terminator
257+ quoted_string dst k terminator
265258 (keep_recent next ~limit: (String. length terminator - 1 ))
266259 lexbuf
267260 }
268261 | eof { failwith " unterminated quoted string literal" }
269262
270- and copy_comment dst k depth = parse
263+ and comment dst k depth = parse
271264 | " (*" {
272- add_lexeme dst lexbuf;
273- copy_comment dst k (depth + 1 ) lexbuf
265+ add_lexeme_opt dst lexbuf;
266+ comment dst k (depth + 1 ) lexbuf
274267 }
275268 | " *)" {
276- add_lexeme dst lexbuf;
269+ add_lexeme_opt dst lexbuf;
277270 if depth = 1
278271 then k lexbuf
279- else copy_comment dst k (depth - 1 ) lexbuf
272+ else comment dst k (depth - 1 ) lexbuf
273+ }
274+ | [^ '(' '*' ]+ {
275+ add_lexeme_opt dst lexbuf;
276+ comment dst k depth lexbuf
280277 }
281278 | _ {
282- add_lexeme dst lexbuf;
283- copy_comment dst k depth lexbuf
279+ add_lexeme_opt dst lexbuf;
280+ comment dst k depth lexbuf
284281 }
285282 | eof { failwith " unterminated comment" }
286283
0 commit comments