packages feed

language-dickinson-0.1.1.2: src/Language/Dickinson/Check/Internal.hs

module Language.Dickinson.Check.Internal ( sanityCheck
                                         , sanityCheckLexer
                                         , maxUniqueDeclaration
                                         ) where

import           Control.Monad             (when)
import           Control.Monad.State       (MonadState)
import           Data.List.NonEmpty        ((<|))
import           Language.Dickinson.Lexer
import           Language.Dickinson.Name
import           Language.Dickinson.Rename
import           Language.Dickinson.Type
import           Language.Dickinson.Unique
import           Lens.Micro                (_1)
import           Lens.Micro.Mtl            (use)

sanityCheckLexer :: (HasLexerState s, MonadState s m) => [Declaration a] -> m ()
sanityCheckLexer d = do
    storedMax <- use (lexerStateLens._1)
    let computedMax = maximum (maxUniqueDeclaration <$> d)
    when (storedMax < computedMax) $
        error "Sanity check failed!"

-- | Sanity check for the renamer.
sanityCheck :: (HasRenames s, MonadState s m) => [Declaration a] -> m ()
sanityCheck d = do
    storedMax <- use (rename.maxLens)
    let computedMax = maximum (maxUniqueDeclaration <$> d)
    when (storedMax < computedMax) $
        error "Sanity check failed!"

-- TODO: see http://hackage.haskell.org/package/uniplate-1.6.12/docs/Data-Generics-Uniplate-Operations.html
-- TODO: recursion schemes? would need benchmark...
maxUniqueDeclaration :: Declaration a -> Int
maxUniqueDeclaration (Define _ (Name _ (Unique i) _) e)   = max i (maxUniqueExpression e)
maxUniqueDeclaration (TyDecl _ (Name _ (Unique i) _) tns) =
    maximum ( i <| fmap (unUnique . unique) tns)

maxUniqueType :: DickinsonTy a -> Int
maxUniqueType TyText{}                          = 0
maxUniqueType (TyFun _ ty ty')                  = max (maxUniqueType ty) (maxUniqueType ty')
maxUniqueType (TyTuple _ ts)                    = maximum (fmap maxUniqueType ts)
maxUniqueType (TyNamed _ (Name _ (Unique k) _)) = k

maxUniqueExpression :: Expression a -> Int
maxUniqueExpression Literal{}                             = 0
maxUniqueExpression (Constructor _ (Name _ (Unique k) _)) = k
maxUniqueExpression StrChunk{}                            = 0
maxUniqueExpression (Var _ (Name _ (Unique i) _))         = i
maxUniqueExpression (Choice _ pes)                        = maximum (maxUniqueExpression . snd <$> pes)
maxUniqueExpression (MultiInterp _ es)                    = maximum (fmap maxUniqueExpression es)
maxUniqueExpression (Interp _ es)                         = maximum (fmap maxUniqueExpression es)
maxUniqueExpression (Concat _ es)                         = maximum (fmap maxUniqueExpression es)
maxUniqueExpression (Apply _ e e')                        = max (maxUniqueExpression e) (maxUniqueExpression e')
maxUniqueExpression (Annot _ e ty)                        = max (maxUniqueExpression e) (maxUniqueType ty)
maxUniqueExpression (Flatten _ e)                         = maxUniqueExpression e
maxUniqueExpression (Tuple _ es)                          = maximum (fmap maxUniqueExpression es)
maxUniqueExpression (Lambda _ (Name _ (Unique i) _) ty e) =
    maximum [ i
            , maxUniqueExpression e
            , maxUniqueType ty
            ]
maxUniqueExpression (Match _ e p e')                      =
    maximum
        [ maxUniqueExpression e
        , maxUniquePattern p
        , maxUniqueExpression e'
        ]
maxUniqueExpression (Let _ bs e) =
    maximum
        [ maxUniqueExpression e
        , maximum (maxUniqueExpression . snd <$> bs)
        , maximum (unUnique . unique . fst <$> bs)
        ]

maxUniquePattern :: Pattern a -> Int
maxUniquePattern (PatternVar _ (Name _ (Unique i) _))  = i
maxUniquePattern Wildcard{}                            = 0
maxUniquePattern (PatternTuple _ ps)                   = maximum (fmap maxUniquePattern ps)
maxUniquePattern (PatternCons _ (Name _ (Unique k) _)) = k