) {
let newPattern = capture.name == nil
? Capture(name: call.name, capture.wrapped)
: capture
diff --git a/Sources/Patterns/Operations on Patterns/And.swift b/Sources/Patterns/Operations on Patterns/And.swift
index 1addd79..b3a731a 100644
--- a/Sources/Patterns/Operations on Patterns/And.swift
+++ b/Sources/Patterns/Operations on Patterns/And.swift
@@ -7,6 +7,7 @@
/// A pattern which matches the `wrapped` pattern, without consuming any input.
public struct AndPattern: Pattern {
+ public typealias Input = Wrapped.Input
public let wrapped: Wrapped
public var description: String { "&\(wrapped)" }
@@ -16,9 +17,9 @@ public struct AndPattern: Pattern {
}
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {
let wrappedInstructions = try wrapped.createInstructions()
- if let indexMovedBy = wrappedInstructions.movesIndexBy {
+ if let indexMovedBy = wrappedInstructions.movesIndexBy() {
instructions.append(contentsOf: wrappedInstructions)
instructions.append(.moveIndex(offset: -indexMovedBy))
} else {
diff --git a/Sources/Patterns/Operations on Patterns/AnyPattern.swift b/Sources/Patterns/Operations on Patterns/AnyPattern.swift
index 9df8eb3..7fcabfe 100644
--- a/Sources/Patterns/Operations on Patterns/AnyPattern.swift
+++ b/Sources/Patterns/Operations on Patterns/AnyPattern.swift
@@ -7,12 +7,12 @@
/// A type erased wrapper around a pattern.
/// Can be used to store patterns in arrays and non-generic variables.
-public struct AnyPattern: Pattern {
+public struct AnyPattern: Pattern where Input.Element: Hashable {
@usableFromInline
let _instructions: (inout Instructions) throws -> Void
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {
try _instructions(&instructions)
}
@@ -22,7 +22,7 @@ public struct AnyPattern: Pattern {
/// The wrapped pattern. If you know the exact type you can unwrap it again.
public let wrapped: Any
- public init(_ p: P) {
+ public init(_ p: P) where Input == P.Input {
_instructions = p.createInstructions
_description = { p.description }
wrapped = p
@@ -33,7 +33,7 @@ public struct AnyPattern: Pattern {
self = p
}
- public init(_ p: Literal) {
+ public init(_ p: Literal) {
_instructions = p.createInstructions
_description = { p.description }
wrapped = p
@@ -44,11 +44,26 @@ public struct AnyPattern: Pattern {
}
}
+extension AnyPattern: ExpressibleByUnicodeScalarLiteral where Input == String {
+ @inlinable
+ public init(unicodeScalarLiteral value: String) {
+ self.init(stringLiteral: String(describing: value))
+ }
+}
+
+extension AnyPattern: ExpressibleByExtendedGraphemeClusterLiteral where Input == String {
+ public typealias ExtendedGraphemeClusterLiteralType = String
+}
+
+extension AnyPattern: ExpressibleByStringLiteral where Input == String {
+ public typealias StringLiteralType = String
+}
+
/// Allows AnyPattern to be defined by a string with patterns in interpolations.
///
/// `let p: AnyPattern = "hi\(whitespace)there"`
/// is the same as `"hi" • whitespace • "there"`.
-extension AnyPattern: ExpressibleByStringInterpolation {
+extension AnyPattern: ExpressibleByStringInterpolation where Input == String {
public struct StringInterpolation: StringInterpolationProtocol {
@usableFromInline
var pattern = AnyPattern("")
@@ -64,7 +79,7 @@ extension AnyPattern: ExpressibleByStringInterpolation {
}
@inlinable
- public mutating func appendInterpolation(_ newpattern: P) {
+ public mutating func appendInterpolation(_ newpattern: P) where P.Input == Input {
pattern = AnyPattern(pattern • newpattern)
}
}
diff --git a/Sources/Patterns/Operations on Patterns/Capture.swift b/Sources/Patterns/Operations on Patterns/Capture.swift
index 99fe4a7..a3ff03f 100644
--- a/Sources/Patterns/Operations on Patterns/Capture.swift
+++ b/Sources/Patterns/Operations on Patterns/Capture.swift
@@ -9,12 +9,13 @@
///
/// It can be retrieved in `Parser.Match.captures` or used for decoding into Decodables.
public struct Capture: Pattern {
+ public typealias Input = Wrapped.Input
public var description: String {
let result: String
switch (name, wrapped) {
- case (nil, is NoPattern):
+ case (nil, is NoPattern):
result = ""
- case let (name?, is NoPattern):
+ case let (name?, is NoPattern):
result = "name: \(name)"
case let (name?, wrapped):
result = "name: \(name), \(wrapped)"
@@ -37,40 +38,46 @@ public struct Capture: Pattern {
}
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {
instructions.append(.captureStart(name: name))
try wrapped.createInstructions(&instructions)
instructions.append(.captureEnd)
}
}
-extension Capture where Wrapped == NoPattern {
+extension Capture {
/// Captures the current input position as an empty range.
/// - Parameter name: optional name
@inlinable
- public init(name: String? = nil) {
- self.wrapped = NoPattern()
+ public init(name: String? = nil) where Wrapped == NoPattern {
+ self.wrapped = NoPattern()
+ self.name = name
+ }
+
+ /// Captures the current input position as an empty range.
+ /// - Parameter name: optional name
+ @inlinable
+ public init(name: String? = nil) where Wrapped == NoPattern {
+ self.wrapped = NoPattern()
self.name = name
}
-}
-extension Capture where Wrapped == Literal {
/// Captures the position of `wrapped` as a range.
/// - Parameter name: optional name
@inlinable
- public init(name: String? = nil, _ wrapped: Literal) {
+ public init(name: String? = nil, _ wrapped: Literal) where Wrapped == Literal {
self.wrapped = wrapped
self.name = name
}
}
/// A pattern that does absolutely nothing.
-public struct NoPattern: Pattern {
+public struct NoPattern: Pattern where Input.Element: Hashable {
public var description: String { "" }
@inlinable
public init() {}
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {}
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {}
}
diff --git a/Sources/Patterns/Operations on Patterns/Choice.swift b/Sources/Patterns/Operations on Patterns/Choice.swift
index 5792a33..b6b3feb 100644
--- a/Sources/Patterns/Operations on Patterns/Choice.swift
+++ b/Sources/Patterns/Operations on Patterns/Choice.swift
@@ -10,7 +10,8 @@ import Foundation
/// A pattern which first tries the `first` pattern,
/// if that fails it tries the `second` pattern from the same position.
-public struct OrPattern: Pattern {
+public struct OrPattern: Pattern where First.Input == Second.Input {
+ public typealias Input = First.Input
public let first: First
public let second: Second
@@ -25,7 +26,7 @@ public struct OrPattern: Pattern {
}
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {
let inst1 = try first.createInstructions()
let inst2 = try second.createInstructions()
instructions.append(.choice(offset: inst1.count + 3))
@@ -47,20 +48,27 @@ public func / (p1: First, p2: Second) -> OrPatt
/// First tries the pattern to the left,
/// if that fails it tries the pattern to the right from the same position.
@inlinable
-public func / (p1: Literal, p2: Second) -> OrPattern {
+public func / (p1: Literal, p2: Second) -> OrPattern, Second> {
OrPattern(p1, or: p2)
}
/// First tries the pattern to the left,
/// if that fails it tries the pattern to the right from the same position.
@inlinable
-public func / (p1: First, p2: Literal) -> OrPattern {
+public func / (p1: First, p2: Literal) -> OrPattern> {
OrPattern(p1, or: p2)
}
/// First tries the pattern to the left,
/// if that fails it tries the pattern to the right from the same position.
@inlinable
-public func / (p1: Literal, p2: Literal) -> OrPattern {
+public func / (p1: Literal, p2: Literal) -> OrPattern, Literal> {
+ OrPattern(p1, or: p2)
+}
+
+/// First tries the pattern to the left,
+/// if that fails it tries the pattern to the right from the same position.
+@inlinable
+public func / (p1: Literal, p2: Literal) -> OrPattern, Literal> {
OrPattern(p1, or: p2)
}
diff --git a/Sources/Patterns/Operations on Patterns/Concatenation.swift b/Sources/Patterns/Operations on Patterns/Concatenation.swift
index 398ce90..b068082 100644
--- a/Sources/Patterns/Operations on Patterns/Concatenation.swift
+++ b/Sources/Patterns/Operations on Patterns/Concatenation.swift
@@ -14,7 +14,8 @@ infix operator •: PatternConcatenationPrecedence
/// A pattern which first tries the `first` pattern,
/// if that succeeds it continues with the `second` pattern.
-public struct Concat: Pattern {
+public struct Concat: Pattern where First.Input == Second.Input {
+ public typealias Input = First.Input
public let first: First
public let second: Second
public var description: String { "\(first) \(second)" }
@@ -26,7 +27,7 @@ public struct Concat: Pattern {
}
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {
try first.createInstructions(&instructions)
try second.createInstructions(&instructions)
}
@@ -34,24 +35,24 @@ public struct Concat: Pattern {
/// First tries the pattern to the left, if that succeeds it tries the pattern to the right.
@inlinable
-public func • (lhs: Left, rhs: Right) -> Concat {
+public func • (lhs: Left, rhs: Right) -> Concat where Left.Input == Right.Input {
Concat(lhs, rhs)
}
/// First tries the pattern to the left, if that succeeds it tries the pattern to the right.
@inlinable
-public func • (lhs: Literal, rhs: Right) -> Concat {
+public func • (lhs: Literal, rhs: Right) -> Concat, Right> {
Concat(lhs, rhs)
}
/// First tries the pattern to the left, if that succeeds it tries the pattern to the right.
@inlinable
-public func • (lhs: Left, rhs: Literal) -> Concat {
+public func • (lhs: Left, rhs: Literal) -> Concat> {
Concat(lhs, rhs)
}
/// First tries the pattern to the left, if that succeeds it tries the pattern to the right.
@inlinable
-public func • (lhs: Literal, rhs: Literal) -> Concat {
+public func • (lhs: Literal, rhs: Literal) -> Concat, Literal> {
Concat(lhs, rhs)
}
diff --git a/Sources/Patterns/Operations on Patterns/Not.swift b/Sources/Patterns/Operations on Patterns/Not.swift
index 21093a4..f57be63 100644
--- a/Sources/Patterns/Operations on Patterns/Not.swift
+++ b/Sources/Patterns/Operations on Patterns/Not.swift
@@ -8,6 +8,7 @@
/// A pattern which only succeeds if the `wrapped` pattern fails.
/// The next pattern will continue from where `wrapped` started.
public struct NotPattern: Pattern {
+ public typealias Input = Wrapped.Input
public let wrapped: Wrapped
public var description: String { "!\(wrapped)" }
@@ -17,7 +18,7 @@ public struct NotPattern: Pattern {
}
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {
let wrappedInstructions = try wrapped.createInstructions()
instructions.append(.choice(offset: wrappedInstructions.count + 3))
instructions.append(contentsOf: wrappedInstructions)
@@ -34,6 +35,6 @@ public prefix func ! (pattern: P) -> NotPattern
{
/// Will only succeed if the following pattern fails. Does not consume any input.
@inlinable
-public prefix func ! (pattern: Literal) -> NotPattern {
+public prefix func ! (pattern: Literal) -> NotPattern> {
NotPattern(pattern)
}
diff --git a/Sources/Patterns/Operations on Patterns/Repetition.swift b/Sources/Patterns/Operations on Patterns/Repetition.swift
index defed6e..2f2f47a 100644
--- a/Sources/Patterns/Operations on Patterns/Repetition.swift
+++ b/Sources/Patterns/Operations on Patterns/Repetition.swift
@@ -10,6 +10,7 @@
///
/// Used by operators `*+¿`.
public struct RepeatPattern: Pattern {
+ public typealias Input = Wrapped.Input
public let wrapped: Wrapped
public let min: Int
public let max: Int?
@@ -27,7 +28,7 @@ public struct RepeatPattern: Pattern {
}
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {
let repeatedInstructions = try wrapped.createInstructions()
for _ in 0 ..< min { instructions.append(contentsOf: repeatedInstructions) }
if let max = max {
@@ -72,7 +73,7 @@ public postfix func * (me: P) -> RepeatPattern
{
/// Tries the preceding pattern, and continues even if it fails.
@inlinable
-public postfix func ¿ (me: Literal) -> RepeatPattern {
+public postfix func ¿ (me: Literal) -> RepeatPattern> {
me.repeat(0 ... 1)
}
diff --git a/Sources/Patterns/Operations on Patterns/Skip.swift b/Sources/Patterns/Operations on Patterns/Skip.swift
index 6e278ae..8a30a83 100644
--- a/Sources/Patterns/Operations on Patterns/Skip.swift
+++ b/Sources/Patterns/Operations on Patterns/Skip.swift
@@ -8,13 +8,15 @@
/// Skips 0 or more elements until a match for the next patterns are found.
///
/// If this is at the end of a pattern, it skips to the end of input.
-public struct Skip: Pattern {
+public struct Skip: Pattern where Input.Element: Hashable {
public var description: String { "Skip()" }
public init() {}
+ public init() where Input == String {}
+
@inlinable
- public func createInstructions(_ instructions: inout Instructions) throws {
+ public func createInstructions(_ instructions: inout ContiguousArray>) throws {
instructions.append(.skip)
}
}
diff --git a/Sources/Patterns/Pattern And Instruction.swift b/Sources/Patterns/Pattern And Instruction.swift
index b684c88..359ebfd 100644
--- a/Sources/Patterns/Pattern And Instruction.swift
+++ b/Sources/Patterns/Pattern And Instruction.swift
@@ -6,8 +6,8 @@
//
/// Something that can create Instructions for the Parser.
-public protocol Pattern: CustomStringConvertible, Equatable {
- typealias Input = String
+public protocol Pattern: CustomStringConvertible {
+ associatedtype Input: BidirectionalCollection where Input.Element: Hashable
typealias ParsedRange = Range
typealias Instructions = ContiguousArray>
@@ -146,10 +146,10 @@ public enum Instruction where Input.Element: Has
}
}
-extension Sequence where Element == Instruction {
+extension Sequence {
/// The offset by which these instructions will move the input index.
@inlinable
- var movesIndexBy: Int? {
+ func movesIndexBy