@@ -16,6 +16,7 @@ import Swift
16
16
17
17
extension Compiler {
18
18
struct ByteCodeGen {
19
+ var reverse = false
19
20
var options : MatchingOptions
20
21
var builder = MEProgram . Builder ( )
21
22
/// A Boolean indicating whether the first matchable atom has been emitted.
@@ -135,6 +136,36 @@ fileprivate extension Compiler.ByteCodeGen {
135
136
for c in s { emitCharacter ( c) }
136
137
}
137
138
139
+ mutating func emitReverseQuotedLiteral( _ s: String ) {
140
+ guard options. semanticLevel == . graphemeCluster else {
141
+ for char in s {
142
+ for scalar in char. unicodeScalars. reversed ( ) {
143
+ emitMatchScalar ( scalar)
144
+ }
145
+ }
146
+ return
147
+ }
148
+
149
+ // Fast path for eliding boundary checks for an all ascii quoted literal
150
+ if optimizationsEnabled && s. allSatisfy ( \. isASCII) && !s. isEmpty {
151
+ builder. buildReverseUnicodeScalar ( 1 )
152
+ let lastIdx = s. unicodeScalars. indices. first!
153
+ for idx in s. unicodeScalars. indices. reversed ( ) {
154
+ let boundaryCheck = idx == lastIdx
155
+ let scalar = s. unicodeScalars [ idx]
156
+ if options. isCaseInsensitive && scalar. properties. isCased {
157
+ builder. buildReverseMatchScalarCaseInsensitive ( scalar, boundaryCheck: boundaryCheck)
158
+ } else {
159
+ builder. buildReverseMatchScalar ( scalar, boundaryCheck: boundaryCheck)
160
+ }
161
+ }
162
+ return
163
+ }
164
+
165
+ builder. buildReverse ( 1 )
166
+ for c in s. reversed ( ) { emitCharacter ( c) }
167
+ }
168
+
138
169
mutating func emitBackreference(
139
170
_ ref: AST . Reference
140
171
) throws {
@@ -189,12 +220,26 @@ fileprivate extension Compiler.ByteCodeGen {
189
220
builder. buildMatchScalar ( s, boundaryCheck: false )
190
221
}
191
222
}
192
-
223
+
224
+ mutating func emitReverseMatchScalar( _ s: UnicodeScalar ) {
225
+ assert ( options. semanticLevel == . unicodeScalar)
226
+ builder. buildReverseUnicodeScalar ( 1 )
227
+ if options. isCaseInsensitive && s. properties. isCased {
228
+ builder. buildReverseMatchScalarCaseInsensitive ( s, boundaryCheck: false )
229
+ } else {
230
+ builder. buildReverseMatchScalar ( s, boundaryCheck: false )
231
+ }
232
+ }
233
+
193
234
mutating func emitCharacter( _ c: Character ) {
194
235
// Unicode scalar mode matches the specific scalars that comprise a character
195
236
if options. semanticLevel == . unicodeScalar {
196
237
for scalar in c. unicodeScalars {
197
- emitMatchScalar ( scalar)
238
+ if reverse {
239
+ emitReverseMatchScalar ( scalar)
240
+ } else {
241
+ emitMatchScalar ( scalar)
242
+ }
198
243
}
199
244
return
200
245
}
@@ -208,20 +253,37 @@ fileprivate extension Compiler.ByteCodeGen {
208
253
c. unicodeScalars. last!,
209
254
boundaryCheck: true )
210
255
} else {
211
- builder. buildMatch ( c, isCaseInsensitive: true )
256
+ if reverse {
257
+ builder. buildReverse ( 1 )
258
+ builder. buildReverseMatch ( c, isCaseInsensitive: true )
259
+ } else {
260
+ builder. buildMatch ( c, isCaseInsensitive: true )
261
+ }
212
262
}
213
263
return
214
264
}
215
265
216
266
if optimizationsEnabled && c. isASCII {
217
267
let lastIdx = c. unicodeScalars. indices. last!
218
268
for idx in c. unicodeScalars. indices {
219
- builder. buildMatchScalar ( c. unicodeScalars [ idx] , boundaryCheck: idx == lastIdx)
269
+ let scalar = c. unicodeScalars [ idx]
270
+ let boundaryCheck = idx == lastIdx
271
+ if reverse {
272
+ builder. buildReverseUnicodeScalar ( 1 )
273
+ builder. buildReverseMatchScalar ( scalar, boundaryCheck: boundaryCheck)
274
+ } else {
275
+ builder. buildMatchScalar ( scalar, boundaryCheck: boundaryCheck)
276
+ }
220
277
}
221
278
return
222
279
}
223
280
224
- builder. buildMatch ( c, isCaseInsensitive: false )
281
+ if reverse {
282
+ builder. buildReverse ( 1 )
283
+ builder. buildReverseMatch ( c, isCaseInsensitive: false )
284
+ } else {
285
+ builder. buildMatch ( c, isCaseInsensitive: false )
286
+ }
225
287
}
226
288
227
289
mutating func emitAny( ) {
@@ -308,7 +370,7 @@ fileprivate extension Compiler.ByteCodeGen {
308
370
try emitNode ( node)
309
371
}
310
372
311
- mutating func emitPositiveLookahead ( _ child: DSLTree . Node ) throws {
373
+ mutating func emitPositiveLookaround ( _ child: DSLTree . Node ) throws {
312
374
/*
313
375
save(restoringAt: success)
314
376
save(restoringAt: intercept)
@@ -337,7 +399,7 @@ fileprivate extension Compiler.ByteCodeGen {
337
399
builder. label ( success)
338
400
}
339
401
340
- mutating func emitNegativeLookahead ( _ child: DSLTree . Node ) throws {
402
+ mutating func emitNegativeLookaround ( _ child: DSLTree . Node ) throws {
341
403
/*
342
404
save(restoringAt: success)
343
405
save(restoringAt: intercept)
@@ -365,19 +427,18 @@ fileprivate extension Compiler.ByteCodeGen {
365
427
366
428
builder. label ( success)
367
429
}
368
-
430
+
369
431
mutating func emitLookaround(
370
432
_ kind: ( forwards: Bool , positive: Bool ) ,
371
433
_ child: DSLTree . Node
372
434
) throws {
373
- guard kind. forwards else {
374
- throw Unsupported ( " backwards assertions " )
375
- }
435
+ reverse = !kind. forwards
376
436
if kind. positive {
377
- try emitPositiveLookahead ( child)
437
+ try emitPositiveLookaround ( child)
378
438
} else {
379
- try emitNegativeLookahead ( child)
439
+ try emitNegativeLookaround ( child)
380
440
}
441
+ reverse = false
381
442
}
382
443
383
444
mutating func emitAtomicNoncapturingGroup(
@@ -438,15 +499,14 @@ fileprivate extension Compiler.ByteCodeGen {
438
499
options. beginScope ( )
439
500
defer { options. endScope ( ) }
440
501
441
- if let lookaround = kind. lookaroundKind {
442
- try emitLookaround ( lookaround, child)
443
- return
444
- }
445
-
446
502
switch kind {
447
503
case . lookahead, . negativeLookahead,
448
504
. lookbehind, . negativeLookbehind:
449
- throw Unreachable ( " TODO: reason " )
505
+ guard let lookaround = kind. lookaroundKind else {
506
+ throw Unreachable ( " TODO: reason " )
507
+ }
508
+
509
+ try emitLookaround ( lookaround, child)
450
510
451
511
case . capture, . namedCapture, . balancedCapture:
452
512
throw Unreachable ( " These should produce a capture node " )
@@ -1161,7 +1221,7 @@ fileprivate extension Compiler.ByteCodeGen {
1161
1221
return [ node]
1162
1222
}
1163
1223
}
1164
- let children = children
1224
+ var children = children
1165
1225
. flatMap ( flatten)
1166
1226
. coalescing ( with: " " , into: DSLTree . Node. quotedLiteral) { str, node in
1167
1227
switch node {
@@ -1180,6 +1240,9 @@ fileprivate extension Compiler.ByteCodeGen {
1180
1240
return false
1181
1241
}
1182
1242
}
1243
+ if reverse {
1244
+ children. reverse ( )
1245
+ }
1183
1246
for child in children {
1184
1247
try emitConcatenationComponent ( child)
1185
1248
}
@@ -1188,7 +1251,6 @@ fileprivate extension Compiler.ByteCodeGen {
1188
1251
@discardableResult
1189
1252
mutating func emitNode( _ node: DSLTree . Node ) throws -> ValueRegister ? {
1190
1253
switch node {
1191
-
1192
1254
case let . orderedChoice( children) :
1193
1255
try emitAlternation ( children)
1194
1256
@@ -1256,7 +1318,11 @@ fileprivate extension Compiler.ByteCodeGen {
1256
1318
try emitAtom ( a)
1257
1319
1258
1320
case let . quotedLiteral( s) :
1259
- emitQuotedLiteral ( s)
1321
+ if reverse {
1322
+ emitReverseQuotedLiteral ( s)
1323
+ } else {
1324
+ emitQuotedLiteral ( s)
1325
+ }
1260
1326
1261
1327
case let . convertedRegexLiteral( n, _) :
1262
1328
return try emitNode ( n)
0 commit comments