blob: 2d04f96a436ae19a84c2385983ea2e1ba39921d5 [file] [edit]
--
-- Copyright 2016, NICTA
--
-- This software may be distributed and modified according to the terms of
-- the GNU General Public License version 2. Note that NO WARRANTY is provided.
-- See "LICENSE_GPLv2.txt" for details.
--
-- @TAG(NICTA_GPL)
--
module Isabelle.ExprTH where
import Data.Generics.Aliases
import Data.Data
import qualified Language.Haskell.ParseExp as M (parseExp)
import qualified Language.Haskell.TH as TH
import Language.Haskell.TH.Quote
import qualified Text.Parsec.Prim as P
import qualified Text.Parsec.Char as P
import Isabelle.InnerAST
import Isabelle.OuterAST
import Isabelle.Parser
-- import Debug.Trace
isaTheory :: QuasiQuoter
isaTheory = qq topLevelL
isaDecl :: QuasiQuoter
isaDecl = qq theoryDeclL
isaTerm :: QuasiQuoter
isaTerm = qq termL
isaType :: QuasiQuoter
isaType = qq typeL
isaMethods :: QuasiQuoter
isaMethods = qq (P.many methodL)
qq :: Data x => ParserM x -> QuasiQuoter
qq prs = QuasiQuoter { quoteExp = parseExp prs
, quotePat = parsePat prs
, quoteType = error "quoteType undefined"
, quoteDec = error "quoteDec undefined" }
#if MIN_VERSION_base(4,13,0)
parse :: MonadFail m => ParserM x -> String -> m x
#else
parse :: Monad m => ParserM x -> String -> m x
#endif
parse prs s = do
let res = P.runP (P.many (P.space) >> prs) () "<isabelle>" s
case res of
Left err -> fail $ show err
Right e -> return e
parseExp :: (Data x) => (ParserM x) -> String -> TH.ExpQ
parseExp prs s = parse prs s >>= dataToExpQ (const Nothing `extQ` typeAntiE `extQ` termAntiE `extQ` nameAntiE)
termAntiE :: Term -> Maybe (TH.Q TH.Exp)
termAntiE (AntiTerm x) = case M.parseExp x of Right e -> return $ return e; Left s -> Nothing
termAntiE _ = Nothing
typeAntiE :: Type -> Maybe (TH.Q TH.Exp)
typeAntiE (AntiType x) = case M.parseExp x of Right e -> return $ return e; Left s -> Nothing
typeAntiE _ = Nothing
nameAntiE :: String -> Maybe (TH.Q TH.Exp)
nameAntiE ('$':xs) = Just $ TH.varE (TH.mkName xs)
nameAntiE _ = Nothing
parsePat :: (Data x) => (ParserM x) -> String -> TH.PatQ
parsePat prs s = parse prs s >>= dataToPatQ (const Nothing `extQ` typeAntiP `extQ` termAntiP `extQ` nameAntiP)
termAntiP :: Term -> Maybe (TH.Q TH.Pat)
termAntiP (AntiTerm x) = Just $ TH.varP (TH.mkName x)
termAntiP _ = Nothing
typeAntiP :: Type -> Maybe (TH.Q TH.Pat )
typeAntiP (AntiType x) = Just $ TH.varP (TH.mkName x)
typeAntiP _ = Nothing
nameAntiP :: String -> Maybe (TH.Q TH.Pat)
nameAntiP ('$':xs) = Just $ TH.varP (TH.mkName xs)
nameAntiP _ = Nothing