Skip to content

Commit 838bdfe

Browse files
authored
Simplify capture representations (#360)
Introduce CaptureList, make CaptureStructure semi-vestigial
1 parent b7fb965 commit 838bdfe

File tree

16 files changed

+457
-537
lines changed

16 files changed

+457
-537
lines changed

Sources/PatternConverter/PatternConverter.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ struct PatternConverter: ParsableCommand {
3030
@Flag(help: "Whether to show canonical regex literal")
3131
var showCanonical: Bool = false
3232

33-
@Flag(help: "Whether to show capture structure")
34-
var showCaptureStructure: Bool = false
35-
3633
@Flag(help: "Whether to skip result builder DSL")
3734
var skipDSL: Bool = false
3835

@@ -71,13 +68,6 @@ struct PatternConverter: ParsableCommand {
7168
print()
7269
}
7370

74-
if showCaptureStructure {
75-
print("Capture structure:")
76-
print()
77-
print(ast.captureStructure)
78-
print()
79-
}
80-
8171
print()
8272
if !skipDSL {
8373
let render = ast.renderAsBuilderDSL(

Sources/_RegexParser/Regex/AST/AST.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,6 @@ public struct AST: Hashable {
2525
extension AST {
2626
/// Whether this AST tree contains at least one capture nested inside of it.
2727
public var hasCapture: Bool { root.hasCapture }
28-
29-
/// The capture structure of this AST tree.
30-
public var captureStructure: CaptureStructure {
31-
var constructor = CaptureStructure.Constructor(.flatten)
32-
return root._captureStructure(&constructor)
33-
}
3428
}
3529

3630
extension AST {
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
public struct CaptureList {
13+
public var captures: [Capture]
14+
15+
public init<S: Sequence>(_ s: S) where S.Element == Capture {
16+
captures = Array(s)
17+
}
18+
19+
public mutating func append(_ c: Capture) {
20+
captures.append(c)
21+
}
22+
}
23+
24+
extension CaptureList {
25+
public struct Capture {
26+
public var name: String?
27+
public var type: Any.Type?
28+
public var optionalDepth: Int
29+
30+
public init(
31+
name: String? = nil,
32+
type: Any.Type? = nil,
33+
optionalDepth: Int
34+
) {
35+
self.name = name
36+
self.type = type
37+
self.optionalDepth = optionalDepth
38+
}
39+
}
40+
}
41+
42+
// MARK: Generating from AST
43+
44+
extension AST.Node {
45+
public func _addCaptures(
46+
to list: inout CaptureList,
47+
optionalNesting nesting: Int
48+
) {
49+
let addOptional = nesting+1
50+
switch self {
51+
case let .alternation(a):
52+
for child in a.children {
53+
child._addCaptures(to: &list, optionalNesting: addOptional)
54+
}
55+
56+
case let .concatenation(c):
57+
for child in c.children {
58+
child._addCaptures(to: &list, optionalNesting: nesting)
59+
}
60+
61+
case let .group(g):
62+
switch g.kind.value {
63+
case .capture:
64+
list.append(.init(optionalDepth: nesting))
65+
66+
case .namedCapture(let name):
67+
list.append(.init(name: name.value, optionalDepth: nesting))
68+
69+
case .balancedCapture(let b):
70+
list.append(.init(name: b.name?.value, optionalDepth: nesting))
71+
72+
default: break
73+
}
74+
g.child._addCaptures(to: &list, optionalNesting: nesting)
75+
76+
case .conditional(let c):
77+
switch c.condition.kind {
78+
case .group(let g):
79+
AST.Node.group(g)._addCaptures(to: &list, optionalNesting: nesting)
80+
default:
81+
break
82+
}
83+
84+
c.trueBranch._addCaptures(to: &list, optionalNesting: addOptional)
85+
c.falseBranch._addCaptures(to: &list, optionalNesting: addOptional)
86+
87+
case .quantification(let q):
88+
var optNesting = nesting
89+
if q.amount.value.bounds.atLeast == 0 {
90+
optNesting += 1
91+
}
92+
q.child._addCaptures(to: &list, optionalNesting: optNesting)
93+
94+
case .absentFunction(let abs):
95+
switch abs.kind {
96+
case .expression(_, _, let child):
97+
child._addCaptures(to: &list, optionalNesting: nesting)
98+
case .clearer, .repeater, .stopper:
99+
break
100+
}
101+
102+
case .quote, .trivia, .atom, .customCharacterClass, .empty:
103+
break
104+
}
105+
}
106+
107+
public var _captureList: CaptureList {
108+
var caps = CaptureList()
109+
self._addCaptures(to: &caps, optionalNesting: 0)
110+
return caps
111+
}
112+
}
113+
114+
extension AST {
115+
/// Get the capture list for this AST
116+
public var captureList: CaptureList {
117+
root._captureList
118+
}
119+
}
120+
121+
// MARK: Convenience for testing and inspection
122+
123+
extension CaptureList.Capture: Equatable {
124+
public static func == (lhs: Self, rhs: Self) -> Bool {
125+
lhs.name == rhs.name &&
126+
lhs.optionalDepth == rhs.optionalDepth &&
127+
lhs.type == rhs.type
128+
}
129+
}
130+
extension CaptureList: Equatable {}
131+
132+
extension CaptureList.Capture: CustomStringConvertible {
133+
public var description: String {
134+
let typeStr: String
135+
if let ty = type {
136+
typeStr = "\(ty)"
137+
} else {
138+
typeStr = "Substring"
139+
}
140+
let suffix = String(repeating: "?", count: optionalDepth)
141+
return typeStr + suffix
142+
}
143+
}
144+
extension CaptureList: CustomStringConvertible {
145+
public var description: String {
146+
"(" + captures.map(\.description).joined(separator: ", ") + ")"
147+
}
148+
}
149+
150+
extension CaptureList: ExpressibleByArrayLiteral {
151+
public init(arrayLiteral elements: Capture...) {
152+
self.init(elements)
153+
}
154+
}

0 commit comments

Comments
 (0)