{-# LANGUAGE LambdaCase #-}

module MonadicBang.Test.ShouldFail (shouldFail) where

import MonadicBang.Test.Utils
import MonadicBang.Internal.Error

import GHC.Types.Name.Occurrence

import GHC.Parser.Errors.Types

shouldFail :: Test
shouldFail = do
  combined
  various
  letStmt
  letInLet

data ErrorData
  = S String -- ^ Out of scope variable
  | O        -- ^ Bang outside of do

mkErrors :: [ErrorData] -> [PsMessage]
mkErrors = map (customError . toError)
  where
    toError = \cases
      (S var) -> ErrOutOfScopeVariable $ mkVarOcc var
      O -> ErrBangOutsideOfDo

combined :: Test
combined = assertParseFailWith (mkErrors [S "x", S "f", S "a", S "b", S "b", O, O]) "\
\!(!do\n\
\  x <- getA\n\
\  let y = let x = print 24 in !x\n\
\  let f (a, b) = !(f a) + !(let c = c + b in c + b + z)\n\
\  pure y)\n\
\"

various :: Test
various = assertParseFailWith (mkErrors [S "a", S "x", S "y", S "b", S "b1", S "a2", O, O, O]) "\
\main = !getA\n\
\g = do let a = x in !a\n\
\       pure ()\n\
\f = !getB\n\
\h = \\x -> !x\n\
\i = do \\y -> !y\n\
\j = let z = z in do \\_ -> !z -- no error\n\
\k = case () of a -> do case () of b -> !(a + b)\n\
\l = let c1 = c1 in do let b1 = b1 in !(let c1 = c1 in a1 + b1 + c1)\n\
\m = do !(let a2 = a2 in !a2)\n\
\"

letStmt :: Test
letStmt = assertParseFailWith (mkErrors [S "x"]) "\
\main = do\n\
\  let x = !x\n\
\  pure x\n\
\"

letInLet :: Test
letInLet = assertParseFailWith (mkErrors [S "y", S "x"]) "\
\main = do\n\
\  let x _ = x in let y = y in !y + !x\n\
\"
