Skip to content

Commit 62609f0

Browse files
authored
Merge pull request #15 from BenchR267/develop
Fixed precedence of operators
2 parents 1adbec0 + 99f29dc commit 62609f0

70 files changed

Lines changed: 9365 additions & 365 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codecov.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
coverage:
22
ignore:
33
- "Tests/*"
4+
comment:
5+
layout: "reach, diff"
6+
behavior: once
7+
require_changes: true

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ matrix:
1515
- bundle exec danger
1616
before_install:
1717
- wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import -
18-
- wget https://swift.org/builds/swift-4.0-branch/ubuntu1404/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-16-a/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-16-a-ubuntu14.04.tar.gz
19-
- tar xzf swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-16-a-ubuntu14.04.tar.gz
20-
- export PATH=${PWD}/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-16-a-ubuntu14.04/usr/bin:"${PATH}"
18+
- wget -q https://swift.org/builds/swift-4.0-branch/ubuntu1404/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-21-a/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-21-a-ubuntu14.04.tar.gz
19+
- tar xzf swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-21-a-ubuntu14.04.tar.gz
20+
- export PATH=${PWD}/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-08-21-a-ubuntu14.04/usr/bin:"${PATH}"
2121
script:
2222
- make travis
2323
- os: osx

Dangerfile

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,32 @@
1-
message("Hello, this worked")
2-
3-
# including in a project's CHANGELOG for example
4-
declared_trivial = github.pr_title.include? "#trivial"
5-
61
# Make it more obvious that a PR is a work in progress and shouldn't be merged yet
72
warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]"
3+
4+
fail "Please provide a summary in the Pull Request description" if github.pr_body.length < 5
5+
6+
warn "#{github.html_link("Package.swift")} was edited." if git.modified_files.include? "Package.swift"
7+
warn "#{github.html_link("Makefile")} was edited." if git.modified_files.include? "Makefile"
8+
9+
# Check if tests were written for swift files
10+
def isTest?(file)
11+
file.start_with? "Tests/"
12+
end
13+
14+
def isSwiftFile?(file)
15+
file.end_with? ".swift"
16+
end
17+
18+
(git.added_files + git.modified_files).each do |file|
19+
next unless file.end_with? "Tests.swift"
20+
warn "Test files should end with _TestCase.swift, not Tests.swift. Please rename #{github.html_link(file)}"
21+
end
22+
23+
files = (git.added_files + git.modified_files).select{ |file| isSwiftFile?(file) && !isTest?(file) }
24+
tests = (git.added_files + git.modified_files).select{ |file| isSwiftFile?(file) && isTest?(file) }
25+
26+
files.each do |file|
27+
next if tests.any? { |e|
28+
name = file.match(/\/([a-zA-Z_0-9]*)\.swift/).captures.first
29+
e.include? name
30+
}
31+
fail("Please add a test case for #{file}.")
32+
end

Gemfile.lock

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ GEM
77
minitest (~> 5.1)
88
thread_safe (~> 0.3, >= 0.3.4)
99
tzinfo (~> 1.1)
10-
addressable (2.5.1)
11-
public_suffix (~> 2.0, >= 2.0.2)
10+
addressable (2.5.2)
11+
public_suffix (>= 2.0.2, < 4.0)
1212
claide (1.0.2)
1313
claide-plugins (0.9.2)
1414
cork
@@ -50,7 +50,7 @@ GEM
5050
colored2 (3.1.2)
5151
cork (0.3.0)
5252
colored2 (~> 3.1)
53-
danger (5.3.4)
53+
danger (5.3.5)
5454
claide (~> 1.0)
5555
claide-plugins (>= 0.9.2)
5656
colored2 (~> 3.1)
@@ -59,6 +59,7 @@ GEM
5959
faraday-http-cache (~> 1.0)
6060
git (~> 1)
6161
kramdown (~> 1.5)
62+
no_proxy_fix
6263
octokit (~> 4.7)
6364
terminal-table (~> 1)
6465
escape (0.0.4)
@@ -78,10 +79,11 @@ GEM
7879
nanaimo (0.2.3)
7980
nap (1.1.0)
8081
netrc (0.7.8)
82+
no_proxy_fix (0.1.1)
8183
octokit (4.7.0)
8284
sawyer (~> 0.8.0, >= 0.5.3)
8385
open4 (1.3.4)
84-
public_suffix (2.0.5)
86+
public_suffix (3.0.0)
8587
ruby-macho (1.1.0)
8688
sawyer (0.8.1)
8789
addressable (>= 2.3.5, < 2.6)

Sources/Parsel/Core/Operators.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,25 @@
77

88
// MARK: - Precendence groups and declaration
99

