nicklockwood / Expression

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

Order of operations question #28

Closed ajkendall closed 4 years ago

ajkendall commented 4 years ago

First off let me say I am really impressed with this library. I do have a question though. I am trying to include "^" as an alternative infix operator to the pow() function. Do you have any recommendation on how one could designate the order of operation for new math operators?

This is how I added the operator:

        Expression(
         Expression.parse(stringValue),
            impureSymbols: { symbol in
                switch symbol {
                case .infix("^"): return {  args in
                    return pow(args[0], args[1])
                }
                default: return nil
                }
            }
        )
nighthawk commented 4 years ago

According to the README there's no way to specify operator precedence:

Operator precedence follows standard BODMAS order, with multiplication/division given precedence over addition/subtraction. Prefix operators take precedence over postfix operators, which take precedence over infix ones. There is currently no way to specify precedence for custom operators - they all have equal priority to addition/subtraction.

My understanding is that if you use that input/pure constructor and return nil, it should fallback to the built-in operators. Do you have an example where your code doesn't work as expected?

(Note that it should be fine to define your ^ operator as a pure symbol, as what it returns is always the same for the same input arguments.)

nicklockwood commented 4 years ago

@ajkendall what @nighthawk said is correct. There is not currently any way to define precedence in the API. There is a hard-coded precedence table for common operators defined in the library, but any that are not defined (including ^) will have a precedence of zero (the same as +) by default.

I'm not sure off the top of my head if that's an appropriate default for ^. I guess that maybe it should have the same precedence as * instead? In which case feel free to add it to the internal precedence table and make a PR.

FWIW the reason I don't define ^ as one of the standard operators is that it is used to mean pow() in some languages and xor in others (with ** being the pow operator), so there didn't seem to be a clear choice as to which should be the default.

ajkendall commented 4 years ago

@nighthawk thanks for pointing out that line in the ReadMe - I definitely missed that bit.... @nicklockwood - I hadn't considered the xor interpretation. Thanks a bunch for pointing out the precedence table. Making a PR seems like the best solution.