Skip to content

Commit 800a611

Browse files
committed
Added support for order of operations with parenthesis
1 parent dfb9a5d commit 800a611

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

Example/Tests/Tests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,34 @@ class Tests: XCTestCase {
2727
XCTAssertNil(Parser.parse(string: "1 + k"))
2828
XCTAssertEqual(Parser.parse(string: "10 * 3 ^ 2")?.evaluate(), 90)
2929
XCTAssertEqual(Parser.parse(string: "12 + 4 * 3")?.evaluate(), 24)
30+
let value = Parser.parse(string: "23 / 0")
31+
XCTAssertNotNil(value)
32+
XCTAssertNil(value?.evaluate())
3033
}
34+
35+
func testExponentRelation() {
36+
XCTAssertEqual(Parser.parse(string: "2 ^ 3 ^ 2")?.evaluate(), 512)
37+
XCTAssertEqual(Parser.parse(string: "2 - 3 ^ 2")?.evaluate(), -7)
38+
}
39+
40+
func testDifferentOperators() {
41+
Operators.addOp = "%"
42+
Operators.subOp = "@"
43+
Operators.multOp = "#"
44+
Operators.powOp = "|"
45+
Operators.divOp = "!"
46+
XCTAssertNotNil(Parser.parse(string: "2 % 4 | 3"))
47+
XCTAssertEqual(Parser.parse(string: "2 % 4 | 3")?.evaluate(), 66)
48+
}
49+
50+
func testParenthesis() {
51+
XCTAssertNotNil(Parser.parse(string: "2 + (2 + 3)"))
52+
XCTAssertEqual(Parser.parse(string: "2 + (2 + 3)")?.evaluate(), 7)
53+
XCTAssertEqual(Parser.parse(string: "2 * (2 + 4)")?.evaluate(), 12)
54+
XCTAssertNil(Parser.parse(string: "2 + (3 * 4"))
55+
XCTAssertEqual(Parser.parse(string: "2 + ((4 + 5) * 3)")?.evaluate(), 29)
56+
XCTAssertNil(Parser.parse(string: "2 + ((((((((4 * 3) - 4) + 2)"))
57+
XCTAssertEqual(Parser.parse(string: "(2 + (3 + (4 * (5)) + 2))")?.evaluate(), 27)
58+
}
3159

3260
}

MathParser.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Pod::Spec.new do |s|
1010
s.name = 'MathParser'
11-
s.version = '1.1'
11+
s.version = '1.3'
1212
s.summary = 'A simple parser for Mathematical Expressions.'
1313

1414
# This description is used to generate tags and improve search results.

MathParser/Classes/Source/Parser.swift

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,32 @@ public class Parser {
1414
/// - parameter string: The string to parse
1515
/// - returns: An expression that will result in the value
1616
public static func parse(string: String) -> Expression? {
17-
let updatedString = Parser.changeMinusIntoOther(change: Operators.subOp, into: string)
17+
var updatedString = Parser.changeMinusIntoOther(change: Operators.subOp, into: string)
1818
guard updatedString.contains(Operators.divOp) || updatedString.contains(Operators.multOp) || updatedString.contains(Operators.addOp) || updatedString.contains(Operators.subOp) || updatedString.contains(Operators.powOp) || Decimal(string) != nil else {
1919
return nil
2020
}
21-
if updatedString.contains(Operators.addOp) || updatedString.contains(Operators.subOp) {
21+
if updatedString.contains("(") {
22+
let idx = updatedString.firstIndex(of: "(")!
23+
var parenCounts = 0
24+
var nextIdx = updatedString.index(after: idx)
25+
while nextIdx != updatedString.endIndex {
26+
if updatedString[nextIdx] == ")" {
27+
parenCounts -= 1
28+
} else if updatedString[nextIdx] == "(" {
29+
parenCounts += 1
30+
}
31+
if parenCounts == -1 {
32+
updatedString.replaceSubrange(idx..<nextIdx, with: "\(decimal: Parser.parse(string: String(updatedString[updatedString.index(after: idx)..<nextIdx]))?.evaluate())")
33+
break
34+
}
35+
nextIdx = updatedString.index(after: nextIdx)
36+
}
37+
if updatedString.contains("(") {
38+
return nil
39+
} else {
40+
return Parser.parse(string: updatedString)
41+
}
42+
} else if updatedString.contains(Operators.addOp) || updatedString.contains(Operators.subOp) {
2243
let addAll = updatedString.split(separator: Operators.addOp[Operators.addOp.startIndex]).map(String.init)
2344
let subMids = addAll.map({string in string.split(separator: Operators.subOp.first!).map(String.init)})
2445
return subMids.reduce(Decimal(0) as Expression, {(result: Expression?, next: [String]) -> Expression? in
@@ -122,3 +143,13 @@ extension Decimal: Expression {
122143
}
123144
}
124145
}
146+
147+
extension String.StringInterpolation {
148+
mutating func appendInterpolation(decimal: Decimal?) {
149+
if let d = decimal {
150+
self.appendInterpolation(d)
151+
} else {
152+
self.appendInterpolation("nil")
153+
}
154+
}
155+
}

0 commit comments

Comments
 (0)