Skip to content

Commit

Permalink
Make the Regex type Sendable (apple#457)
Browse files Browse the repository at this point in the history
This change makes `Regex`, `RegexComponent`, and its component types `Sendable`.

Regex stores a `Program` instance, which lazily lowers the DSLTree into a 
compiled program. Without synchronization, this lazy compilation is unsafe 
under concurrency. This change uses atomic initialization for the compiled 
program.
  • Loading branch information
natecook1000 committed Jun 1, 2022
1 parent dd81d61 commit 6cc803c
Show file tree
Hide file tree
Showing 14 changed files with 150 additions and 101 deletions.
5 changes: 4 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ let package = Package(
dependencies: []),
.target(
name: "_StringProcessing",
dependencies: ["_RegexParser", "_CUnicode"],
dependencies: [
"_RegexParser",
"_CUnicode",
],
swiftSettings: publicStdlibSettings),
.target(
name: "RegexBuilder",
Expand Down
26 changes: 13 additions & 13 deletions Sources/_RegexParser/Regex/AST/AST.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ extension AST {
extension AST {
/// A node in the regex AST.
public indirect enum Node:
Hashable, _TreeNode //, _ASTPrintable ASTValue, ASTAction
Hashable, _TreeNode, Sendable //, _ASTPrintable ASTValue, ASTAction
{
/// ... | ... | ...
case alternation(Alternation)
Expand Down Expand Up @@ -143,7 +143,7 @@ extension AST.Node {

extension AST {

public struct Alternation: Hashable, _ASTNode {
public struct Alternation: Hashable, Sendable, _ASTNode {
public let children: [AST.Node]
public let pipes: [SourceLocation]

Expand All @@ -162,7 +162,7 @@ extension AST {
}
}

public struct Concatenation: Hashable, _ASTNode {
public struct Concatenation: Hashable, Sendable, _ASTNode {
public let children: [AST.Node]
public let location: SourceLocation

Expand All @@ -172,7 +172,7 @@ extension AST {
}
}

public struct Quote: Hashable, _ASTNode {
public struct Quote: Hashable, Sendable, _ASTNode {
public let literal: String
public let location: SourceLocation

Expand All @@ -182,7 +182,7 @@ extension AST {
}
}

public struct Trivia: Hashable, _ASTNode {
public struct Trivia: Hashable, Sendable, _ASTNode {
public let contents: String
public let location: SourceLocation

Expand All @@ -197,7 +197,7 @@ extension AST {
}
}

public struct Interpolation: Hashable, _ASTNode {
public struct Interpolation: Hashable, Sendable, _ASTNode {
public let contents: String
public let location: SourceLocation

Expand All @@ -207,7 +207,7 @@ extension AST {
}
}

public struct Empty: Hashable, _ASTNode {
public struct Empty: Hashable, Sendable, _ASTNode {
public let location: SourceLocation

public init(_ location: SourceLocation) {
Expand All @@ -219,15 +219,15 @@ extension AST {
///
/// This is used to model a pattern which should
/// not be matched against across varying scopes.
public struct AbsentFunction: Hashable, _ASTNode {
public enum Start: Hashable {
public struct AbsentFunction: Hashable, Sendable, _ASTNode {
public enum Start: Hashable, Sendable {
/// `(?~|`
case withPipe

/// `(?~`
case withoutPipe
}
public enum Kind: Hashable {
public enum Kind: Hashable, Sendable {
/// An absent repeater `(?~absent)`. This is equivalent to `(?~|absent|.*)`
/// and therefore matches as long as the pattern `absent` is not matched.
case repeater(AST.Node)
Expand Down Expand Up @@ -261,8 +261,8 @@ extension AST {
}
}

public struct Reference: Hashable {
public enum Kind: Hashable {
public struct Reference: Hashable, Sendable {
public enum Kind: Hashable, Sendable {
// \n \gn \g{n} \g<n> \g'n' (?n) (?(n)...
// Oniguruma: \k<n>, \k'n'
case absolute(Int)
Expand Down Expand Up @@ -304,7 +304,7 @@ extension AST {
}

/// A set of global matching options in a regular expression literal.
public struct GlobalMatchingOptionSequence: Hashable {
public struct GlobalMatchingOptionSequence: Hashable, Sendable {
public var options: [AST.GlobalMatchingOption]

public init?(_ options: [AST.GlobalMatchingOption]) {
Expand Down
42 changes: 21 additions & 21 deletions Sources/_RegexParser/Regex/AST/Atom.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//===----------------------------------------------------------------------===//

extension AST {
public struct Atom: Hashable, _ASTNode {
public struct Atom: Hashable, Sendable, _ASTNode {
public let kind: Kind
public let location: SourceLocation

Expand All @@ -19,7 +19,7 @@ extension AST {
self.location = loc
}

public enum Kind: Hashable {
public enum Kind: Hashable, Sendable {
/// Just a character
///
/// A, \*, \\, ...
Expand Down Expand Up @@ -113,7 +113,7 @@ extension AST.Atom {
}

extension AST.Atom {
public struct Scalar: Hashable {
public struct Scalar: Hashable, Sendable {
public var value: UnicodeScalar
public var location: SourceLocation

Expand All @@ -123,7 +123,7 @@ extension AST.Atom {
}
}

public struct ScalarSequence: Hashable {
public struct ScalarSequence: Hashable, Sendable {
public var scalars: [Scalar]
public var trivia: [AST.Trivia]

Expand All @@ -145,7 +145,7 @@ extension AST.Atom {

// Characters, character types, literals, etc., derived from
// an escape sequence.
public enum EscapedBuiltin: Hashable {
public enum EscapedBuiltin: Hashable, Sendable {
// TODO: better doc comments

// Literal single characters
Expand Down Expand Up @@ -374,7 +374,7 @@ extension AST.Atom.EscapedBuiltin {
}

extension AST.Atom {
public struct CharacterProperty: Hashable {
public struct CharacterProperty: Hashable, Sendable {
public var kind: Kind

/// Whether this is an inverted property e.g '\P{Ll}', '[:^ascii:]'.
Expand All @@ -397,7 +397,7 @@ extension AST.Atom {
}

extension AST.Atom.CharacterProperty {
public enum Kind: Hashable {
public enum Kind: Hashable, Sendable {
/// Matches any character, equivalent to Oniguruma's '\O'.
case any

Expand Down Expand Up @@ -453,14 +453,14 @@ extension AST.Atom.CharacterProperty {
/// Some special properties implemented by Java.
case javaSpecial(JavaSpecial)

public enum MapKind: Hashable {
public enum MapKind: Hashable, Sendable {
case lowercase
case uppercase
case titlecase
}
}

public enum PCRESpecialCategory: String, Hashable {
public enum PCRESpecialCategory: String, Hashable, Sendable {
case alphanumeric = "Xan"
case posixSpace = "Xps"
case perlSpace = "Xsp"
Expand All @@ -470,7 +470,7 @@ extension AST.Atom.CharacterProperty {

/// Special Java properties that correspond to methods on
/// `java.lang.Character`, with the `java` prefix replaced by `is`.
public enum JavaSpecial: String, Hashable, CaseIterable {
public enum JavaSpecial: String, Hashable, CaseIterable, Sendable {
case alphabetic = "javaAlphabetic"
case defined = "javaDefined"
case digit = "javaDigit"
Expand All @@ -494,7 +494,7 @@ extension AST.Atom.CharacterProperty {

extension AST.Atom {
/// Anchors and other built-in zero-width assertions.
public enum AssertionKind: String {
public enum AssertionKind: String, Hashable, Sendable {
/// \A
case startOfSubject = #"\A"#

Expand Down Expand Up @@ -554,10 +554,10 @@ extension AST.Atom {
}

extension AST.Atom {
public enum Callout: Hashable {
public enum Callout: Hashable, Sendable {
/// A PCRE callout written `(?C...)`
public struct PCRE: Hashable {
public enum Argument: Hashable {
public struct PCRE: Hashable, Sendable {
public enum Argument: Hashable, Sendable {
case number(Int)
case string(String)
}
Expand All @@ -573,8 +573,8 @@ extension AST.Atom {
}

/// A named Oniguruma callout written `(*name[tag]{args, ...})`
public struct OnigurumaNamed: Hashable {
public struct ArgList: Hashable {
public struct OnigurumaNamed: Hashable, Sendable {
public struct ArgList: Hashable, Sendable {
public var leftBrace: SourceLocation
public var args: [AST.Located<String>]
public var rightBrace: SourceLocation
Expand Down Expand Up @@ -604,8 +604,8 @@ extension AST.Atom {
}

/// An Oniguruma callout 'of contents', written `(?{...}[tag]D)`
public struct OnigurumaOfContents: Hashable {
public enum Direction: Hashable {
public struct OnigurumaOfContents: Hashable, Sendable {
public enum Direction: Hashable, Sendable {
case inProgress // > (the default)
case inRetraction // <
case both // X
Expand Down Expand Up @@ -652,7 +652,7 @@ extension AST.Atom {

extension AST.Atom.Callout {
/// A tag specifier `[...]` that can appear in an Oniguruma callout.
public struct OnigurumaTag: Hashable {
public struct OnigurumaTag: Hashable, Sendable {
public var leftBracket: SourceLocation
public var name: AST.Located<String>
public var rightBracket: SourceLocation
Expand All @@ -670,8 +670,8 @@ extension AST.Atom.Callout {
}

extension AST.Atom {
public struct BacktrackingDirective: Hashable {
public enum Kind: Hashable {
public struct BacktrackingDirective: Hashable, Sendable {
public enum Kind: Hashable, Sendable {
/// (*ACCEPT)
case accept

Expand Down
12 changes: 6 additions & 6 deletions Sources/_RegexParser/Regex/AST/Conditional.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//===----------------------------------------------------------------------===//

extension AST {
public struct Conditional: Hashable, _ASTNode {
public struct Conditional: Hashable, Sendable, _ASTNode {
public var location: SourceLocation
public var condition: Condition

Expand All @@ -32,8 +32,8 @@ extension AST {
}

extension AST.Conditional {
public struct Condition: Hashable {
public enum Kind: Hashable {
public struct Condition: Hashable, Sendable {
public enum Kind: Hashable, Sendable {
/// Check to see if a certain group was matched.
case groupMatched(AST.Reference)

Expand Down Expand Up @@ -65,7 +65,7 @@ extension AST.Conditional {
}

extension AST.Conditional.Condition {
public struct PCREVersionNumber: Hashable {
public struct PCREVersionNumber: Hashable, Sendable {
public var major: Int
public var minor: Int
public var location: SourceLocation
Expand All @@ -76,8 +76,8 @@ extension AST.Conditional.Condition {
self.location = location
}
}
public struct PCREVersionCheck: Hashable {
public enum Kind: Hashable {
public struct PCREVersionCheck: Hashable, Sendable {
public enum Kind: Hashable, Sendable {
case equal, greaterThanOrEqual
}
public var kind: AST.Located<Kind>
Expand Down
10 changes: 5 additions & 5 deletions Sources/_RegexParser/Regex/AST/CustomCharClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


extension AST {
public struct CustomCharacterClass: Hashable {
public struct CustomCharacterClass: Hashable, Sendable {
public var start: Located<Start>
public var members: [Member]

Expand All @@ -27,7 +27,7 @@ extension AST {
self.location = sr
}

public enum Member: Hashable {
public enum Member: Hashable, Sendable {
/// A nested custom character class `[[ab][cd]]`
case custom(CustomCharacterClass)

Expand All @@ -47,7 +47,7 @@ extension AST {
/// A binary operator applied to sets of members `abc&&def`
case setOperation([Member], Located<SetOp>, [Member])
}
public struct Range: Hashable {
public struct Range: Hashable, Sendable {
public var lhs: Atom
public var dashLoc: SourceLocation
public var rhs: Atom
Expand All @@ -63,12 +63,12 @@ extension AST {
self.trivia = trivia
}
}
public enum SetOp: String, Hashable {
public enum SetOp: String, Hashable, Sendable {
case subtraction = "--"
case intersection = "&&"
case symmetricDifference = "~~"
}
public enum Start: String {
public enum Start: String, Hashable, Sendable {
case normal = "["
case inverted = "[^"
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/_RegexParser/Regex/AST/Group.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//===----------------------------------------------------------------------===//

extension AST {
public struct Group: Hashable {
public struct Group: Hashable, Sendable {
public let kind: Located<Kind>
public let child: AST.Node

Expand All @@ -24,7 +24,7 @@ extension AST {
self.location = r
}

public enum Kind: Hashable {
public enum Kind: Hashable, Sendable {
// (...)
case capture

Expand Down Expand Up @@ -116,7 +116,7 @@ extension AST.Group.Kind {
}

extension AST.Group {
public struct BalancedCapture: Hashable {
public struct BalancedCapture: Hashable, Sendable {
/// The name of the group, or nil if the group has no name.
public var name: AST.Located<String>?

Expand Down

0 comments on commit 6cc803c

Please sign in to comment.