@@ -44,19 +44,41 @@ public struct ConfiguredRegions {
44
44
45
45
/// Determine whether the given syntax node is active within the configured
46
46
/// regions.
47
+ ///
48
+ /// Any given node within the range of configured regions can either be
49
+ /// "active" (it is part of the program), "inactive" (it is not part of the
50
+ /// program), or "unparsed" (it is not part of the program and shouldn't
51
+ /// produce any syntax errors).
52
+ ///
53
+ /// This operation takes time that is logarthmic in the number of regions
54
+ /// in the syntax tree.
47
55
public func isActive( _ node: some SyntaxProtocol ) -> IfConfigRegionState {
48
- var currentState : IfConfigRegionState = . active
49
- for (ifClause, state) in regions {
50
- if node. position < ifClause. position {
51
- return currentState
56
+ // Find the slice of the regions in which this node lands.
57
+ var currentSlice = regions [ ... ]
58
+ while !currentSlice. isEmpty {
59
+ let middle = currentSlice. startIndex + currentSlice. count / 2
60
+
61
+ // If the node is prior to the start of the middle, take the left-hand side.
62
+ if node. position < currentSlice [ middle] . 0 . regionStart {
63
+ currentSlice = currentSlice [ ..< middle]
64
+ continue
52
65
}
53
66
54
- if node. position >= ifClause. regionStart && node. position <= ifClause. endPosition {
55
- currentState = state
67
+ // If the node is after the end of the middle, take the right-hand side.
68
+ if node. position > currentSlice [ middle] . 0 . endPosition {
69
+ currentSlice = currentSlice [ ( middle + 1 ) ... ]
70
+ continue
56
71
}
72
+
73
+ // We cannot narrow the range any further.
74
+ break
57
75
}
58
76
59
- return currentState
77
+ // Find the last region in which this node lands. If there is no such
78
+ // region, this is active.
79
+ return currentSlice. last { region in
80
+ node. position >= region. 0 . regionStart && node. position <= region. 0 . endPosition
81
+ } ? . 1 ?? . active
60
82
}
61
83
}
62
84
0 commit comments