Skip to content

Commit 227c032

Browse files
committed
Track source locations for alternation pipes
1 parent a5535f5 commit 227c032

File tree

4 files changed

+27
-8
lines changed

4 files changed

+27
-8
lines changed

Sources/_MatchingEngine/Regex/AST/AST.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,20 @@ extension AST {
9292

9393
public struct Alternation: Hashable, _ASTNode {
9494
public let children: [AST]
95-
public let location: SourceLocation
95+
public let pipes: [SourceLocation]
96+
97+
public init(_ mems: [AST], pipes: [SourceLocation]) {
98+
// An alternation must have at least two branches (though the branches
99+
// may be empty AST nodes), and n - 1 pipes.
100+
precondition(mems.count >= 2)
101+
precondition(pipes.count == mems.count - 1)
96102

97-
public init(_ mems: [AST], _ location: SourceLocation) {
98103
self.children = mems
99-
self.location = location
104+
self.pipes = pipes
105+
}
106+
107+
public var location: SourceLocation {
108+
.init(children.first!.location.start ..< children.last!.location.end)
100109
}
101110
}
102111

Sources/_MatchingEngine/Regex/Parse/Parse.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,20 @@ extension Parser {
8989

9090
if source.isEmpty { return .empty(.init(loc(_start))) }
9191

92-
var result = Array<AST>(singleElement: try parseConcatenation())
93-
while source.tryEat("|") {
94-
// TODO: track pipe locations too...
92+
var result = [try parseConcatenation()]
93+
var pipes: [SourceLocation] = []
94+
while true {
95+
let pipeStart = source.currentPosition
96+
guard source.tryEat("|") else { break }
97+
pipes.append(loc(pipeStart))
9598
result.append(try parseConcatenation())
9699
}
97100

98101
if result.count == 1 {
99102
return result[0]
100103
}
101104

102-
return .alternation(.init(result, loc(_start)))
105+
return .alternation(.init(result, pipes: pipes))
103106
}
104107

105108
/// Parse a term, potentially separated from others by `|`

Sources/_StringProcessing/ASTBuilder.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ AST.
1717
import _MatchingEngine
1818

1919
func alt(_ asts: [AST]) -> AST {
20-
.alternation(.init(asts, .fake))
20+
return .alternation(
21+
.init(asts, pipes: Array(repeating: .fake, count: asts.count - 1))
22+
)
2123
}
2224
func alt(_ asts: AST...) -> AST {
2325
alt(asts)

Tests/RegexTests/ParseTests.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,11 @@ extension RegexTests {
928928
rangeTest(alt, entireRange)
929929
rangeTest("(\(alt))", insetRange(by: 1), at: \.children![0].location)
930930
}
931+
932+
rangeTest("|", entireRange, at: { $0.as(Alt.self)!.pipes[0] })
933+
rangeTest("a|", range(1 ..< 2), at: { $0.as(Alt.self)!.pipes[0] })
934+
rangeTest("a|b", range(1 ..< 2), at: { $0.as(Alt.self)!.pipes[0] })
935+
rangeTest("|||", range(1 ..< 2), at: { $0.as(Alt.self)!.pipes[1] })
931936
}
932937

933938
func testParseErrors() {

0 commit comments

Comments
 (0)