module TestTypechecker where

import Test.HUnit

import Parser
import Typechecker

intCheck :: Assertion
intCheck = parseAndTypecheck "60" "int"

if0Check :: Assertion
if0Check = parseAndTypecheck "if0 5 then <> else <>" "unit"

absCheck :: Assertion
absCheck = parseAndTypecheck "func [] (x:int) . x" "forall [] (int) -> int"

-- The following should fail, since we need a type annotation for the function
-- appCheck :: Assertion
-- appCheck = parseAndTypecheck "((func [] (x:int) . x) [] 12)" "int"

annotatedAppCheck :: Assertion
annotatedAppCheck = parseAndTypecheck "(((func [] (x:int) . x) : forall [] (int) -> int) [] (12))" "int"

tyAppCheck :: Assertion
tyAppCheck = parseAndTypecheck "(((func [α] (x:α) . x) : forall [α] (α) -> α) [int] (13))" "int"

handleCheck :: Assertion
handleCheck = parseAndTypecheck "handle (1; x.2)" "int"

raiseCheck :: Assertion
raiseCheck = parseAndTypecheck "raise [int] 1" "int"

letCheck :: Assertion
letCheck = parseAndTypecheck "let x = 1 in <>" "unit"

letAnnoCheck :: Assertion
letAnnoCheck = parseAndTypecheck "let x = (1:int) in <>" "unit"

parseAndTypecheck :: String -> String -> Assertion
parseAndTypecheck ex typ =
  case (parseExpr ex, parseType typ) of
    (Left err, _) -> assertFailure $ show err
    (_, Left err) -> assertFailure $ show err
    (Right e, Right τ) -> (typeCheckProgram e τ) @?= (Right True)

