import Tok

resolve :: [Tok] -> Maybe Exp
resolve tokens = fmap fst $ parseRightExpr (Op "dummy" (-1) Nonfix) False tokens

-- | parse an expression following an operator and an optional minus sign
parseRightExpr :: Op -> Bool -> [Tok] -> Maybe (Exp, [Tok])
parseRightExpr op1 neg ts = case ts of
  [] -> error "missing right argument"
  t : r -> case t of
    TNeg -> do
      (n, r') <- parseRightExpr op1 True r
      continueParse op1 neg (Neg n) r'
    TExp e1 -> continueParse op1 neg e1 r
    _ -> error "two consecutive operators"

-- | for a left expression parse a contintuation starting with an operator.
continueParse :: Op -> Bool -> Exp -> [Tok] -> Maybe (Exp, [Tok])
continueParse op1@(Op _ prec1 fix1) neg e1 ts = case ts of
  [] -> Just (e1, [])
  t : r -> case t of
    TOp op2@(Op _ prec2 fix2) ->
       let cmp = if neg then
                     if prec2 <= 6
                     then LT -- minus binds stronger (finish)
                     else GT -- recurse
                 else case compare prec2 prec1 of
              EQ -> if fix1 == fix2 then
                case fix1 of
                  Leftfix -> LT    -- finish
                  Nonfix -> EQ     -- fail
                  Rightfix -> GT   -- recurse
                else EQ
              c -> c
       in case cmp of
            LT -> Just (e1, ts) -- finished with expression
            EQ -> Nothing       -- illegal expression
            GT -> do            -- enlarge left expression
              (e2, r') <- parseRightExpr op2 False r
              continueParse op1 neg (OpApp e1 op2 e2) r'
    _ -> error $ "unexpected expression: " ++ show t

main = test resolve
