packages feed

hic-0.0.0.1: test/Language/Cimple/Analysis/Refined/Arbitrary.hs

{-# LANGUAGE FlexibleInstances   #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-orphans #-}

module Language.Cimple.Analysis.Refined.Arbitrary where

import           Data.Bits                                    (shiftL, (.&.),
                                                               (.|.))
import           Data.Foldable                                (foldlM)
import           Data.IntMap.Strict                           (IntMap)
import qualified Data.IntMap.Strict                           as IntMap
import           Data.List                                    (foldl')
import qualified Data.List                                    as List
import           Data.Map.Strict                              (Map)
import qualified Data.Map.Strict                              as Map
import           Data.Text                                    (Text)
import qualified Data.Text                                    as T
import           Data.Word                                    (Word32, Word64)
import           Language.Cimple                              (AlexPosn (..),
                                                               Lexeme (..),
                                                               LexemeClass (..))
import           Language.Cimple.Analysis.Refined.Context
import           Language.Cimple.Analysis.Refined.LatticeOp
import           Language.Cimple.Analysis.Refined.PathContext
import           Language.Cimple.Analysis.Refined.Solver
import           Language.Cimple.Analysis.Refined.State
import           Language.Cimple.Analysis.Refined.Types
import           Test.QuickCheck                              (Arbitrary (..),
                                                               Gen,
                                                               arbitraryBoundedEnum,
                                                               choose, elements,
                                                               listOf, listOf1,
                                                               oneof, resize,
                                                               scale, sized,
                                                               vectorOf)

instance Arbitrary StdType where
    arbitrary = arbitraryBoundedEnum

instance Arbitrary Quals where
    arbitrary = Quals <$> arbitrary

instance Arbitrary Nullability where
    arbitrary = arbitraryBoundedEnum

instance Arbitrary Ownership where
    arbitrary = arbitraryBoundedEnum

instance Arbitrary Polarity where
    arbitrary = arbitraryBoundedEnum

instance Arbitrary Variance where
    arbitrary = arbitraryBoundedEnum

instance Arbitrary LatticePhase where
    arbitrary = arbitraryBoundedEnum

instance Arbitrary TemplateId where
    arbitrary = oneof $
        [ TIdName . T.pack <$> listOf1 (elements ['a'..'z'])
        , TIdParam <$> arbitrary <*> arbitrary <*> pure Nothing
        , TIdSkolem <$> arbitrary <*> arbitrary <*> arbitrary
        , TIdInstance <$> arbitrary
        , TIdDeBruijn <$> choose (0, 30)
        ] ++
        -- Stable 'Nuisance' Names often encountered in Inference
        [ pure (TIdName "LIT_0")
        , pure (TIdName "T")
        , pure (TIdName "U")
        , TIdSkolem <$> elements [10, 20, 100] <*> elements [10, 20, 100] <*> choose (0, 5)
        ]

instance Arbitrary MappingContext where
    arbitrary = do
        count <- choose (0, 30)
        let n1 = min 14 count
        w1Data <- foldl' (\acc i -> (acc `shiftL` 4) .|. (i .&. 0xF)) 0 <$> vectorOf n1 (choose (0 :: Word64, 15))
        let w1 = (w1Data `shiftL` 8) .|. fromIntegral count

        let n2 = if count > 14 then count - 14 else 0
        w2 <- foldl' (\acc i -> (acc `shiftL` 4) .|. (i .&. 0xF)) 0 <$> vectorOf n2 (choose (0 :: Word64, 15))
        return $ MappingContext w1 w2

instance Arbitrary MappingRefinements where
    arbitrary = do
        count <- choose (0, 8)
        keys <- vectorOf count (arbitrary :: Gen Int)
        foldlM (\r k -> do
            nodeID <- arbitrary
            return $ setRefinement k nodeID r) emptyRefinements keys

instance Arbitrary ProductState where
    arbitrary = ProductState <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> choose (0, 30) <*> choose (0, 30) <*> oneof [pure Nothing, Just <$> ((,) <$> choose (0, 30) <*> arbitrary)]

instance Arbitrary PathRoot where
    arbitrary = oneof
        [ VarRoot <$> arbitrary
        , ParamRoot <$> arbitrary
        , InstanceRoot <$> arbitrary
        ]

instance Arbitrary PathStep where
    arbitrary = oneof
        [ FieldStep <$> arbitrary
        , IndexStep <$> arbitrary
        , VarStep <$> arbitrary
        ]

instance Arbitrary SymbolicPath where
    arbitrary = SymbolicPath <$> arbitrary <*> arbitrary

instance Arbitrary ValueConstraint where
    arbitrary = oneof [EqConst <$> arbitrary, NotConst <$> arbitrary, EqVariant <$> arbitrary]

instance Arbitrary PathContext where
    arbitrary = PathContext <$> arbitrary <*> arbitrary

instance Arbitrary T.Text where
    arbitrary = T.pack <$> listOf1 (elements ['a'..'z'])

instance (Arbitrary a, Ord a) => Arbitrary (AnyRigidNodeF TemplateId a) where
    arbitrary = oneof
        [ AnyRigidNodeF <$> (RObject <$> arbitrary <*> arbitrary)
        , AnyRigidNodeF <$> (RReference <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary)
        , AnyRigidNodeF <$> (RFunction <$> arbitrary <*> arbitrary)
        , AnyRigidNodeF <$> (RTerminal <$> arbitrary)
        ]

instance (Arbitrary a, Ord a) => Arbitrary (ObjectStructure TemplateId a) where
    arbitrary = sized $ \n ->
        let sub = resize (n `div` 2) arbitrary
            listLimit = scale (`div` 4)
        in oneof $
            [ VBuiltin <$> arbitrary
            , VSingleton <$> arbitrary <*> arbitrary
            , VNominal . dummyL . TIdName . T.pack <$> listOf1 (elements ['A'..'Z']) <*> listLimit (listOf sub)
            , VEnum . dummyL . TIdName . T.pack <$> listOf1 (elements ['A'..'Z'])
            , VVar <$> arbitrary <*> oneof [pure Nothing, Just <$> (IVar <$> arbitrary)]
            , VVariant . IntMap.fromList <$> listLimit (listOf ((,) <$> arbitrary <*> sub))
            , VProperty <$> sub <*> arbitrary
            , do terms <- Map.fromListWith (+) <$> listLimit (listOf1 ((,) <$> sub <*> choose (1, 10)))
                 return $ VSizeExpr (Map.toList terms)
            ] ++
            [ do count <- choose (1, 3)
                 body <- sub
                 return $ VExistential (map TIdDeBruijn [0..count-1]) body
            | n > 0 ] ++
            [ do body <- resize (n - 1) arbitrary
                 return $ VExistential [TIdDeBruijn 0] body
            | n > 2 ]

instance Arbitrary a => Arbitrary (RefStructure TemplateId a) where
    arbitrary = sized $ \n ->
        let sub = resize (n `div` 2) arbitrary
            listLimit = scale (`div` 4)
        in oneof
            [ Arr <$> sub <*> listLimit (listOf sub)
            , Ptr <$> arbitrary
            ]

instance Arbitrary a => Arbitrary (PtrTarget TemplateId a) where
    arbitrary = sized $ \n ->
        let sub = resize (n `div` 2) arbitrary
            listLimit = scale (`div` 4)
        in oneof
            [ TargetObject <$> sub
            , TargetFunction <$> listLimit (listOf sub) <*> arbitrary
            , TargetOpaque <$> arbitrary
            ]

instance Arbitrary a => Arbitrary (ReturnType a) where
    arbitrary = oneof [RetVal <$> arbitrary, pure RetVoid]

instance Arbitrary a => Arbitrary (TerminalNode a) where
    arbitrary = oneof [pure SBottom, pure SAny, pure SConflict]

instance Arbitrary PropertyKind where
    arbitrary = oneof
        [ pure PSize
        , pure PAlign
        , POffset . T.pack <$> listOf1 (elements ['a'..'z'])
        ]

instance Arbitrary a => Arbitrary (Index a) where
    arbitrary = oneof [ILit <$> arbitrary, IVar <$> arbitrary]

instance Arbitrary StructureKind where
    arbitrary = arbitraryBoundedEnum

instance Arbitrary Constraint where
    arbitrary = oneof
        [ do l <- choose (0, 20)
             r <- choose (0, 20)
             pol <- arbitrary
             ctx <- arbitrary
             path <- arbitrary
             dL <- choose (0, 30)
             dR <- choose (0, 30)
             return $ CSubtype l r pol ctx path dL dR
        , do l <- choose (0, 20)
             r <- choose (0, 20)
             return $ CInherit l r
        ]

-- | Helper for dummy Lexemes in tests.
dummyL :: t -> Lexeme t
dummyL = L (AlexPn 0 0 0) IdSueType