Skip to content

Commit f9982f0

Browse files
committed
Implement hasProgressed separately on Parser and Parser.Lookahed
This improves parsing performance by 1.5%.
1 parent ddf0b20 commit f9982f0

File tree

1 file changed

+37
-13
lines changed

1 file changed

+37
-13
lines changed

Sources/SwiftParser/LoopProgressCondition.swift

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,14 @@ struct LoopProgressCondition {
1919
var currentToken: Lexer.Lexeme?
2020

2121
init() {}
22-
}
2322

24-
extension TokenConsumer {
25-
/// Check that the token consumer has made progress since `hasProgress` was
26-
/// called the last time with this `loopProgress`.
27-
///
28-
/// In assert builds, this traps if the loop has not made any parser progress
29-
/// in between two iterations, ie. it checks if the parser's `currentToken`
30-
/// has changed in between two calls to `evaluate`.
31-
/// In non-assert builds, `evaluate()` returns `false` if the loop has not made
32-
/// progress, thus aborting the loop.
33-
func hasProgressed(_ loopProgress: inout LoopProgressCondition) -> Bool {
23+
/// Implementation of the above `evaluate` methods.
24+
fileprivate mutating func evaluate(_ currentToken: Lexer.Lexeme) -> Bool {
3425
defer {
35-
loopProgress.currentToken = currentToken
26+
self.currentToken = currentToken
3627
}
3728

38-
guard let previousToken = loopProgress.currentToken else {
29+
guard let previousToken = self.currentToken else {
3930
return true
4031
}
4132
// The loop has made progress if either
@@ -50,3 +41,36 @@ extension TokenConsumer {
5041
return hasMadeProgress
5142
}
5243
}
44+
45+
// Implementing the extension separately on `Parser` and `Parser.Lookahead` is
46+
// ~1.5% faster than implementing it on `TokenConsumer`.
47+
48+
extension Parser {
49+
/// Check that the token consumer has made progress since `hasProgress` was
50+
/// called the last time with this `loopProgress`.
51+
///
52+
/// In assert builds, this traps if the loop has not made any parser progress
53+
/// in between two iterations, ie. it checks if the parser's `currentToken`
54+
/// has changed in between two calls to `evaluate`.
55+
/// In non-assert builds, `evaluate()` returns `false` if the loop has not made
56+
/// progress, thus aborting the loop.
57+
@inline(__always)
58+
func hasProgressed(_ loopProgress: inout LoopProgressCondition) -> Bool {
59+
return loopProgress.evaluate(self.currentToken)
60+
}
61+
}
62+
63+
extension Parser.Lookahead {
64+
/// Check that the token consumer has made progress since `hasProgress` was
65+
/// called the last time with this `loopProgress`.
66+
///
67+
/// In assert builds, this traps if the loop has not made any parser progress
68+
/// in between two iterations, ie. it checks if the parser's `currentToken`
69+
/// has changed in between two calls to `evaluate`.
70+
/// In non-assert builds, `evaluate()` returns `false` if the loop has not made
71+
/// progress, thus aborting the loop.
72+
@inline(__always)
73+
func hasProgressed(_ loopProgress: inout LoopProgressCondition) -> Bool {
74+
return loopProgress.evaluate(self.currentToken)
75+
}
76+
}

0 commit comments

Comments
 (0)