packages feed

hermit-0.6.0.0: src/HERMIT/ParserType.y

{
{-# LANGUAGE CPP #-}
module HERMIT.ParserType
    ( parseType
    , parseTypeT
    , parseTypeWithHoles
    , parseTypeWithHolesT
    ) where

import Control.Arrow
import Control.Monad.State
import Data.Char (isSpace, isDigit)

import HERMIT.Context
import HERMIT.Core
import HERMIT.External
import HERMIT.GHC
import HERMIT.Kure
import HERMIT.Monad
import HERMIT.Name
import HERMIT.ParserCore
import HERMIT.Syntax (isCoreInfixIdChar, isCoreIdFirstChar, isCoreIdChar)

import Language.KURE.MonadCatch (prefixFailMsg)
}

%name parser
%tokentype { Token }
%error { parseError }
%monad { TypeParseM } { >>= } { return }

%token
    'forall'   { Tforall }
    '%rec'     { Trec }
    '%let'     { Tlet }
    '%in'      { Tin }
    '%case'    { Tcase }
    '%of'      { Tof }
    '%cast'    { Tcast }
    '%note'    { Tnote }
    '%external' { Texternal }
    '%local'   { Tlocal }
    '%_'       { Twild }
    '('        { Toparen }
    ')'        { Tcparen }
    '{'        { Tobrace }
    '}'        { Tcbrace }
    '#'        { Thash}
    '='        { Teq }
    ':'        { Tcolon }
    '::'       { Tcoloncolon }
    ':=:'      { Tcoloneqcolon }
    '*'        { Tstar }
    '->'       { Tarrow }
    '=>'       { Tdoublearrow }
    '\\'       { Tlambda}
    '@'        { Tat }
    '.'        { Tdot }
    '?'        { Tquestion}
    ';'        { Tsemicolon }
    NAME       { Tname $$ }
    CNAME      { Tcname $$ }
    INTEGER    { Tinteger $$ }
    RATIONAL   { Trational $$ }
    STRING     { Tstring $$ }
    CHAR       { Tchar $$ }

%%

-- | Top level type term.
type : tytheta '=>' tyapp  { mkPhiTy $1 $3 } -- { uncurry mkSigmaTy $1 $3 }
     | tyapp               { $1 }

tytheta : tyapp            { [$1] } -- {% liftM (\(tvs,ty) -> (tvs,[ty])) $ catchFrees $1 }

tyapp : tyapp tyarg        { mkAppTy $1 $2 }
      | tyarg                { $1 }

tyarg : '(' tyapp ')'      { $2 }
    | '(' ')'              {% lookupName "()" }
    | tyvar                { $1 }

tyvar : NAME               {% lookupName $1 }
{

lookupName :: String -> TypeParseM Type
lookupName nm = do
    c <- getContext
    et <- lift $ attemptM $ findType (parseName nm) c
    either (const (addTyVar nm)) return et

catchFrees :: Type -> TypeParseM ([TyVar], Type)
catchFrees ty = do
    used <- gets tpUsed
    let frees = varSetElems $ freeVarsType ty
        quants = filter (`elem` used) frees
    modify $ \ st -> st { tpUsed = filter (`notElem` frees) (tpUsed st) }
    return (quants, ty)

data TPState = TPState { tpContext :: HermitC
                       , tpUsed :: [TyVar]
                       }

type TypeParseM a = StateT TPState HermitM a

getContext :: TypeParseM HermitC
getContext = gets tpContext

addTyVar :: String -> TypeParseM Type
addTyVar tvStr = do
    used <- gets tpUsed
    case [ tv | tv <- used, unqualifiedName tv == tvStr ] of
        [] -> do tv <- lift $ newTyVarH tvStr liftedTypeKind
                 modify $ \ st -> st { tpUsed = tv : tpUsed st }
                 return $ mkTyVarTy tv
        [tv] -> return $ mkTyVarTy tv
        other -> fail "addTyVar: impossible case"

---------------------------------------------

-- | Parse a CoreString into a Type, where all type variables must be bound.
parseType :: CoreString -> HermitC -> HermitM Type
parseType cs c = do
    (ty, holes) <- parseTypeWithHoles cs c
    guardMsg (null holes) "type contains unbound type variables."
    return ty

-- | Parse a CoreString into a Type, any unbound variables are returned.
parseTypeWithHoles :: CoreString -> HermitC -> HermitM (Type, [TyVar])
parseTypeWithHoles (CoreString s) c =
    case lexer s of
        Left msg -> fail msg
        Right tokens -> do
            (ty,st) <- runStateT (parser tokens) (TPState c [])
            return (ty,tpUsed st)

---------------------------------------------

-- | Parse a 'CoreString' to a 'Type', using the current context.
parseTypeT :: CoreString -> TransformH a Type
parseTypeT = contextonlyT . parseType

-- | Parse a 'CoreString' to a 'Type', using the current context, returning unbound type variables.
parseTypeWithHolesT :: CoreString -> TransformH a (Type, [TyVar])
parseTypeWithHolesT = contextonlyT . parseTypeWithHoles

---------------------------------------------

}