10+
// Check https://github.com/apple/swift-evolution/blob/master/proposals/0077-operator-precedence.md for reference
11+
12+
/// ^^ and ^^^
13+
precedencegroup ParserMapPrecedenceGroup {
14+
associativity: left
15+
lowerThan: AdditionPrecedence, BitwiseShiftPrecedence, NilCoalescingPrecedence
16+
}
17+
18+
/// ~ and >~
1019
precedencegroup ParserConjunctionGroup {
1120
associativity: left
12-
higherThan: BitwiseShiftPrecedence
21+
lowerThan: NilCoalescingPrecedence
22+
higherThan: ParserMapPrecedenceGroup
1323
}
1424

25+
/// <~
1526
precedencegroup ParserConjuctionRightGroup {
1627
associativity: right
17-
higherThan: ParserConjunctionGroup
18-
}
19-
20-
precedencegroup ParserMapPrecedenceGroup {
21-
associativity: left
28+
lowerThan: NilCoalescingPrecedence
2229
higherThan: ParserConjunctionGroup
2330
}
2431

Sources/Parsel/RegexParser.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Foundation
99

1010
/// A shortcut to RegexParser
11-
public typealias Regex = RegexParser
11+
public typealias R = RegexParser
1212

1313
/// A parser that parses Strings with a given regular expression
1414
public final class RegexParser: Parser<String, String> {
@@ -58,9 +58,10 @@ public final class RegexParser: Parser<String, String> {
5858
([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})
5959
""".r
6060

61+
// swiftlint:disable line_length
6162
/// Parses an http(s) address
6263
public static let httpAddress = """
63-
(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?
64+
^(?i)(?:(?:https?|ftp):\\/\\/)?(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))(?::\\d{2,5})?(?:\\/[^\\s]*)?$
6465
""".r
6566

6667
/// Parses an IP address
@@ -69,9 +70,9 @@ public final class RegexParser: Parser<String, String> {
6970
""".r
7071

7172
// swiftlint:disable line_length
72-
/// Parses a semantic version number (1.0.0, 1.0, …) thanks to https://github.com/mojombo/semver/issues/232
73+
/// Parses a semantic version number (1.0.0, 1.0, …) thanks to https://git.daplie.com/coolaj86/semver-utils
7374
public static let semver = """
74-
(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?
75+
v?((\\d+)\\.(\\d+)\\.(\\d+))(?:-([\\dA-Za-z\\-]+(?:\\.[\\dA-Za-z\\-]+)*))?(?:\\+([\\dA-Za-z\\-]+(?:\\.[\\dA-Za-z\\-]+)*))?
7576
""".r
7677
}
7778

Tests/ParselTests/Helpers.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ internal let digit = Parser<String, Int> { str in
4444
return .success(result: number, rest: String(str.dropFirst()))
4545
}
4646

47-
internal let number = digit.rep.map { Int($0.map(String.init).joined()) ?? 0 }
47+
internal let number = digit.atLeastOnce.map { Int($0.map(String.init).joined()) ?? 0 }

Tests/ParselTests/Operators_TestCase.swift

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,50 @@ class Operators_TestCase: XCTestCase {
9090
XCTAssertEqual(try res1.unwrap(), [])
9191
}
9292

93-
func test_fallback_operator() {
93+
func test_fallback_operator() throws {
9494
let p1 = char("a") ?? "b"
9595
let p2 = char("a").fallback("b")
9696

9797
let input = "cba"
9898
let res1 = p1.parse(input)
9999
let res2 = p2.parse(input)
100100
XCTAssertTrue(res1 == res2)
101+
102+
let p3 = char("a").map({ $0.description }) ?? digit.map({ $0.description })
103+
let res3 = p3.parse("1")
104+
XCTAssertEqual(try res3.unwrap(), "1")
105+
let res4 = p3.parse("a")
106+
XCTAssertEqual(try res4.unwrap(), "a")
107+
let res5 = p3.parse("b")
108+
XCTAssertTrue(res5.isFailed())
101109
}
102110

111+
func test_precedence() throws {
112+
// ~ has higher presedence than ^^
113+
let p = char("a") >~ char("b") <~ char("c") ^^ { String($0) }
114+
let res1 = p.parse("abcd")
115+
XCTAssertEqual(try res1.unwrap(), "b")
116+
XCTAssertEqual(try res1.rest(), "d")
117+
118+
// >> has higher precedence than ^^
119+
let p2 = char("a") >> char("b") ^^ { L.asciiValue(from: $0) }
120+
XCTAssertEqual(try p2.parse("ab").unwrap(), L.asciiValue(from: "b"))
121+
122+
// + and * have highest precedence
123+
let p3 = char("a")* ~ char("b")+ ^^ { ($0.0.count, String($0.1)) }
124+
let res2 = try p3.parse("aaaaaaaaabbb").unwrap()
125+
XCTAssertEqual(res2.0, 9)
126+
XCTAssertEqual(res2.1, "bbb")
127+
128+
// ?? has highest priority
129+
let p4 = char("a") ?? "a" ~ digit
130+
let res3 = try p4.parse("a4").unwrap()
131+
XCTAssertEqual(res3.0, "a")
132+
XCTAssertEqual(res3.1, 4)
133+
let res4 = try p4.parse("4").unwrap()
134+
XCTAssertEqual(res4.0, "a")
135+
XCTAssertEqual(res4.1, 4)
136+
}
103137
}
104138

105139
#if os(Linux)
@@ -114,7 +148,8 @@ class Operators_TestCase: XCTestCase {
114148
("test_atLeastOnce_operator", test_atLeastOnce_operator),
115149
("test_rep_operator", test_rep_operator),
116150
("test_rep_fail_operator", test_rep_fail_operator),
117-
("test_fallback_operator", test_fallback_operator)
151+
("test_fallback_operator", test_fallback_operator),
152+
("test_precedence", test_precedence)
118153
]
119154
}
120155
#endif

