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