hermit-0.2.0.0: src/Language/HERMIT/ParserCore.y
{
{-# LANGUAGE CPP #-}
module Language.HERMIT.ParserCore (parseCore) where
import Control.Monad.Reader
import Data.Char (isSpace, isDigit)
import GhcPlugins
import Language.HERMIT.Context
import Language.HERMIT.External
import Language.HERMIT.Monad
import Language.HERMIT.Primitive.Common
import Language.HERMIT.Syntax (isCoreInfixIdChar, isCoreIdFirstChar, isCoreIdChar)
import Language.KURE.MonadCatch (prefixFailMsg)
import Language.Haskell.TH as TH
}
%name parser
%tokentype { Token }
%error { parseError }
%monad { CoreParseM } { >>= } { 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 }
'\\' { Tlambda}
'@' { Tat }
'.' { Tdot }
'?' { Tquestion}
';' { Tsemicolon }
NAME { Tname $$ }
CNAME { Tcname $$ }
INTEGER { Tinteger $$ }
RATIONAL { Trational $$ }
STRING { Tstring $$ }
CHAR { Tchar $$ }
%%
-- | Top level expression term.
expr : app { $1 }
app : app arg { App $1 $2 }
| arg { $1 }
arg : '(' expr ')' { $2 }
| '(' ')' {% lookupName "()" Var }
| var { $1 }
| intlit { $1 }
| strlit { $1 }
intlit : INTEGER {% mkIntExpr' $1 } -- mkIntLit makes a primitive Int#
strlit : STRING {% lift $ mkStringExpr $1 }
var : NAME {% lookupName $1 varToCoreExpr }
{
mkIntExpr' :: Integer -> CoreParseM CoreExpr
#if __GLASGOW_HASKELL__ > 706
mkIntExpr' i = do
dflags <- lift getDynFlags
return $ mkIntExpr dflags i
#else
mkIntExpr' i = return $ mkIntExpr i
#endif
lookupName :: String -> (Id -> CoreExpr) -> CoreParseM CoreExpr
lookupName nm k = do
c <- ask
v <- lift $ prefixFailMsg (nm ++ " lookup: ") $ findId (TH.mkName nm) c
return (k v)
type CoreParseM a = ReaderT HermitC HermitM a
parseError :: Monad m => [Token] -> m a
parseError ts = fail $ "core parse error: " ++ show ts
data Token
= Tforall
| Trec
| Tlet
| Tin
| Tcase
| Tof
| Tcast
| Tnote
| Texternal
| Tlocal
| Twild --
| Toparen --
| Tcparen --
| Tobrace
| Tcbrace
| Thash
| Teq
| Tcolon --
| Tcoloncolon --
| Tcoloneqcolon
| Tstar
| Tarrow
| Tlambda --
| Tat
| Tdot
| Tquestion
| Tsemicolon
| Tname String
| Tcname String
| Tinteger Integer
| Trational Float
| Tstring String
| Tchar Char
deriving (Eq, Show)
lexer :: String -> Either String [Token]
lexer [] = Right []
lexer ('_' :cs) = fmap (Twild:) $ lexer cs
lexer ('(' :cs) = fmap (Toparen:) $ lexer cs
lexer (')' :cs) = fmap (Tcparen:) $ lexer cs
lexer (':':':':cs) = fmap (Tcoloncolon:) $ lexer cs
-- lexer (':' :cs) = fmap (Tcolon:) $ lexer cs
lexer ('\\':cs) = fmap (Tlambda:) $ lexer cs
lexer ('-':'>':cs) = fmap (Tarrow:) $ lexer cs
lexer ('\"':cs) = let (str,rest) = span (/='\"') cs
in case rest of
('\"':cs') -> fmap (Tstring str:) $ lexer cs'
_ -> Left "lexer: no matching quote"
lexer s@(c:cs) | isSpace c = lexer cs
| isDigit c = let (i,s') = span isDigit s
in fmap (Tinteger (read i):) $ lexer s'
| isCoreIdFirstChar c = let (i,s') = span isCoreIdChar s
in fmap (Tname i:) $ lexer s'
| isCoreInfixIdChar c = let (op,s') = span isCoreInfixIdChar s
in fmap (Tname op:) $ lexer s'
lexer s = Left $ "lexer: no match on " ++ s
---------------------------------------------
parseCore :: CoreString -> HermitC -> HermitM CoreExpr
parseCore (CoreString s) c =
case lexer s of
Left msg -> fail msg
Right tokens -> runReaderT (parser tokens) c
}