packages feed

axel-0.0.13: test/Axel/Test/ASTGen.hs

module Axel.Test.ASTGen where

import Axel.Prelude

import qualified Axel.AST as AST
import qualified Axel.Sourcemap as SM

import Control.Applicative
import Control.Lens (isn't)

import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

import TestUtils

genIdentifier :: (MonadGen m) => m AST.Identifier
genIdentifier = Gen.text (Range.linear 1 5) Gen.alpha

genLiteral :: (MonadGen m) => m (AST.Literal (Maybe SM.Expression))
genLiteral =
  Gen.choice
    [ AST.LChar Nothing <$> Gen.unicode
    , AST.LFloat Nothing <$> Gen.float (Range.exponentialFloat (-10000) 10000)
    , AST.LInt Nothing <$> Gen.int Range.constantBounded
    , AST.LString Nothing <$> Gen.text (Range.linear 0 5) Gen.unicode
    ]

genCaseBlock :: (MonadGen m) => m (AST.CaseBlock (Maybe SM.Expression))
genCaseBlock =
  AST.CaseBlock Nothing <$> genExpression <*>
  Gen.list (Range.linear 0 10) ((,) <$> genExpression <*> genExpression)

genFunctionApplication ::
     (MonadGen m) => m (AST.FunctionApplication (Maybe SM.Expression))
genFunctionApplication =
  AST.FunctionApplication Nothing <$>
  Gen.filter (isn't AST._EEmptySExpression) genExpression <*>
  Gen.list (Range.linear 0 10) genExpression

genLambda :: (MonadGen m) => m (AST.Lambda (Maybe SM.Expression))
genLambda =
  AST.Lambda Nothing <$> Gen.list (Range.linear 0 10) genExpression <*>
  genExpression

genLetBlock :: (MonadGen m) => m (AST.LetBlock (Maybe SM.Expression))
genLetBlock =
  AST.LetBlock Nothing <$>
  Gen.list (Range.linear 0 10) ((,) <$> genExpression <*> genExpression) <*>
  genExpression

genPatternBinding ::
     (MonadGen m) => m (AST.PatternBinding (Maybe SM.Expression))
genPatternBinding =
  AST.PatternBinding Nothing <$> (AST.EIdentifier Nothing <$> genIdentifier) <*>
  genExpression

genRawExpression :: (MonadGen m) => m Text
genRawExpression = Gen.text (Range.linear 0 10) Gen.unicode

genRecordDefinition ::
     (MonadGen m) => m (AST.RecordDefinition (Maybe SM.Expression))
genRecordDefinition =
  AST.RecordDefinition Nothing <$>
  Gen.list (Range.linear 0 10) ((,) <$> genIdentifier <*> genExpression)

genRecordType :: (MonadGen m) => m (AST.RecordType (Maybe SM.Expression))
genRecordType =
  AST.RecordType Nothing <$>
  Gen.list (Range.linear 0 10) ((,) <$> genIdentifier <*> genExpression)

genExpression :: (MonadGen m) => m (AST.Expression (Maybe SM.Expression))
genExpression =
  Gen.recursive
    Gen.choice
    [ pure $ AST.EEmptySExpression Nothing
    , AST.EIdentifier Nothing <$> genIdentifier
    ]
    [ AST.ECaseBlock <$> genCaseBlock
    , AST.EFunctionApplication <$> genFunctionApplication
    , AST.ELambda <$> genLambda
    , AST.ELetBlock <$> genLetBlock
    , AST.ELiteral <$> genLiteral
    , AST.EPatternBinding <$> genPatternBinding
    , AST.ERawExpression Nothing <$> genRawExpression
    , AST.ERecordDefinition <$> genRecordDefinition
    , AST.ERecordType <$> genRecordType
    ]

genTypeDefinition ::
     (MonadGen m) => m (AST.TypeDefinition (Maybe SM.Expression))
genTypeDefinition =
  Gen.choice
    [ AST.ProperType Nothing <$> genIdentifier
    , AST.TypeConstructor Nothing <$> genFunctionApplication
    ]

genDataDeclaration ::
     (Alternative m, MonadGen m)
  => m (AST.DataDeclaration (Maybe SM.Expression))
genDataDeclaration =
  AST.DataDeclaration Nothing <$> genTypeDefinition <*>
  Gen.list (Range.linear 0 10) genExpression <*>
  genConstraints

genFunctionDefinition ::
     (Alternative m, MonadGen m)
  => Maybe Int
  -> m (AST.FunctionDefinition (Maybe SM.Expression))
genFunctionDefinition numArgs =
  let genArgs =
        case numArgs of
          Just n -> Range.linear n n
          Nothing -> Range.linear 0 10
   in AST.FunctionDefinition Nothing <$> genIdentifier <*>
      Gen.list genArgs genExpression <*>
      genExpression <*>
      Gen.list
        (Range.linear 0 10)
        ((AST.STypeSignature <$> genTypeSignature) <|>
         (AST.SFunctionDefinition <$> genFunctionDefinition Nothing))

genPragma :: (MonadGen m) => m (AST.Pragma (Maybe SM.Expression))
genPragma = AST.Pragma Nothing <$> Gen.text (Range.linear 0 10) Gen.ascii

genMacroDefinition ::
     (Alternative m, MonadGen m)
  => m (AST.MacroDefinition (Maybe SM.Expression))
genMacroDefinition =
  AST.MacroDefinition Nothing <$> genFunctionDefinition (Just 1)

genImport :: (MonadGen m) => m (AST.Import (Maybe SM.Expression))
genImport =
  Gen.choice
    [ AST.ImportItem Nothing <$> genIdentifier
    , AST.ImportType Nothing <$> genIdentifier <*>
      Gen.list (Range.linear 0 10) genIdentifier
    ]

genImportSpecification ::
     (MonadGen m) => Bool -> m (AST.ImportSpecification (Maybe SM.Expression))
genImportSpecification importAll =
  let options =
        (AST.ImportOnly Nothing <$> Gen.list (Range.linear 0 10) genImport) :
        [pure $ AST.ImportAll Nothing | importAll]
   in Gen.choice options

genQualifiedImport ::
     (MonadGen m) => m (AST.QualifiedImport (Maybe SM.Expression))
genQualifiedImport =
  AST.QualifiedImport Nothing <$> genIdentifier <*> genIdentifier <*>
  genImportSpecification True

genMacroImport :: (MonadGen m) => m (AST.MacroImport (Maybe SM.Expression))
genMacroImport =
  AST.MacroImport Nothing <$> genIdentifier <*>
  Gen.list (Range.linear 0 10) genIdentifier

genNewtypeDeclaration ::
     (Alternative m, MonadGen m)
  => m (AST.NewtypeDeclaration (Maybe SM.Expression))
genNewtypeDeclaration =
  AST.NewtypeDeclaration Nothing <$> genTypeDefinition <*> genExpression <*>
  genConstraints

genRawStatement :: (MonadGen m) => m Text
genRawStatement = Gen.text (Range.linear 0 10) Gen.unicode

genRestrictedImport ::
     (MonadGen m) => Bool -> m (AST.RestrictedImport (Maybe SM.Expression))
genRestrictedImport importAll =
  AST.RestrictedImport Nothing <$> genIdentifier <*>
  genImportSpecification importAll

genTopLevel ::
     (Alternative m, MonadGen m) => m (AST.TopLevel (Maybe SM.Expression))
genTopLevel = AST.TopLevel Nothing <$> Gen.list (Range.linear 0 10) genStatement

genConstraints :: (Alternative m, MonadGen m) => m [AST.SMExpression]
genConstraints =
  Gen.list
    (Range.linear 0 10)
    ((AST.EIdentifier Nothing <$> genIdentifier) <|>
     (AST.EFunctionApplication <$> genFunctionApplication))

genTypeclassDefinition ::
     (Alternative m, MonadGen m)
  => m (AST.TypeclassDefinition (Maybe SM.Expression))
genTypeclassDefinition =
  AST.TypeclassDefinition Nothing <$>
  ((AST.EFunctionApplication <$> genFunctionApplication) <|>
   (AST.EIdentifier Nothing <$> genIdentifier)) <*>
  genConstraints <*>
  Gen.list (Range.linear 0 10) genTypeSignature

genTypeclassInstance ::
     (Alternative m, MonadGen m)
  => m (AST.TypeclassInstance (Maybe SM.Expression))
genTypeclassInstance =
  AST.TypeclassInstance Nothing <$>
  ((AST.EFunctionApplication <$> genFunctionApplication) <|>
   (AST.EIdentifier Nothing <$> genIdentifier)) <*>
  genConstraints <*>
  Gen.list (Range.linear 0 10) (genFunctionDefinition Nothing)

genTypeSignature ::
     (Alternative m, MonadGen m) => m (AST.TypeSignature (Maybe SM.Expression))
genTypeSignature =
  AST.TypeSignature Nothing <$> genIdentifier <*> genConstraints <*>
  genExpression

genTypeSynonym :: (MonadGen m) => m (AST.TypeSynonym (Maybe SM.Expression))
genTypeSynonym = AST.TypeSynonym Nothing <$> genExpression <*> genExpression

genStatement :: (Alternative m, MonadGen m) => m AST.SMStatement
genStatement =
  Gen.recursive
    Gen.choice
    [ AST.SDataDeclaration <$> genDataDeclaration
    , AST.SPragma <$> genPragma
    , AST.SMacroImport <$> genMacroImport
    , AST.SModuleDeclaration Nothing <$> genIdentifier
    , AST.SQualifiedImport <$> genQualifiedImport
    , AST.SRawStatement Nothing <$> genRawStatement
    , AST.SRestrictedImport <$> genRestrictedImport True
    , AST.STypeclassDefinition <$> genTypeclassDefinition
    , AST.STypeclassInstance <$> genTypeclassInstance
    , AST.STypeSignature <$> genTypeSignature
    , AST.STypeSynonym <$> genTypeSynonym
    ]
    [ AST.STopLevel <$> genTopLevel
    , AST.SFunctionDefinition <$> genFunctionDefinition Nothing
    , AST.SMacroDefinition <$> genMacroDefinition
    ]