packages feed

language-lua2-0.1.0.4: test/Instances.hs

{-# LANGUAGE CPP                  #-}
{-# LANGUAGE ConstraintKinds      #-}
{-# LANGUAGE DeriveGeneric        #-}
{-# LANGUAGE OverloadedLists      #-}
{-# LANGUAGE StandaloneDeriving   #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Instances where

import Language.Lua.Token
import Language.Lua.Syntax
import Language.Lua.Parser (NodeInfo)

import           Control.Applicative
import           Control.DeepSeq
import           Data.Char                  (isAsciiLower, isAsciiUpper, isDigit)
import           Data.HashSet               (HashSet)
import qualified Data.HashSet               as HS
import           Data.List.NonEmpty         (NonEmpty)
import qualified Data.List.NonEmpty         as NE
import           Data.Loc                   (L(..), Loc(..), Pos(..))
import           GHC.Generics               (Generic)
import           Test.QuickCheck.Arbitrary
import           Test.QuickCheck.Gen

--------------------------------------------------------------------------------
-- Arbitrary

#if !MIN_VERSION_base(4,8,0)
import Data.Typeable (Typeable)
type C a = (Arbitrary a, Typeable a)
#else
type C a = Arbitrary a
#endif

instance C a => Arbitrary (Ident a) where
    arbitrary = Ident <$> arbitrary <*> genIdent
      where
        genIdent :: Gen String
        genIdent = liftA2 (:) first rest `suchThat` \s -> not (HS.member s keywords)
          where
            first :: Gen Char
            first = frequency [(5, pure '_'), (95, arbitrary `suchThat` isAsciiLetter)]

            rest :: Gen String
            rest = listOf $
                frequency [ (10, pure '_')
                          , (45, arbitrary `suchThat` isAsciiLetter)
                          , (45, arbitrary `suchThat` isDigit)
                          ]

            -- Meh, forget unicode for now.
            isAsciiLetter :: Char -> Bool
            isAsciiLetter c = isAsciiLower c || isAsciiUpper c

        keywords :: HashSet String
        keywords = HS.fromList
            [ "and", "break", "do", "else", "elseif", "end", "false"
            , "for", "function", "goto", "if", "in", "local", "nil"
            , "not", "or", "repeat", "return", "then", "true", "until", "while"
            ]

instance C a => Arbitrary (IdentList a) where
    arbitrary = IdentList <$> arbitrary <*> arbitrary
    shrink = genericShrink

instance C a => Arbitrary (IdentList1 a) where
    arbitrary = IdentList1 <$> arbitrary <*> arbitrary
    shrink = genericShrink

instance C a => Arbitrary (Block a) where
    arbitrary = Block <$> arbitrary <*> listOf1 arbitrary <*> arbitrary
    shrink = genericShrink

instance C a => Arbitrary (Statement a) where
    arbitrary = oneof
        [ EmptyStmt      <$> arbitrary
        , Assign         <$> arbitrary <*> arbitrary <*> arbitrary
        , FunCall        <$> arbitrary <*> arbitrary
        , Label          <$> arbitrary <*> arbitrary
        , Break          <$> arbitrary
        , Goto           <$> arbitrary <*> arbitrary
        , Do             <$> arbitrary <*> arbitrary
        , While          <$> arbitrary <*> arbitrary <*> arbitrary
        , Repeat         <$> arbitrary <*> arbitrary <*> arbitrary
        , If             <$> arbitrary <*> arbitrary <*> arbitrary
        , For            <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
        , ForIn          <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
        , FunAssign      <$> arbitrary <*> arbitrary <*> arbitrary
        , LocalFunAssign <$> arbitrary <*> arbitrary <*> arbitrary
        , LocalAssign    <$> arbitrary <*> arbitrary <*> arbitrary
        ]

    shrink = genericShrink

instance C a => Arbitrary (ReturnStatement a) where
    arbitrary = ReturnStatement <$> arbitrary <*> arbitrary
    shrink = genericShrink

instance C a => Arbitrary (FunctionName a) where
    arbitrary = FunctionName <$> arbitrary <*> arbitrary <*> arbitrary
    shrink = genericShrink

instance C a => Arbitrary (Variable a) where
    arbitrary = oneof
        [ VarIdent     <$> arbitrary <*> arbitrary
        , VarField     <$> arbitrary <*> arbitrary <*> arbitrary
        , VarFieldName <$> arbitrary <*> arbitrary <*> arbitrary
        ]

    shrink = genericShrink

instance C a => Arbitrary (VariableList1 a) where
    arbitrary = VariableList1 <$> arbitrary <*> arbitrary

instance C a => Arbitrary (Expression a) where
    arbitrary = oneof
        [ Nil       <$> arbitrary
        , Bool      <$> arbitrary <*> arbitrary
        , Integer   <$> arbitrary <*> (show <$> (arbitrary :: Gen Int)) -- TODO: Make these better
        , Float     <$> arbitrary <*> (show <$> (arbitrary :: Gen Float))
        , String    <$> arbitrary <*> arbitrary
        , Vararg    <$> arbitrary
        , FunDef    <$> arbitrary <*> arbitrary
        , PrefixExp <$> arbitrary <*> arbitrary
        , TableCtor <$> arbitrary <*> arbitrary
        , Binop     <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
        , Unop      <$> arbitrary <*> arbitrary <*> arbitrary
        ]

    shrink = genericShrink

instance C a => Arbitrary (ExpressionList a) where
    arbitrary = ExpressionList <$> arbitrary <*> arbitrary

instance C a => Arbitrary (ExpressionList1 a) where
    arbitrary = ExpressionList1 <$> arbitrary <*> arbitrary

instance C a => Arbitrary (PrefixExpression a) where
    arbitrary = oneof
        [ PrefixVar     <$> arbitrary <*> arbitrary
        , PrefixFunCall <$> arbitrary <*> arbitrary
        , Parens        <$> arbitrary <*> arbitrary
        ]

    shrink = genericShrink

instance C a => Arbitrary (FunctionCall a) where
    arbitrary = oneof
        [ FunctionCall <$> arbitrary <*> arbitrary <*> arbitrary
        , MethodCall   <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
        ]

    shrink = genericShrink

instance C a => Arbitrary (FunctionArgs a) where
    arbitrary = oneof
        [ Args       <$> arbitrary <*> arbitrary
        , ArgsTable  <$> arbitrary <*> arbitrary
        , ArgsString <$> arbitrary <*> arbitrary
        ]

    shrink = genericShrink

instance C a => Arbitrary (FunctionBody a) where
    arbitrary = FunctionBody <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
    shrink = genericShrink

instance C a => Arbitrary (TableConstructor a) where
    arbitrary = TableConstructor <$> arbitrary <*> arbitrary
    shrink = genericShrink

instance C a => Arbitrary (Field a) where
    arbitrary = oneof
        [ FieldExp   <$> arbitrary <*> arbitrary <*> arbitrary
        , FieldIdent <$> arbitrary <*> arbitrary <*> arbitrary
        , Field      <$> arbitrary <*> arbitrary
        ]

    shrink = genericShrink

instance C a => Arbitrary (FieldList a) where
    arbitrary = FieldList <$> arbitrary <*> arbitrary
    shrink = genericShrink

instance C a => Arbitrary (Binop a) where
    arbitrary = oneof
        [ Plus       <$> arbitrary
        , Minus      <$> arbitrary
        , Mult       <$> arbitrary
        , FloatDiv   <$> arbitrary
        , FloorDiv   <$> arbitrary
        , Exponent   <$> arbitrary
        , Modulo     <$> arbitrary
        , BitwiseAnd <$> arbitrary
        , BitwiseXor <$> arbitrary
        , BitwiseOr  <$> arbitrary
        , Rshift     <$> arbitrary
        , Lshift     <$> arbitrary
        , Concat     <$> arbitrary
        , Lt         <$> arbitrary
        , Leq        <$> arbitrary
        , Gt         <$> arbitrary
        , Geq        <$> arbitrary
        , Eq         <$> arbitrary
        , Neq        <$> arbitrary
        , And        <$> arbitrary
        , Or         <$> arbitrary
        ]

    shrink = genericShrink

instance C a => Arbitrary (Unop a) where
    arbitrary = oneof
        [ Negate     <$> arbitrary
        , Not        <$> arbitrary
        , Length     <$> arbitrary
        , BitwiseNot <$> arbitrary
        ]

    shrink = genericShrink

--------------------------------------------------------------------------------
-- NFData

instance NFData NodeInfo
instance NFData Token

instance NFData a => NFData (Ident a)
instance NFData a => NFData (IdentList a)
instance NFData a => NFData (IdentList1 a)
instance NFData a => NFData (Block a)
instance NFData a => NFData (Statement a)
instance NFData a => NFData (ReturnStatement a)
instance NFData a => NFData (FunctionName a)
instance NFData a => NFData (Variable a)
instance NFData a => NFData (VariableList1 a)
instance NFData a => NFData (Expression a)
instance NFData a => NFData (ExpressionList a)
instance NFData a => NFData (ExpressionList1 a)
instance NFData a => NFData (PrefixExpression a)
instance NFData a => NFData (FunctionCall a)
instance NFData a => NFData (FunctionArgs a)
instance NFData a => NFData (FunctionBody a)
instance NFData a => NFData (TableConstructor a)
instance NFData a => NFData (Field a)
instance NFData a => NFData (FieldList a)
instance NFData a => NFData (Binop a)
instance NFData a => NFData (Unop a)

-- Orphans

instance Arbitrary a => Arbitrary (NonEmpty a) where
    arbitrary = NE.fromList <$> listOf1 arbitrary

deriving instance Generic a => Generic (L a)
instance (Generic a, NFData a) => NFData (L a)

deriving instance Generic Loc
instance NFData Loc

deriving instance Generic Pos
instance NFData Pos