Skip to content

Implement .as for Regex and Unify Match and AnyRegexOutput #376

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 5 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
103 changes: 42 additions & 61 deletions Sources/_RegexParser/Utility/TypeConstruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,7 @@
// const Metadata * const *elements,
// const char *labels,
// const ValueWitnessTable *proposedWitnesses);
//
// SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
// MetadataResponse
// swift_getTupleTypeMetadata2(MetadataRequest request,
// const Metadata *elt0, const Metadata *elt1,
// const char *labels,
// const ValueWitnessTable *proposedWitnesses);
// SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
// MetadataResponse
// swift_getTupleTypeMetadata3(MetadataRequest request,
// const Metadata *elt0, const Metadata *elt1,
// const Metadata *elt2, const char *labels,
// const ValueWitnessTable *proposedWitnesses);


@_silgen_name("swift_getTupleTypeMetadata")
private func swift_getTupleTypeMetadata(
Expand All @@ -40,31 +28,13 @@ private func swift_getTupleTypeMetadata(
proposedWitnesses: UnsafeRawPointer?
) -> (value: Any.Type, state: Int)

@_silgen_name("swift_getTupleTypeMetadata2")
private func swift_getTupleTypeMetadata2(
request: Int,
element1: Any.Type,
element2: Any.Type,
labels: UnsafePointer<Int8>?,
proposedWitnesses: UnsafeRawPointer?
) -> (value: Any.Type, state: Int)

@_silgen_name("swift_getTupleTypeMetadata3")
private func swift_getTupleTypeMetadata3(
request: Int,
element1: Any.Type,
element2: Any.Type,
element3: Any.Type,
labels: UnsafePointer<Int8>?,
proposedWitnesses: UnsafeRawPointer?
) -> (value: Any.Type, state: Int)

public enum TypeConstruction {
/// Returns a tuple metatype of the given element types.
public static func tupleType<
ElementTypes: BidirectionalCollection
>(
of elementTypes: __owned ElementTypes
of elementTypes: __owned ElementTypes,
labels: String? = nil
) -> Any.Type where ElementTypes.Element == Any.Type {
// From swift/ABI/Metadata.h:
// template <typename int_type>
Expand All @@ -78,39 +48,50 @@ public enum TypeConstruction {
let elementCountFlag = 0x0000FFFF
assert(elementTypes.count != 1, "A one-element tuple is not a realistic Swift type")
assert(elementTypes.count <= elementCountFlag, "Tuple size exceeded \(elementCountFlag)")
switch elementTypes.count {
case 2:
return swift_getTupleTypeMetadata2(
request: 0,
element1: elementTypes[elementTypes.startIndex],
element2: elementTypes[elementTypes.index(elementTypes.startIndex, offsetBy: 1)],
labels: nil,
proposedWitnesses: nil).value
case 3:
return swift_getTupleTypeMetadata3(
request: 0,
element1: elementTypes[elementTypes.startIndex],
element2: elementTypes[elementTypes.index(elementTypes.startIndex, offsetBy: 1)],
element3: elementTypes[elementTypes.index(elementTypes.startIndex, offsetBy: 2)],
labels: nil,
proposedWitnesses: nil).value
default:
let result = elementTypes.withContiguousStorageIfAvailable { elementTypesBuffer in
swift_getTupleTypeMetadata(

var flags = elementTypes.count

// If we have labels to provide, then say the label pointer is not constant
// because the lifetime of said pointer will only be vaild for the lifetime
// of the 'swift_getTupleTypeMetadata' call. If we don't have labels, then
// our label pointer will be empty and constant.
if labels != nil {
// Has non constant labels
flags |= 0x10000
}

let result = elementTypes.withContiguousStorageIfAvailable { elementTypesBuffer in
if let labels = labels {
return labels.withCString { labelsPtr in
swift_getTupleTypeMetadata(
request: 0,
flags: flags,
elements: elementTypesBuffer.baseAddress,
labels: labelsPtr,
proposedWitnesses: nil
)
}
} else {
return swift_getTupleTypeMetadata(
request: 0,
flags: elementTypesBuffer.count,
flags: flags,
elements: elementTypesBuffer.baseAddress,
labels: nil,
proposedWitnesses: nil).value
proposedWitnesses: nil
)
}
guard let result = result else {
fatalError("""
The collection of element types does not support an internal representation of
contiguous storage
""")
}
return result
}

guard let result = result else {
fatalError(
"""
The collection of element types does not support an internal representation of
contiguous storage
"""
)
}

return result.value
}

/// Creates a type-erased tuple with the given elements.
Expand Down
37 changes: 10 additions & 27 deletions Sources/_StringProcessing/Capture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,6 @@

@_implementationOnly import _RegexParser

/// A structured capture
struct StructuredCapture {
/// The `.optional` height of the result
var optionalCount = 0

var storedCapture: StoredCapture?

var someCount: Int {
storedCapture == nil ? optionalCount - 1 : optionalCount
}
}

/// A storage form for a successful capture
struct StoredCapture {
// TODO: drop optional when engine tracks all ranges
var range: Range<String.Index>?

// If strongly typed, value is set
var value: Any? = nil
}

// TODO: Where should this live? Inside TypeConstruction?
func constructExistentialOutputComponent(
from input: Substring,
Expand Down Expand Up @@ -61,26 +40,30 @@ func constructExistentialOutputComponent(
return underlying
}

extension StructuredCapture {
@available(SwiftStdlib 5.7, *)
extension AnyRegexOutput.Element {
func existentialOutputComponent(
from input: Substring
) -> Any {
constructExistentialOutputComponent(
from: input,
in: storedCapture?.range,
value: storedCapture?.value,
optionalCount: optionalCount)
in: range,
value: value,
optionalCount: optionalDepth
)
}

func slice(from input: String) -> Substring? {
guard let r = storedCapture?.range else { return nil }
guard let r = range else { return nil }
return input[r]
}
}

extension Sequence where Element == StructuredCapture {
@available(SwiftStdlib 5.7, *)
extension Sequence where Element == AnyRegexOutput.Element {
// FIXME: This is a stop gap where we still slice the input
// and traffic through existentials
@available(SwiftStdlib 5.7, *)
func existentialOutput(
from input: Substring
) -> Any {
Expand Down
27 changes: 16 additions & 11 deletions Sources/_StringProcessing/Engine/Structuralize.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
@_implementationOnly import _RegexParser

extension CaptureList {
func structuralize(
@available(SwiftStdlib 5.7, *)
func createElements(
_ list: MECaptureList,
_ input: String
) -> [StructuredCapture] {
) -> [AnyRegexOutput.ElementRepresentation] {
assert(list.values.count == captures.count)

var result = [StructuredCapture]()
for (cap, meStored) in zip(self.captures, list.values) {
let stored = StoredCapture(
range: meStored.latest, value: meStored.latestValue)

result.append(.init(
optionalCount: cap.optionalDepth, storedCapture: stored))

var result = [AnyRegexOutput.ElementRepresentation]()

for (cap, meStored) in zip(captures, list.values) {
let element = AnyRegexOutput.ElementRepresentation(
optionalDepth: cap.optionalDepth,
bounds: meStored.latest,
name: cap.name,
value: meStored.latestValue
)

result.append(element)
}

return result
}
}
Expand Down
16 changes: 10 additions & 6 deletions Sources/_StringProcessing/Executor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct Executor {
namedCaptureOffsets: engine.program.namedCaptureOffsets)

let range = inputRange.lowerBound..<endIdx
let caps = engine.program.captureList.structuralize(capList, input)
let caps = engine.program.captureList.createElements(capList, input)

// FIXME: This is a workaround for not tracking (or
// specially compiling) whole-match values.
Expand All @@ -55,14 +55,18 @@ struct Executor {
} else {
value = nil
}

return .init(
let anyRegexOutput = AnyRegexOutput(
input: input,
elements: caps
)

return .init(
anyRegexOutput: anyRegexOutput,
range: range,
rawCaptures: caps,
referencedCaptureOffsets: capList.referencedCaptureOffsets,
namedCaptureOffsets: capList.namedCaptureOffsets,
value: value)
value: value
)
}

@available(SwiftStdlib 5.7, *)
Expand Down
Loading