Make stack flags customizable in GNUmakefile.
[haskell/symantic.git] / symantic-lib / Language / Symantic / Typing / Test.hs
index 349b807bd921d4299605fa931d6dcd429e05d62d..194f0a5ef4e4873c2ea370173244088151e407df 100644 (file)
@@ -1,3 +1,4 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Typing.Test where
@@ -7,111 +8,178 @@ import Test.Tasty.HUnit
 
 import Control.Applicative (Applicative(..))
 import Control.Arrow (left)
+import Data.Functor.Identity (Identity(..))
+import Data.List.NonEmpty (NonEmpty)
+import Data.Map.Strict (Map)
 import Data.Maybe (isJust)
+import Data.NonNull (NonNull)
 import Data.Proxy
+import Data.Ratio (Ratio)
+import Data.Text (Text)
 import GHC.Exts (Constraint)
 import Prelude hiding (exp)
+import qualified Control.Monad.Classes.Run as MC
+import qualified Control.Monad.Trans.State.Strict as SS
+import qualified Data.Function as Fun
+import qualified Data.Map.Strict as Map
+import qualified Data.MonoTraversable as MT
+import qualified Data.Sequences as Seqs
+import qualified System.IO as IO
 import qualified Text.Megaparsec as P
+import qualified Text.Megaparsec.Prim as P
 
-import Language.Symantic.Parsing
-import Language.Symantic.Typing
-import Language.Symantic.Lib ()
-import Language.Symantic.Lib.Lambda ((~>))
-import Language.Symantic.Helper.Data.Type.List
+import Language.Symantic.Grammar
+import Language.Symantic
+import Language.Symantic.Lib hiding ((<$>), (<*), show)
 
-import Parsing.Test
+import Grammar.Megaparsec ()
 
 -- * Tests
-type Tys = Constants ++ '[Proxy String]
-instance
- ( ParsecC e s
- , Gram_Meta meta (P.ParsecT e s m)
- ) => Gram_Type meta (P.ParsecT e s m)
+type SS =
+ [ Proxy (->)
+ , Proxy Bool
+ , Proxy []
+ , Proxy ()
+ , Proxy (,)
+ , Proxy Char
+ , Proxy Either
+ , Proxy Int
+ , Proxy Integer
+ , Proxy IO
+ , Proxy IO.Handle
+ , Proxy IO.IOMode
+ , Proxy Ordering
+ , Proxy Map
+ , Proxy Maybe
+ , Proxy NonNull
+ , Proxy Ratio
+ , Proxy Text
+ , Proxy Applicative
+ , Proxy Bounded
+ , Proxy Enum
+ , Proxy Eq
+ , Proxy Foldable
+ , Proxy Functor
+ , Proxy Integral
+ , Proxy Monad
+ , Proxy Monoid
+ , Proxy MT.MonoFoldable
+ , Proxy MT.MonoFunctor
+ , Proxy Num
+ , Proxy Ord
+ , Proxy Real
+ , Proxy Seqs.IsSequence
+ , Proxy Seqs.SemiSequence
+ , Proxy Show
+ , Proxy Traversable
+ ]
+type SRC = SrcTe (NonEmpty P.SourcePos) SS
+
+impsTy :: Imports NameTy
+impsTy = importTypes @SS []
+
+modsTy :: Source src => ModulesTy src
+modsTy =
+       Map.insert ([] `Mod` "String")
+        (TypeTLen $ \len -> TypeT $
+               tyConstLen @(K [])   @[]   len `tyApp`
+               tyConstLen @(K Char) @Char len) $
+       modulesTyInj @SS
+
+parseTy ::
+ forall src g err inp.
+ g ~ P.ParsecT err inp (SS.StateT (Imports NameTy, ModulesTy src) Identity) =>
+ P.MonadParsec err inp (P.ParsecT err inp g) =>
+ Gram_Type src g =>
+ P.Token inp ~ Char =>
+ inp -> Either (P.ParseError Char err) (AST_Type src)
+parseTy inp =
+       runIdentity $
+       MC.evalStateStrict (impsTy, modsTy @src) $
+       P.runParserT g "" inp
+       where g = unCF $ g_type <* eoi
 
 tests :: TestTree
 tests = testGroup "Typing" $
