Skip to content
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
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<p align="center">
<a href="https://developer.apple.com/swift/">
<img src="https://img.shields.io/badge/Swift-5.2-orange.svg?style=flat" alt="Swift 5.2">
<img src="https://img.shields.io/badge/Swift-5.3-orange.svg?style=flat" alt="Swift 5.3">
</a>
<a href="https://github.com/apple/swift-package-manager">
<img src="https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg" alt="SPM">
Expand All @@ -17,6 +17,10 @@ For general information about PEGs, see [the original paper](https://dl.acm.org/

To try out Patterns in a playground, open Playground/Playground.xcworkspace in Xcode.

### Note

Patterns requires Swift 5.3, which is currently in beta. If using Xcode, version 12 (also in beta) is required.

## Example

```swift
Expand Down Expand Up @@ -183,6 +187,30 @@ let pointsAsSubstrings = parser.matches(in: text).map { match in

You can also use `match[multiple: name]` to get an array if captures with that name may be matched multiple times. `match[one: name]` only returns the first capture of that name.

### Inputs

By default, patterns have `String` as their input type. But you can use any `BidirectionalCollection` with `Hashable` elements for input. Just explicitly specify the input type of the first pattern, and the rest should get it automatically:

```swift
let text = "This is a point: (43,7), so is (0, 5). But my final point is (3,-1).".utf8

let digit = OneOf<String.UTF8View>(UInt8(ascii: "0")...UInt8(ascii: "9"))
let number = ("+" / "-" / "") • digit+
let point = "(" • Capture(name: "x", number)
• "," • " "¿ • Capture(name: "y", number) • ")"

struct Point: Codable {
let x, y: Int
}

let parser = try Parser(search: point)
let pointsAsSubstrings = parser.matches(in: text).map { match in
(text[match[one: "x"]!], text[match[one: "y"]!])
}
```

`Parser.decode` can (currently) only take String as input, but `.matches` handles all types.

## Setup

### [Swift Package Manager](https://swift.org/package-manager/)
Expand Down
89 changes: 54 additions & 35 deletions Tests/PatternsTests/PatternTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -307,48 +307,67 @@ class PatternTests: XCTestCase {
assertCaptures(point, input: text, result: [["43", "7"], ["0", "5"], ["3", "-1"]])
}

func testReadme() throws {
do {
let l = OneOf(description: "ten") { character in
character.wholeNumberValue == 10
}

let arithmetic = Grammar { g in
g.all <- g.expr • !any
g.expr <- g.sum
g.sum <- g.product • (("+" / "-") • g.product)*
g.product <- g.power • (("*" / "/") • g.power)*
g.power <- g.value • ("^" • g.power)¿
g.value <- digit+ / "(" • g.expr • ")"
}

let parser = try Parser(search: l)
for match in parser.matches(in: "text") {
_ = match
// ...
}
_ = arithmetic
func testReadme1() throws {
let l = OneOf(description: "ten") { character in
character.wholeNumberValue == 10
}

do {
let text = "This is a point: (43,7), so is (0, 5). But my final point is (3,-1)."
let arithmetic = Grammar { g in
g.all <- g.expr • !any
g.expr <- g.sum
g.sum <- g.product • (("+" / "-") • g.product)*
g.product <- g.power • (("*" / "/") • g.power)*
g.power <- g.value • ("^" • g.power)¿
g.value <- digit+ / "(" • g.expr • ")"
}

let parser = try Parser(search: l)
for match in parser.matches(in: "text") {
_ = match
// ...
}

_ = arithmetic
}

func testReadme2() throws {
let text = "This is a point: (43,7), so is (0, 5). But my final point is (3,-1)."

let number = ("+" / "-" / "") • digit+
let point = "(" • Capture(name: "x", number)
• "," • " "¿ • Capture(name: "y", number) • ")"

struct Point: Codable {
let x, y: Int
}

let parser = try Parser(search: point)
let points = try parser.decode([Point].self, from: text)

let number = ("+" / "-" / "") • digit+
let point = "(" • Capture(name: "x", number)
• "," • " "¿ • Capture(name: "y", number) • ")"
let pointsAsSubstrings = parser.matches(in: text).map { match in
(text[match[one: "x"]!], text[match[one: "y"]!])
}

_ = (points, pointsAsSubstrings)
}

struct Point: Codable {
let x, y: Int
}
func testReadme3() throws {
let text = "This is a point: (43,7), so is (0, 5). But my final point is (3,-1).".utf8

let parser = try Parser(search: point)
let points = try parser.decode([Point].self, from: text)
let digit = OneOf<String.UTF8View>(UInt8(ascii: "0") ... UInt8(ascii: "9"))
let number = ("+" / "-" / "") • digit+
let point = "(" • Capture(name: "x", number)
• "," • " "¿ • Capture(name: "y", number) • ")"

let pointsAsSubstrings = parser.matches(in: text).map { match in
(text[match[one: "x"]!], text[match[one: "y"]!])
}
struct Point: Codable {
let x, y: Int
}

_ = (points, pointsAsSubstrings)
let parser = try Parser(search: point)
let pointsAsSubstrings = parser.matches(in: text).map { match in
(text[match[one: "x"]!], text[match[one: "y"]!])
}

_ = pointsAsSubstrings
}
}