@@ -113,6 +113,22 @@ extension Source {
113
113
try tryEatNonEmpty ( sequence: String ( c) )
114
114
}
115
115
116
+ /// Attempt to make a series of lexing steps in `body`, returning `nil` if
117
+ /// unsuccesful, which will revert the source back to its previous state. If
118
+ /// an error is thrown, the source will not be reverted.
119
+ mutating func tryEating< T> (
120
+ _ body: ( inout Source ) throws -> T ?
121
+ ) rethrows -> T ? {
122
+ // We don't revert the source if an error is thrown, as it's useful to
123
+ // maintain the source location in that case.
124
+ let current = self
125
+ guard let result = try body ( & self ) else {
126
+ self = current
127
+ return nil
128
+ }
129
+ return result
130
+ }
131
+
116
132
/// Throws an expected ASCII character error if not matched
117
133
mutating func expectASCII( ) throws -> Located < Character > {
118
134
try recordLoc { src in
@@ -296,16 +312,11 @@ extension Source {
296
312
if src. tryEat ( " + " ) { return . oneOrMore }
297
313
if src. tryEat ( " ? " ) { return . zeroOrOne }
298
314
299
- // FIXME: Actually, PCRE treats empty as literal `{}`...
300
- // But Java 8 errors out?
301
- if src. tryEat ( " { " ) {
302
- // FIXME: Erm, PCRE parses as literal if no lowerbound...
303
- let amt = try src. expectRange ( )
304
- try src. expect ( " } " )
305
- return amt. value // FIXME: track actual range...
315
+ return try src. tryEating { src in
316
+ guard src. tryEat ( " { " ) , let range = try src. lexRange ( ) , src. tryEat ( " } " )
317
+ else { return nil }
318
+ return range. value
306
319
}
307
-
308
- return nil
309
320
}
310
321
guard let amt = amt else { return nil }
311
322
@@ -318,56 +329,56 @@ extension Source {
318
329
return ( amt, kind)
319
330
}
320
331
321
- /// Consume a range
332
+ /// Try to consume a range, returning `nil` if unsuccessful.
322
333
///
323
334
/// Range -> ',' <Int> | <Int> ',' <Int>? | <Int>
324
335
/// | ExpRange
325
336
/// ExpRange -> '..<' <Int> | '...' <Int>
326
337
/// | <Int> '..<' <Int> | <Int> '...' <Int>?
327
- mutating func expectRange ( ) throws -> Located < Quant . Amount > {
338
+ mutating func lexRange ( ) throws -> Located < Quant . Amount > ? {
328
339
try recordLoc { src in
329
- // TODO: lex positive numbers, more specifically...
330
-
331
- let lowerOpt = try src. lexNumber ( )
332
-
333
- // ',' or '...' or '..<' or nothing
334
- let closedRange : Bool ?
335
- if src. tryEat ( " , " ) {
336
- closedRange = true
337
- } else if src. experimentalRanges && src. tryEat ( " . " ) {
338
- try src. expect ( " . " )
339
- if src. tryEat ( " . " ) {
340
+ try src. tryEating { src in
341
+ let lowerOpt = try src. lexNumber ( )
342
+
343
+ // ',' or '...' or '..<' or nothing
344
+ // TODO: We ought to try and consume whitespace here and emit a
345
+ // diagnostic for the user warning them that it would cause the range to
346
+ // be treated as literal.
347
+ let closedRange : Bool ?
348
+ if src. tryEat ( " , " ) {
340
349
closedRange = true
350
+ } else if src. experimentalRanges && src. tryEat ( " . " ) {
351
+ try src. expect ( " . " )
352
+ if src. tryEat ( " . " ) {
353
+ closedRange = true
354
+ } else {
355
+ try src. expect ( " < " )
356
+ closedRange = false
357
+ }
341
358
} else {
342
- try src. expect ( " < " )
343
- closedRange = false
359
+ closedRange = nil
344
360
}
345
- } else {
346
- closedRange = nil
347
- }
348
- // FIXME: wait, why `try!` ?
349
- let upperOpt : Located < Int > ?
350
- if let u = try ! src. lexNumber ( ) {
351
- upperOpt = ( closedRange == true ) ? u : Located ( u. value- 1 , u. location)
352
- } else {
353
- upperOpt = nil
354
- }
355
361
356
- switch ( lowerOpt, closedRange, upperOpt) {
357
- case let ( l? , nil , nil ) :
358
- return . exactly( l)
359
- case let ( l? , true , nil ) :
360
- return . nOrMore( l)
361
- case let ( nil , _, u? ) :
362
- return . upToN( u)
363
- case let ( l? , _, u? ) :
364
- // FIXME: source location tracking
365
- return . range( l, u)
366
-
367
- case let ( nil , nil , u) where u != nil :
368
- fatalError ( " Not possible " )
369
- default :
370
- throw ParseError . misc ( " Invalid range " )
362
+ let upperOpt = try src. lexNumber ( ) ? . map { upper in
363
+ // If we have an open range, the upper bound should be adjusted down.
364
+ closedRange == true ? upper : upper - 1
365
+ }
366
+
367
+ switch ( lowerOpt, closedRange, upperOpt) {
368
+ case let ( l? , nil , nil ) :
369
+ return . exactly( l)
370
+ case let ( l? , true , nil ) :
371
+ return . nOrMore( l)
372
+ case let ( nil , _? , u? ) :
373
+ return . upToN( u)
374
+ case let ( l? , _? , u? ) :
375
+ return . range( l, u)
376
+
377
+ case ( nil , nil , _? ) :
378
+ fatalError ( " Didn't lex lower bound, but lexed upper bound? " )
379
+ default :
380
+ return nil
381
+ }
371
382
}
372
383
}
373
384
}
0 commit comments