- [ testGroup "compile_Type" $
-       let run inp exp = testCase inp $ got @?= Right (Right exp)
+ [ testGroup "readType" $
+       let run inp (TypeT exp :: TypeT SRC '[]) =
+               testCase inp $ got @?= Right (Right $ TypeVT exp)
                where
                got :: Either (P.ParseError Char P.Dec)
-                             (Either (Error_Type P.SourcePos '[Proxy Token_Type])
-                                     (EType Tys))
-               got = compile_EType <$> P.runParser (unCF g) "" inp
-               g :: Gram_Type P.SourcePos g => CF g (TokType P.SourcePos)
-               g = typeG <* eoi in
+                             (Either (Error_Type SRC) (TypeVT SRC))
+               got = readType <$> parseTy inp
+               in
        let (==>) = run; infixr 0 ==> in
-        [ "Bool"                        ==> EType $ ty @Bool
-        , "[]"                          ==> EType $ ty @[]
-        , "[Char]"                      ==> EType $ ty @[] :$ ty @Char
-        , "[Char -> [Char]]"            ==> EType $ ty @[] :$ (ty @Char ~> ty @[] :$ ty @Char)
-        , "([])"                        ==> EType $ ty @[]
-        , "[()]"                        ==> EType $ ty @[] :$ ty @()
-        , "()"                          ==> EType $ ty @()
-        , "(())"                        ==> EType $ ty @()
-        , "(,)"                         ==> EType $ ty @(,)
-        , "((,))"                       ==> EType $ ty @(,)
-        , "(,) Int"                     ==> EType $ ty @(,) :$ ty @Int
-        , "(Bool)"                      ==> EType $ ty @Bool
-        , "((Bool))"                    ==> EType $ ty @Bool
-        , "(Bool, Int)"                 ==> EType $ ty @(,) :$ ty @Bool :$ ty @Int
-        , "((Bool, Int))"               ==> EType $ ty @(,) :$ ty @Bool :$ ty @Int
-        , "((Bool, Int), Char)"         ==> EType $ ty @(,) :$ (ty @(,) :$ ty @Bool :$ ty @Int) :$ ty @Char
-        , "(Bool, Int) -> Char"         ==> EType $ (ty @(,) :$ ty @Bool :$ ty @Int) ~> ty @Char
-        , "(Bool -> Int)"               ==> EType $ ty @Bool ~> ty @Int
-        , "String"                      ==> EType $ ty @[] :$ ty @Char
-        , "[Char] -> String"            ==> EType $ ty @[] :$ ty @Char ~> ty @[] :$ ty @Char
-        , "String -> [Char]"            ==> EType $ ty @[] :$ ty @Char ~> ty @[] :$ ty @Char
-        , "Maybe Bool"                  ==> EType $ ty @Maybe :$ ty @Bool
-        , "Either Bool Int"             ==> EType $ ty @Either :$ ty @Bool :$ ty @Int
-        , "Bool -> Int"                 ==> EType $ ty @Bool ~> ty @Int
-        , "(Bool -> Int) -> Char"       ==> EType $ (ty @Bool ~> ty @Int) ~> ty @Char
-        , "Bool -> (Int -> Char)"       ==> EType $ ty @Bool ~> (ty @Int ~> ty @Char)
-        , "Bool -> Int -> Char"         ==> EType $ ty @Bool ~> ty @Int ~> ty @Char
-        , "Bool -> (Int -> Char) -> ()" ==> EType $ ty @Bool ~> (ty @Int ~> ty @Char) ~> ty @()
-        , "IO"                          ==> EType $ ty @IO
-        , "Eq"                          ==> EType $ ty @Eq
-        , "Eq Bool"                     ==> EType $ ty @Eq :$ ty @Bool
-        , "Traversable IO"              ==> EType $ ty @Traversable :$ ty @IO
-        , "Monad IO"                    ==> EType $ ty @Monad :$ ty @IO
-        , "(->) Bool"                   ==> EType $ ty @(->) :$ ty @Bool
-        , "(->) (IO Bool)"              ==> EType $ ty @(->) :$ (ty @IO :$ ty @Bool)
-        , "Monad IO"                    ==> EType $ ty @Monad :$ ty @IO
+        [ "Bool"                        ==> TypeT $ tyBool
+        , "(->) Bool"                   ==> TypeT $ tyFun `tyApp` tyBool
+        , "[]"                          ==> TypeT $ tyConst @(K []) @[]
+        , "[Char]"                      ==> TypeT $ tyList tyChar
+        , "[Char -> [Char]]"            ==> TypeT $ tyList (tyChar ~> tyList tyChar)
+        , "([])"                        ==> TypeT $ tyConst @(K []) @[]
+        , "[()]"                        ==> TypeT $ tyList tyUnit
+        , "()"                          ==> TypeT $ tyUnit
+        , "(())"                        ==> TypeT $ tyUnit
+        , "(,)"                         ==> TypeT $ tyConst @(K (,)) @(,)
+        , "((,))"                       ==> TypeT $ tyConst @(K (,)) @(,)
+        , "(,) Int"                     ==> TypeT $ tyConst @(K (,)) @(,) `tyApp` tyInt
+        , "(Bool)"                      ==> TypeT $ tyBool
+        , "((Bool))"                    ==> TypeT $ tyBool
+        , "(Bool, Int)"                 ==> TypeT $ tyBool `tyTuple2` tyInt
+        , "((Bool, Int))"               ==> TypeT $ tyBool `tyTuple2` tyInt
+        , "((Bool, Int), Char)"         ==> TypeT $ (tyBool `tyTuple2` tyInt) `tyTuple2` tyChar
+        , "(Bool, Int) -> Char"         ==> TypeT $ (tyBool `tyTuple2` tyInt) ~> tyChar
+        , "(Bool -> Int)"               ==> TypeT $ tyBool ~> tyInt
+        , "String"                      ==> TypeT $ tyList tyChar
+        , "[Char] -> String"            ==> TypeT $ tyList tyChar ~> tyList tyChar
+        , "String -> [Char]"            ==> TypeT $ tyList tyChar ~> tyList tyChar
+        , "Maybe Bool"                  ==> TypeT $ tyMaybe tyBool
+        , "Either Bool Int"             ==> TypeT $ tyEither tyBool tyInt
+        , "Bool -> Int"                 ==> TypeT $ tyBool ~> tyInt
+        , "(Bool -> Int) -> Char"       ==> TypeT $ (tyBool ~> tyInt) ~> tyChar
+        , "Bool -> (Int -> Char)"       ==> TypeT $ tyBool ~> (tyInt ~> tyChar)
+        , "Bool -> Int -> Char"         ==> TypeT $ tyBool ~> tyInt ~> tyChar
+        , "Bool -> (Int -> Char) -> ()" ==> TypeT $ tyBool ~> (tyInt ~> tyChar) ~> tyUnit
+        , "IO"                          ==> TypeT $ tyConst @(K IO) @IO
+        , "Traversable IO"              ==> TypeT $ tyTraversable (tyConst @(K IO) @IO)
+        , "Monad IO"                    ==> TypeT $ tyMonad (tyConst @(K IO) @IO)
+        , "(->) (IO Bool)"              ==> TypeT $ tyConst @(K (->)) @(->) `tyApp` (tyIO tyBool)
+        , "Monad IO"                    ==> TypeT $ tyMonad (tyConst @(K IO) @IO)
+        , "Eq"                          ==> TypeT $ tyConst @(K Eq) @Eq
+        , "Eq Bool"                     ==> TypeT $ tyEq tyBool
         ]
         , testGroup "Parsing errors" $
                let run inp = testCase inp $ got @?= Left ()
                        where
-                       got :: Either () (TokType P.SourcePos)
-                       got = left (\(_::P.ParseError (P.Token String) P.Dec) -> ()) $ P.runParser (unCF g) "" inp
-                       g :: Gram_Type P.SourcePos g => CF g (TokType P.SourcePos)
-                       g = typeG <* eoi in
+                       got :: Either () (AST_Type SRC)
+                       got = left (\(_::P.ParseError (P.Token String) P.Dec) -> ()) $ parseTy inp in
                run <$>
                 [ "Bool, Int"
                 , "(Bool -> Int) Char"
+                , "NonExistingType"
                 ]
         , testGroup "Compiling errors" $
                let run inp = testCase inp $ got @?= Right (Left ())
                        where
-                       got :: Either (P.ParseError Char P.Dec) (Either () (EType Tys))
-                       got = left (const ()) . compile_EType <$> P.runParser (unCF g) "" inp
-                       g :: Gram_Type P.SourcePos g => CF g (TokType P.SourcePos)
-                       g = typeG <* eoi in
+                       got :: Either (P.ParseError Char P.Dec) (Either () (TypeVT SRC))
+                       got = left (Fun.const ()) . readType <$> parseTy inp in
                run <$>
-                [ "NonExistingType"
-                , "Bool Int"
+                [ "Bool Int"
                 , "[IO]"
                 , "(->) IO"
                 , "(->) Bool Int Char"
                 , "Monad Eq"
                 ]
- , testGroup "proj_TyCon" $
-       let (==>) (typ::Type Constants (h::Constraint)) expected =
-               testCase (show_Type typ) $
-               isJust (proj_TyCon typ) @?= expected in
-        [ ty @Eq          :$ ty @Bool  ==> True
-        , ty @Ord         :$ ty @Bool  ==> True
-        , ty @Functor     :$ ty @Maybe ==> True
-        , ty @Functor     :$ ty @IO    ==> True
-        , ty @Monad       :$ ty @IO    ==> True
-        , ty @Traversable :$ ty @IO    ==> False
+ , testGroup "proveConstraint" $
+       let (==>) (typ::Type SRC SS (t::Constraint)) expected =
+               let imps = importTypes @SS [] in
+               let conf = config_Doc_Type{config_Doc_Type_imports = imps} in
+               testCase (showType conf typ) $
+               isJust (proveConstraint typ) @?= expected in
+        [ tyEq          tyBool                      ==> True
+        , tyOrd         tyBool                      ==> True
+        , tyFunctor     (tyConst @(K Maybe) @Maybe) ==> True
+        , tyFunctor     (tyConst @(K IO) @IO)       ==> True
+        , tyMonad       (tyConst @(K IO) @IO)       ==> True
+        , tyTraversable (tyConst @(K IO) @IO)       ==> False
         ]
  ]