Skip to content

Commit 5c705ee

Browse files
authored
refactor(boot): simplify pps lexer states (#14406)
Unify the duplicated string, quoted-string, and comment scanners into shared lexer states, and handle begin/end-style nesting directly in skip_expect_test. This keeps the bootstrap preprocessor behavior unchanged while reducing duplicated logic in boot/pps.mll. Signed-off-by: Rudi Grinberg <me@rgrinberg.com>
1 parent d29a328 commit 5c705ee

1 file changed

Lines changed: 77 additions & 80 deletions

File tree

boot/pps.mll

Lines changed: 77 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
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
@@ -35,12 +47,6 @@
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

4652
let 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

Comments
 (0)