nicklockwood / Expression

A cross-platform Swift library for evaluating mathematical expressions at runtime
MIT License
829 stars 51 forks source link

Fact `!` postfix operator does not work #50

Closed vanniktech closed 1 year ago

vanniktech commented 1 year ago
let expression = "5!"

let result = try Expression(
    expression,
    symbols: [
        .postfix("!"): { Double(fact(Int($0[0]))) }
    ]
).evaluate()

print(result)

private func fact(_ number: Int) -> Int {
   if number == 0 {
      return 1
   } else {
      return number * fact(number - 1)
   }
}

I would expect 120, but the infix operator isn't called.

nicklockwood commented 1 year ago

This works for me. It seems like you were originally trying with infix (which wouldn't have worked), but postfix should (and does, when I tried it).

nicklockwood commented 1 year ago

(Also, it's not related to the question, but your implementation of fact() will never terminate if you give it a negative number)

vanniktech commented 1 year ago

Oh yes. It does indeed work. Sorry for the noise. And thanks for catching the implementation error :)

vanniktech commented 1 year ago

However it seems like plus operators afterwards aren't tolerated after a postfix:

let expression = Expression(
    optimized,
    constants: [
        "π": Double.pi,
        "ℇ": Darwin.M_E,
    ],
    symbols: [
        .function("log10", arity: 1): { log10($0[0]) },
        .infix("()"): { $0[0] * $0[1] },
        .infix("^"): { pow($0[0], $0[1]) },
        .postfix("!"): { Double(fact(Int($0[0]))) },
        .postfix("π"): { $0[0] * Double.pi },
        .postfix("ℇ"): { $0[0] * Darwin.M_E },
        .prefix("√"): { sqrt($0[0]) },
    ]
)

9!+1 should yield 362881 but it throws an error: Expression.Expression.Error error 3.

nicklockwood commented 1 year ago

This is a limitation of the parser. Because it supports arbitrary operators it can't tell that !+ isn't meant to be an infix operator in its own right.

I'll see if there's a way to make it more flexible, but in the meantime adding spaces should solve it:

9! + 1

vanniktech commented 1 year ago

Yes adding spaces does the trick.