@@ -44,19 +44,41 @@ public struct ConfiguredRegions {
4444
4545 /// Determine whether the given syntax node is active within the configured
4646 /// 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.
4755 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
5265 }
5366
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
5671 }
72+
73+ // We cannot narrow the range any further.
74+ break
5775 }
5876
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
6082 }
6183}
6284
0 commit comments