From 2735679ebc3672aac576fec6420ff2d1a1c25a95 Mon Sep 17 00:00:00 2001 From: Kare Morstol Date: Thu, 13 Aug 2020 20:37:11 +0200 Subject: [PATCH 1/2] Readme: require Swift 5.3 --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c8e574a..2ce8acd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- Swift 5.2 + Swift 5.3 SPM @@ -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 From eddb419ae22ed206597e2ad2feba113f18662fb3 Mon Sep 17 00:00:00 2001 From: Kare Morstol Date: Thu, 13 Aug 2020 21:56:44 +0200 Subject: [PATCH 2/2] Readme: Add part about pattern input types. Split up readme unit test to avoid warning about it taking too long to type check. --- README.md | 24 +++++++ Tests/PatternsTests/PatternTests.swift | 89 ++++++++++++++++---------- 2 files changed, 78 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 2ce8acd..4209b55 100644 --- a/README.md +++ b/README.md @@ -187,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(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/) diff --git a/Tests/PatternsTests/PatternTests.swift b/Tests/PatternsTests/PatternTests.swift index 940ba21..2666710 100644 --- a/Tests/PatternsTests/PatternTests.swift +++ b/Tests/PatternsTests/PatternTests.swift @@ -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(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 } }