module Penny.Liberty.Expressions (
I.Precedence(Precedence),

I.Associativity(ALeft, ARight),

I.Token(TokOperand,
TokUnaryPostfix,
TokUnaryPrefix,
TokBinary,
TokOpenParen,
TokCloseParen),

R.Operand(..),
tokAnd,
tokOr,
tokNot,
evaluate) where

import qualified Data.Foldable as Fdbl
import Penny.Liberty.Expressions.Infix as I
import Penny.Liberty.Expressions.RPN as R

-- | Tokens should be enqueued from left to right, so that tokens on
-- the left side of the sequence are those at the beginning of the
-- expression.
evaluate ::
Fdbl.Foldable l
=> l (I.Token a)
-> Maybe a
evaluate i = I.infixToRPN i >>= R.process

-- | An And token which is left associative with precedence 3.
tokAnd :: I.Token (a -> Bool)
tokAnd = I.TokBinary (I.Precedence 3) I.ALeft f where
f x y = \a -> x a && y a

-- | An Or token which is left associative with precedence 2.
tokOr :: I.Token (a -> Bool)
tokOr = I.TokBinary (I.Precedence 2) I.ALeft f where
f x y = \a -> x a || y a

-- | A unary prefix Not token with precedence 4.
tokNot :: I.Token (a -> Bool)
tokNot = I.TokUnaryPrefix (I.Precedence 4) (not .)

--
-- Testing
--
_plus :: I.Token Double
_plus = I.TokBinary (I.Precedence 4) I.ALeft (+)

_minus :: I.Token Double
_minus = I.TokBinary (I.Precedence 4) I.ALeft (-)

_times :: I.Token Double
_times = I.TokBinary (I.Precedence 5) I.ALeft (*)

_divide :: I.Token Double
_divide = I.TokBinary (I.Precedence 5) I.ALeft (/)

_neg :: I.Token Double
_neg = I.TokUnaryPrefix (I.Precedence 5) negate