Skip to content

Commit 01e94a1

Browse files
committed
Implement skipSingle and skipUntil without recursion
1 parent 1bf320a commit 01e94a1

File tree

1 file changed

+87
-60
lines changed

1 file changed

+87
-60
lines changed

Sources/SwiftParser/Lookahead.swift

Lines changed: 87 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,7 @@ extension Parser.Lookahead {
335335

336336
extension Parser.Lookahead {
337337
mutating func skipUntil(_ t1: RawTokenKind, _ t2: RawTokenKind) {
338-
while !self.at(any: [.eof, t1, t2, .poundEndifKeyword, .poundElseKeyword, .poundElseifKeyword]) {
339-
self.skipSingle()
340-
}
338+
return skip(initialState: .skipUntil(t1, t2))
341339
}
342340

343341
mutating func skipUntilEndOfLine() {
@@ -347,70 +345,99 @@ extension Parser.Lookahead {
347345
}
348346

349347
mutating func skipSingle() {
350-
enum BracketedTokens: RawTokenKindSubset {
351-
case leftParen
352-
case leftBrace
353-
case leftSquareBracket
354-
case poundIfKeyword
355-
case poundElseKeyword
356-
case poundElseifKeyword
357-
358-
init?(lexeme: Lexer.Lexeme) {
359-
switch lexeme.tokenKind {
360-
case .leftParen: self = .leftParen
361-
case .leftBrace: self = .leftBrace
362-
case .leftSquareBracket: self = .leftSquareBracket
363-
case .poundIfKeyword: self = .poundIfKeyword
364-
case .poundElseKeyword: self = .poundElseKeyword
365-
case .poundElseifKeyword: self = .poundElseifKeyword
366-
default: return nil
367-
}
348+
return skip(initialState: .skipSingle)
349+
}
350+
351+
private enum BracketedTokens: RawTokenKindSubset {
352+
case leftParen
353+
case leftBrace
354+
case leftSquareBracket
355+
case poundIfKeyword
356+
case poundElseKeyword
357+
case poundElseifKeyword
358+
359+
init?(lexeme: Lexer.Lexeme) {
360+
switch lexeme.tokenKind {
361+
case .leftParen: self = .leftParen
362+
case .leftBrace: self = .leftBrace
363+
case .leftSquareBracket: self = .leftSquareBracket
364+
case .poundIfKeyword: self = .poundIfKeyword
365+
case .poundElseKeyword: self = .poundElseKeyword
366+
case .poundElseifKeyword: self = .poundElseifKeyword
367+
default: return nil
368368
}
369+
}
369370

370-
var rawTokenKind: RawTokenKind {
371-
switch self {
372-
case .leftParen: return .leftParen
373-
case .leftBrace: return .leftBrace
374-
case .leftSquareBracket: return .leftSquareBracket
375-
case .poundIfKeyword: return .poundIfKeyword
376-
case .poundElseKeyword: return .poundElseKeyword
377-
case .poundElseifKeyword: return .poundElseifKeyword
378-
}
371+
var rawTokenKind: RawTokenKind {
372+
switch self {
373+
case .leftParen: return .leftParen
374+
case .leftBrace: return .leftBrace
375+
case .leftSquareBracket: return .leftSquareBracket
376+
case .poundIfKeyword: return .poundIfKeyword
377+
case .poundElseKeyword: return .poundElseKeyword
378+
case .poundElseifKeyword: return .poundElseifKeyword
379379
}
380380
}
381+
}
381382

382-
switch self.at(anyIn: BracketedTokens.self) {
383-
case (.leftParen, let handle)?:
384-
self.eat(handle)
385-
self.skipUntil(.rightParen, .rightBrace)
386-
self.consume(if: .rightParen)
387-
return
388-
case (.leftBrace, let handle)?:
389-
self.eat(handle)
390-
self.skipUntil(.rightBrace, .rightBrace)
391-
self.consume(if: .rightBrace)
392-
return
393-
case (.leftSquareBracket, let handle)?:
394-
self.eat(handle)
395-
self.skipUntil(.rightSquareBracket, .rightSquareBracket)
396-
self.consume(if: .rightSquareBracket)
397-
return
398-
case (.poundIfKeyword, let handle)?,
399-
(.poundElseKeyword, let handle)?,
400-
(.poundElseifKeyword, let handle)?:
401-
self.eat(handle)
402-
// skipUntil also implicitly stops at tok::pound_endif.
403-
self.skipUntil(.poundElseKeyword, .poundElseifKeyword)
383+
private enum SkippingState {
384+
/// Equivalent to a call to `skipSingle`. Skip a single token.
385+
/// If that token is bracketed, skip until the closing bracket
386+
case skipSingle
387+
/// Execute code after skipping bracketed tokens detected from `skipSingle`.
388+
case skipSinglePost(start: BracketedTokens)
389+
/// Skip until either `t1` or `t2`.
390+
case skipUntil(_ t1: RawTokenKind, _ t2: RawTokenKind)
391+
}
404392

405-
if self.at(any: [.poundElseKeyword, .poundElseifKeyword]) {
406-
self.skipSingle()
407-
} else {
408-
self.consume(if: .poundElseifKeyword)
393+
/// A non-recursie function to skip tokens.
394+
private mutating func skip(initialState: SkippingState) {
395+
var stack: [SkippingState] = [initialState]
396+
397+
while let state = stack.popLast() {
398+
switch state {
399+
case .skipSingle:
400+
let t = self.at(anyIn: BracketedTokens.self)
401+
switch t {
402+
case (.leftParen, let handle)?:
403+
self.eat(handle)
404+
stack += [.skipSinglePost(start: .leftParen), .skipUntil(.rightParen, .rightBrace)]
405+
case (.leftBrace, let handle)?:
406+
self.eat(handle)
407+
stack += [.skipSinglePost(start: .leftBrace), .skipUntil(.rightBrace, .rightBrace)]
408+
case (.leftSquareBracket, let handle)?:
409+
self.eat(handle)
410+
stack += [.skipSinglePost(start: .leftSquareBracket), .skipUntil(.rightSquareBracket, .rightSquareBracket)]
411+
case (.poundIfKeyword, let handle)?,
412+
(.poundElseKeyword, let handle)?,
413+
(.poundElseifKeyword, let handle)?:
414+
self.eat(handle)
415+
// skipUntil also implicitly stops at tok::pound_endif.
416+
stack += [.skipSinglePost(start: t!.0), .skipUntil(.poundElseKeyword, .poundElseifKeyword)]
417+
case nil:
418+
self.consumeAnyToken()
419+
}
420+
case .skipSinglePost(start: let start):
421+
switch start {
422+
case .leftParen:
423+
self.consume(if: .rightParen)
424+
case .leftBrace:
425+
self.consume(if: .rightBrace)
426+
case .leftSquareBracket:
427+
self.consume(if: .rightSquareBracket)
428+
case .poundIfKeyword, .poundElseKeyword, .poundElseifKeyword:
429+
if self.at(any: [.poundElseKeyword, .poundElseifKeyword]) {
430+
stack += [.skipSingle]
431+
} else {
432+
self.consume(if: .poundElseifKeyword)
433+
}
434+
return
435+
}
436+
case .skipUntil(let t1, let t2):
437+
if !self.at(any: [.eof, t1, t2, .poundEndifKeyword, .poundElseKeyword, .poundElseifKeyword]) {
438+
stack += [.skipUntil(t1, t2), .skipSingle]
439+
}
409440
}
410-
return
411-
case nil:
412-
self.consumeAnyToken()
413-
return
414441
}
415442
}
416443
}

0 commit comments

Comments
 (0)