Skip to content
4 changes: 4 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ let availabilityDefinition = PackageDescription.SwiftSetting.unsafeFlags([
"-define-availability",
"-Xfrontend",
"SwiftStdlib 5.7:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999",
"-Xfrontend",
"-define-availability",
"-Xfrontend",
"SwiftStdlib 5.8:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999",
])

/// Swift settings for building a private stdlib-like module that is to be used
Expand Down
68 changes: 56 additions & 12 deletions Sources/RegexBuilder/Variadics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
// Copyright (c) 2021-2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -571,7 +571,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<Substring> where R0.RegexOutput == W0 {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does if #available(SwiftStdlib 5.8, *) work?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that isn't allowed in an always-emit function.

return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -582,7 +586,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0)> where R0.RegexOutput == (W0, C0) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -593,7 +601,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1)> where R0.RegexOutput == (W0, C0, C1) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -604,7 +616,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1, C2)> where R0.RegexOutput == (W0, C0, C1, C2) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -615,7 +631,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1, C2, C3)> where R0.RegexOutput == (W0, C0, C1, C2, C3) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -626,7 +646,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1, C2, C3, C4)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -637,7 +661,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1, C2, C3, C4, C5)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -648,7 +676,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -659,7 +691,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -670,7 +706,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}
@available(SwiftStdlib 5.7, *)
Expand All @@ -681,7 +721,11 @@ extension RegexComponentBuilder {
accumulated: R0, next: R1
) -> Regex<(Substring, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where R0.RegexOutput == (W0, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) {
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions Sources/VariadicsGenerator/VariadicsGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ struct VariadicsGenerator: ParsableCommand {
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
// Copyright (c) 2021-2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -308,7 +308,11 @@ struct VariadicsGenerator: ParsableCommand {
output("""
{
let factory = makeFactory()
return factory.accumulate(accumulated, next)
if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) {
return factory.accumulate(accumulated, factory.ignoreCapturesInTypedOutput(next))
} else {
return factory.accumulate(accumulated, next)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about a helper function that will reduce spew and, more importantly, give a name and place to commend why we're doing this and how it differs across versions.

E.g.

// comment...
private func dropCaptures(_ next: ...) -> ... {
  // ... comment about old and new behavior
  if #available(...) {
   return  ...
  }
  return ...
}

...

return factory.accumulate(accumulated, dropCaptures(next))

(or some better name than dropCaptures)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good call, I only ever wrote this once, but it is codegen'd an awful lot.

}
}

Expand Down
33 changes: 19 additions & 14 deletions Sources/_RegexParser/Regex/Parse/CaptureList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,19 @@ extension CaptureList {
public var type: Any.Type
public var optionalDepth: Int
public var location: SourceLocation
public var visibleInTypedOutput: Bool

public init(
name: String? = nil,
type: Any.Type = Substring.self,
optionalDepth: Int,
visibleInTypedOutput: Bool,
_ location: SourceLocation
) {
self.name = name
self.type = type
self.optionalDepth = optionalDepth
self.visibleInTypedOutput = visibleInTypedOutput
self.location = location
}
}
Expand Down Expand Up @@ -104,58 +107,60 @@ extension CaptureList {

extension CaptureList.Builder {
public mutating func addCaptures(
of node: AST.Node, optionalNesting nesting: OptionalNesting
of node: AST.Node,
optionalNesting nesting: OptionalNesting,
visibleInTypedOutput: Bool
) {
switch node {
case let .alternation(a):
for child in a.children {
addCaptures(of: child, optionalNesting: nesting.addingOptional)
addCaptures(of: child, optionalNesting: nesting.addingOptional, visibleInTypedOutput: visibleInTypedOutput)
}

case let .concatenation(c):
for child in c.children {
addCaptures(of: child, optionalNesting: nesting)
addCaptures(of: child, optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput)
}

case let .group(g):
switch g.kind.value {
case .capture:
captures.append(.init(optionalDepth: nesting.depth, g.location))
captures.append(.init(optionalDepth: nesting.depth, visibleInTypedOutput: visibleInTypedOutput, g.location))

case .namedCapture(let name):
captures.append(.init(
name: name.value, optionalDepth: nesting.depth, g.location))
name: name.value, optionalDepth: nesting.depth, visibleInTypedOutput: visibleInTypedOutput, g.location))

case .balancedCapture(let b):
captures.append(.init(
name: b.name?.value, optionalDepth: nesting.depth, g.location))
name: b.name?.value, optionalDepth: nesting.depth, visibleInTypedOutput: visibleInTypedOutput, g.location))

default: break
}
addCaptures(of: g.child, optionalNesting: nesting)
addCaptures(of: g.child, optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput)

case .conditional(let c):
switch c.condition.kind {
case .group(let g):
addCaptures(of: .group(g), optionalNesting: nesting)
addCaptures(of: .group(g), optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput)
default:
break
}

addCaptures(of: c.trueBranch, optionalNesting: nesting.addingOptional)
addCaptures(of: c.falseBranch, optionalNesting: nesting.addingOptional)
addCaptures(of: c.trueBranch, optionalNesting: nesting.addingOptional, visibleInTypedOutput: visibleInTypedOutput)
addCaptures(of: c.falseBranch, optionalNesting: nesting.addingOptional, visibleInTypedOutput: visibleInTypedOutput)

case .quantification(let q):
var optNesting = nesting
if q.amount.value.bounds.atLeast == 0 {
optNesting = optNesting.addingOptional
}
addCaptures(of: q.child, optionalNesting: optNesting)
addCaptures(of: q.child, optionalNesting: optNesting, visibleInTypedOutput: visibleInTypedOutput)

case .absentFunction(let abs):
switch abs.kind {
case .expression(_, _, let child):
addCaptures(of: child, optionalNesting: nesting)
addCaptures(of: child, optionalNesting: nesting, visibleInTypedOutput: visibleInTypedOutput)
case .clearer, .repeater, .stopper:
break
}
Expand All @@ -166,8 +171,8 @@ extension CaptureList.Builder {
}
public static func build(_ ast: AST) -> CaptureList {
var builder = Self()
builder.captures.append(.init(optionalDepth: 0, .fake))
builder.addCaptures(of: ast.root, optionalNesting: .init(canNest: false))
builder.captures.append(.init(optionalDepth: 0, visibleInTypedOutput: true, .fake))
builder.addCaptures(of: ast.root, optionalNesting: .init(canNest: false), visibleInTypedOutput: true)
return builder.captures
}
}
Expand Down
5 changes: 4 additions & 1 deletion Sources/_StringProcessing/ByteCodeGen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ fileprivate extension Compiler.ByteCodeGen {
switch node {
case .concatenation(let ch):
return ch.flatMap(flatten)
case .convertedRegexLiteral(let n, _):
case .convertedRegexLiteral(let n, _), .ignoreCapturesInTypedOutput(let n):
return flatten(n)
default:
return [node]
Expand Down Expand Up @@ -951,6 +951,9 @@ fileprivate extension Compiler.ByteCodeGen {
case let .nonCapturingGroup(kind, child):
try emitNoncapturingGroup(kind.ast, child)

case let .ignoreCapturesInTypedOutput(child):
try emitNode(child)

case .conditional:
throw Unsupported("Conditionals")

Expand Down
2 changes: 1 addition & 1 deletion Sources/_StringProcessing/Capture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ extension Sequence where Element == AnyRegexOutput.Element {
// and traffic through existentials
@available(SwiftStdlib 5.7, *)
func existentialOutput(from input: String) -> Any {
let elements = map {
let elements = filter(\.representation.visibleInTypedOutput).map {
$0.existentialOutputComponent(from: input)
}
return elements.count == 1
Expand Down
2 changes: 1 addition & 1 deletion Sources/_StringProcessing/ConsumerInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ extension DSLTree.Node {
case .orderedChoice, .conditional, .concatenation,
.capture, .nonCapturingGroup,
.quantification, .trivia, .empty,
.absentFunction: return nil
.ignoreCapturesInTypedOutput, .absentFunction: return nil

case .consumer:
fatalError("FIXME: Is this where we handle them?")
Expand Down
3 changes: 2 additions & 1 deletion Sources/_StringProcessing/Engine/Structuralize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ extension CaptureList {
optionalDepth: cap.optionalDepth,
content: meStored.deconstructed,
name: cap.name,
referenceID: list.referencedCaptureOffsets.first { $1 == i }?.key
referenceID: list.referencedCaptureOffsets.first { $1 == i }?.key,
visibleInTypedOutput: cap.visibleInTypedOutput
)

result.append(element)
Expand Down
3 changes: 3 additions & 0 deletions Sources/_StringProcessing/PrintAsPattern.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ extension PrettyPrinter {
printer.printAsPattern(convertedFromAST: child)
}

case let .ignoreCapturesInTypedOutput(child):
printAsPattern(convertedFromAST: child, isTopLevel: isTopLevel)

case .conditional:
print("/* TODO: conditional */")

Expand Down
4 changes: 4 additions & 0 deletions Sources/_StringProcessing/Regex/AnyRegexOutput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,10 @@ extension AnyRegexOutput {

/// The capture reference this element refers to.
var referenceID: ReferenceID? = nil

/// A Boolean value indicating whether this capture should be included in
/// the typed output.
var visibleInTypedOutput: Bool
}

internal init(input: String, elements: [ElementRepresentation]) {
Expand Down
Loading