Skip to content

Generic Reference type and match result subscript #182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 86 additions & 28 deletions Sources/VariadicsGenerator/VariadicsGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,7 @@ var standardError = StandardErrorStream()

typealias Counter = Int64
let regexProtocolName = "RegexProtocol"
let concatenationStructTypeBaseName = "Concatenate"
let capturingGroupTypeBaseName = "CapturingGroup"
let matchAssociatedTypeName = "Match"
let captureAssociatedTypeName = "Capture"
let patternBuilderTypeName = "RegexBuilder"
let patternProtocolRequirementName = "regex"
let regexTypeName = "Regex"
Expand Down Expand Up @@ -535,108 +532,169 @@ struct VariadicsGenerator: ParsableCommand {
: "(\(baseMatchTypeName), \(newCaptureType), " + (0..<arity).map { "C\($0)" }.joined(separator: ", ") + ")"
}
let whereClause = "where R.\(matchAssociatedTypeName) == \(matchType)"
let rawNewMatchType = newMatchType(newCaptureType: "W")
let transformedNewMatchType = newMatchType(newCaptureType: "NewCapture")
output("""
// MARK: - Non-builder capture arity \(arity)

public func capture<\(genericParams)>(
_ component: R, as reference: Reference? = nil
) -> \(regexTypeName)<\(newMatchType(newCaptureType: "W"))> \(whereClause) {
.init(node: .group(.capture, component.regex.root, reference?.id))
_ component: R
) -> \(regexTypeName)<\(rawNewMatchType)> \(whereClause) {
.init(node: .group(.capture, component.regex.root))
}

public func capture<\(genericParams)>(
_ component: R, as reference: Reference<W>
) -> \(regexTypeName)<\(rawNewMatchType)> \(whereClause) {
.init(node: .group(.capture, component.regex.root, reference.id))
}

public func capture<\(genericParams), NewCapture>(
_ component: R,
transform: @escaping (Substring) -> NewCapture
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component.regex.root,
CaptureTransform(resultType: NewCapture.self) {
transform($0) as Any
}))
}

public func capture<\(genericParams), NewCapture>(
_ component: R,
as reference: Reference? = nil,
as reference: Reference<NewCapture>,
transform: @escaping (Substring) -> NewCapture
) -> \(regexTypeName)<\(newMatchType(newCaptureType: "NewCapture"))> \(whereClause) {
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component.regex.root,
CaptureTransform(resultType: NewCapture.self) {
transform($0) as Any
},
reference?.id))
reference.id))
}

public func tryCapture<\(genericParams), NewCapture>(
_ component: R,
as reference: Reference? = nil,
transform: @escaping (Substring) throws -> NewCapture
) -> \(regexTypeName)<\(newMatchType(newCaptureType: "NewCapture"))> \(whereClause) {
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component.regex.root,
CaptureTransform(resultType: NewCapture.self) {
try transform($0) as Any
}))
}

public func tryCapture<\(genericParams), NewCapture>(
_ component: R,
as reference: Reference<NewCapture>,
transform: @escaping (Substring) throws -> NewCapture
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component.regex.root,
CaptureTransform(resultType: NewCapture.self) {
try transform($0) as Any
},
reference?.id))
reference.id))
}

public func tryCapture<\(genericParams), NewCapture>(
_ component: R,
as reference: Reference? = nil,
transform: @escaping (Substring) -> NewCapture?
) -> \(regexTypeName)<\(newMatchType(newCaptureType: "NewCapture"))> \(whereClause) {
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component.regex.root,
CaptureTransform(resultType: NewCapture.self) {
transform($0) as Any?
}))
}

public func tryCapture<\(genericParams), NewCapture>(
_ component: R,
as reference: Reference<NewCapture>,
transform: @escaping (Substring) -> NewCapture?
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component.regex.root,
CaptureTransform(resultType: NewCapture.self) {
transform($0) as Any?
},
reference?.id))
reference.id))
}

// MARK: - Builder capture arity \(arity)

public func capture<\(genericParams)>(
as reference: Reference? = nil,
@RegexBuilder _ component: () -> R
) -> \(regexTypeName)<\(newMatchType(newCaptureType: "W"))> \(whereClause) {
.init(node: .group(.capture, component().regex.root, reference?.id))
) -> \(regexTypeName)<\(rawNewMatchType)> \(whereClause) {
.init(node: .group(.capture, component().regex.root))
}

public func capture<\(genericParams)>(
as reference: Reference<W>,
@RegexBuilder _ component: () -> R
) -> \(regexTypeName)<\(rawNewMatchType)> \(whereClause) {
.init(node: .group(.capture, component().regex.root, reference.id))
}

public func capture<\(genericParams), NewCapture>(
as reference: Reference? = nil,
@RegexBuilder _ component: () -> R,
transform: @escaping (Substring) -> NewCapture
) -> \(regexTypeName)<\(newMatchType(newCaptureType: "NewCapture"))> \(whereClause) {
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component().regex.root,
CaptureTransform(resultType: NewCapture.self) {
transform($0) as Any
},
reference?.id))
}))
}

public func tryCapture<\(genericParams), NewCapture>(
as reference: Reference? = nil,
as reference: Reference<NewCapture>,
@RegexBuilder _ component: () -> R,
transform: @escaping (Substring) throws -> NewCapture
) -> \(regexTypeName)<\(newMatchType(newCaptureType: "NewCapture"))> \(whereClause) {
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component().regex.root,
CaptureTransform(resultType: NewCapture.self) {
try transform($0) as Any
},
reference?.id))
reference.id))
}

public func tryCapture<\(genericParams), NewCapture>(
@RegexBuilder _ component: () -> R,
transform: @escaping (Substring) -> NewCapture?
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component().regex.root,
CaptureTransform(resultType: NewCapture.self) {
transform($0) as Any?
}))
}

public func tryCapture<\(genericParams), NewCapture>(
as reference: Reference? = nil,
as reference: Reference<NewCapture>,
@RegexBuilder _ component: () -> R,
transform: @escaping (Substring) -> NewCapture?
) -> \(regexTypeName)<\(newMatchType(newCaptureType: "NewCapture"))> \(whereClause) {
) -> \(regexTypeName)<\(transformedNewMatchType)> \(whereClause) {
.init(node: .groupTransform(
.capture,
component().regex.root,
CaptureTransform(resultType: NewCapture.self) {
transform($0) as Any?
},
reference?.id))
reference.id))
}


""")
}
}
2 changes: 1 addition & 1 deletion Sources/_StringProcessing/ByteCodeGen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ extension Compiler.ByteCodeGen {
mutating func emitGroup(
_ kind: AST.Group.Kind,
_ child: DSLTree.Node,
_ referenceID: Reference.ID?
_ referenceID: ReferenceID?
) throws -> CaptureRegister? {
guard kind.isCapturing || referenceID == nil else {
throw Unreachable("Reference ID shouldn't exist for non-capturing groups")
Expand Down
6 changes: 4 additions & 2 deletions Sources/_StringProcessing/Capture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ func constructExistentialMatchComponent(
underlying = Optional<Any>(nil) as Any
someCount = optionalCount - 1
}

for _ in 0..<someCount {
underlying = Optional(underlying) as Any
func wrap<T>(_ x: T) {
underlying = Optional(x) as Any
}
_openExistential(underlying, do: wrap)
}
return underlying
}
Expand Down
3 changes: 2 additions & 1 deletion Sources/_StringProcessing/Engine/Consume.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ extension Engine where Input == String {
guard let result = result else { return nil }

let capList = cpu.storedCaptures
return (result, CaptureList(caps: capList))
return (result, CaptureList(
values: capList, referencedCaptureOffsets: program.referencedCaptureOffsets))
}
}

15 changes: 8 additions & 7 deletions Sources/_StringProcessing/Engine/MEBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ extension MEProgram where Input.Element: Hashable {
var captureStructure: CaptureStructure = .empty

// Symbolic reference resolution
var unresolvedReferences: [Reference.ID: [InstructionAddress]] = [:]
var captureOffsets: [Reference.ID: Int] = [:]
var unresolvedReferences: [ReferenceID: [InstructionAddress]] = [:]
var referencedCaptureOffsets: [ReferenceID: Int] = [:]
var captureCount: Int {
// We currently deduce the capture count from the capture register number.
nextCaptureRegister.rawValue
Expand Down Expand Up @@ -274,7 +274,7 @@ extension MEProgram.Builder {
.init(.backreference, .init(capture: cap)))
}

public mutating func buildUnresolvedReference(id: Reference.ID) {
public mutating func buildUnresolvedReference(id: ReferenceID) {
buildBackreference(.init(0))
unresolvedReferences[id, default: []].append(lastInstructionAddress)
}
Expand Down Expand Up @@ -352,7 +352,8 @@ extension MEProgram.Builder {
staticTransformFunctions: transformFunctions,
staticMatcherFunctions: matcherFunctions,
registerInfo: regInfo,
captureStructure: captureStructure)
captureStructure: captureStructure,
referencedCaptureOffsets: referencedCaptureOffsets)
}

public mutating func reset() { self = Self() }
Expand Down Expand Up @@ -424,7 +425,7 @@ extension MEProgram.Builder {
fileprivate extension MEProgram.Builder {
mutating func resolveReferences() throws {
for (id, uses) in unresolvedReferences {
guard let offset = captureOffsets[id] else {
guard let offset = referencedCaptureOffsets[id] else {
throw RegexCompilationError.uncapturedReference
}
for use in uses {
Expand All @@ -437,11 +438,11 @@ fileprivate extension MEProgram.Builder {

// Register helpers
extension MEProgram.Builder {
public mutating func makeCapture(id: Reference.ID?) -> CaptureRegister {
public mutating func makeCapture(id: ReferenceID?) -> CaptureRegister {
defer { nextCaptureRegister.rawValue += 1 }
// Register the capture for later lookup via symbolic references.
if let id = id {
let preexistingValue = captureOffsets.updateValue(
let preexistingValue = referencedCaptureOffsets.updateValue(
captureCount, forKey: id)
assert(preexistingValue == nil)
}
Expand Down
5 changes: 3 additions & 2 deletions Sources/_StringProcessing/Engine/MECapture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,15 @@ extension Processor._StoredCapture: CustomStringConvertible {
}

public struct CaptureList {
var caps: Array<Processor<String>._StoredCapture>
var values: Array<Processor<String>._StoredCapture>
var referencedCaptureOffsets: [ReferenceID: Int]

// func extract(from s: String) -> Array<Array<Substring>> {
// caps.map { $0.map { s[$0] } }
// }
//
func latestUntyped(from s: String) -> Array<Substring?> {
caps.map {
values.map {
guard let last = $0.latest else {
return nil
}
Expand Down
1 change: 1 addition & 0 deletions Sources/_StringProcessing/Engine/MEProgram.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public struct MEProgram<Input: Collection> where Input.Element: Equatable {
var enableTracing: Bool = false

let captureStructure: CaptureStructure
let referencedCaptureOffsets: [ReferenceID: Int]
}

extension MEProgram: CustomStringConvertible {
Expand Down
2 changes: 2 additions & 0 deletions Sources/_StringProcessing/Engine/Processor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public enum MatchMode {
case partialFromFront
}

typealias Program = MEProgram<String>

/// A concrete CU. Somehow will run the concrete logic and
/// feed stuff back to generic code
struct Controller {
Expand Down
33 changes: 0 additions & 33 deletions Sources/_StringProcessing/Engine/StringProcessor.swift

This file was deleted.

10 changes: 5 additions & 5 deletions Sources/_StringProcessing/Engine/Structuralize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ extension CaptureStructure {
}

switch self {
case let .tuple(caps):
assert(list.caps.count == caps.count)
case let .tuple(values):
assert(list.values.count == values.count)
var result = Array<StructuredCapture>()
for (cap, storedCap) in zip(caps, list.caps) {
for (cap, storedCap) in zip(values, list.values) {
result.append(mapCap(cap, storedCap))
}
return result

default:
assert(list.caps.count == 1)
return [mapCap(self, list.caps.first!)]
assert(list.values.count == 1)
return [mapCap(self, list.values.first!)]
}
}
}
Loading