Tests/ParselTests/Parsel_TestCase.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Parsel_TestCase: XCTestCase {
1212

1313
func test_addition() {
1414

15-
let addition = (number ~ char("+") ~ number).map { a, _, b in
15+
let addition = number ~ char("+") ~ number ^^ { a, _, b in
1616
return a + b
1717
}
1818

@@ -38,7 +38,7 @@ class Parsel_TestCase: XCTestCase {
3838
}
3939
}
4040

41-
let addition1 = (digit ~ "\\+".r ~ digit).map { a, _, b in a + b } // "+".r is a RegexParser that parses the `+` sign
41+
let addition1 = digit ~ "\\+".r ~ digit ^^ { a, _, b in a + b } // "+".r is a RegexParser that parses the `+` sign
4242
let result1 = addition1.parse("2+4")
4343

4444
XCTAssertEqual(try result1.unwrap(), 6)

Tests/ParselTests/RegexParser_TestCase.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,62 @@ class RegexParser_TestCase: XCTestCase {
5959
XCTAssertEqual(regex, "[")
6060
}
6161

62+
func test_parse_mail() throws {
63+
let p = R.mail
64+
let res1 = p.parse("mail@benchr.de")
65+
XCTAssertEqual(try res1.unwrap(), "mail@benchr.de")
66+
67+
let res2 = p.parse("mail@mail@benchr.de")
68+
XCTAssertTrue(res2.isFailed())
69+
}
70+
71+
func test_parse_httpAddress() throws {
72+
let p = R.httpAddress
73+
let res1 = p.parse("https://www.google.de")
74+
XCTAssertEqual(try res1.unwrap(), "https://www.google.de")
75+
76+
let res2 = p.parse("http://https://facebook.com")
77+
XCTAssertTrue(res2.isFailed())
78+
}
79+
80+
func test_parse_ipAddress() throws {
81+
let p = R.ipAddress
82+
let res1 = p.parse("192.168.2.1")
83+
XCTAssertEqual(try res1.unwrap(), "192.168.2.1")
84+
85+
let res2 = p.parse("5454.242.545.1")
86+
XCTAssertTrue(res2.isFailed())
87+
}
88+
89+
func test_parse_semver() throws {
90+
let p = R.semver
91+
92+
let tests = [
93+
"1.0.0",
94+
"1.0.0-alpha1",
95+
"1.0.0+build-123",
96+
"v1.0.0",
97+
"1.0.0b",
98+
"1.0.0+build-abc."
99+
]
100+
101+
for test in tests {
102+
let res1 = p.parse(test)
103+
XCTAssertTrue(test.hasPrefix(try res1.unwrap()))
104+
}
105+
106+
let failTests = [
107+
"a.b.c",
108+
"1",
109+
"1.0"
110+
]
111+
112+
for test in failTests {
113+
let res2 = p.parse(test)
114+
XCTAssertTrue(res2.isFailed())
115+
}
116+
}
117+
62118
}
63119

64120
#if os(Linux)
@@ -70,6 +126,10 @@ class RegexParser_TestCase: XCTestCase {
70126
("test_parse_lowercasedLetters", test_parse_lowercasedLetters),
71127
("test_parse_fail", test_parse_fail),
72128
("test_parse_fail_invalidRegex", test_parse_fail_invalidRegex),
129+
("test_parse_mail", test_parse_mail),
130+
("test_parse_httpAddress", test_parse_httpAddress),
131+
("test_parse_ipAddress", test_parse_ipAddress),
132+
("test_parse_semver", test_parse_semver)
73133
]
74134
}
75135
#endif

0 commit comments

Comments
 (0)