BNFC-meta-0.1: Language/LBNF.hs
{-# LANGUAGE TemplateHaskell #-}
module Language.LBNF (
compile
, pp
, cf, q, qm, Q, errormsg
, ord, listArray, (!), Err(..), Array, HappyStk(..)
, Lift (..), Entrypoint(..), Aq(..)
, module Language.Haskell.Meta.Parse
, module Language.Haskell.TH.Quote
, dumpAlex, dumpHappy
) where
import Language.LBNF.CF
import Language.LBNF.CFtoAbstract
import Language.LBNF.CFtoAlex2
import Language.LBNF.CFtoHappy
import Language.LBNF.CFtoPrinter
import Language.LBNF.ErrM
import Language.LBNF.GetCF
import Language.LBNF.LiftBNF()
import Language.LBNF.PrintPrelude
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Lift
import Language.Haskell.Meta.Parse
import Text.Happy.Quote
import Text.Alex.Quote
import Data.Array
import Data.Char (ord, toLower)
cf :: QuasiQuoter
cf = QuasiQuoter cfe cfp where
cfe s = case getCF s of
(g,[]) -> lift g
(_,msgs) -> error $ unlines msgs
cfp = error "Pattern quoting of grammars is not supported"
qm :: (Entrypoint a, Lift b) => (a -> Q b) -> QuasiQuoter
qm f = QuasiQuoter qExpM (error "Pattern quotes are not supported yet...")
where
qExpM s = case parse s of
Bad e -> error e
Ok a -> f a >>= lift
q :: (Entrypoint a, Lift b) => (a -> b) -> QuasiQuoter
q f = QuasiQuoter qExp (error "Pattern quotes are not supported yet...")
where
qExp s = case parse s of
Bad e -> error e
Ok a -> lift $ f a
errormsg :: String -> Q a
errormsg s = error s
pp :: Print a => a -> String
pp = printTree
class Entrypoint a where
parse :: String -> Err a
class Aq a where
aq :: a -> ExpQ
compose f g = [|$f . $g|]
compile :: CF -> Q [Dec]
compile g = do
(d1,tokens) <- cf2Abstract g
d2 <- cf2Printer g
d3 <- deriveLiftMany' $ map TyConI tokens
dEp <- deriveEps g d1
dalx <- alexcode g
dhpy <- happycode g
return $ d1
++ d2
++ tokens
++ dEp
++ dalx
++ dhpy
++ d3
dumpHappy :: CF -> String
dumpHappy = cf2HappyS
dumpAlex :: CF -> String
dumpAlex = cf2alex2
happycode = compileHappy . parseHappy . cf2HappyS
alexcode = compileAlex . parseAlex . cf2alex2
subst _ _ [ ] = []
subst from to xs@(a:as) =
if isPrefixOf from xs
then to ++ drop (length from) xs
else a : subst from to as
where isPrefixOf as bs = and $ zipWith (==) as bs
deriveEps :: CF -> [Dec] -> Q [Dec]
deriveEps cf ds = do
d1 <- mapM deriveEp eps
d2 <- maybe (deriveLiftMany' $ map TyConI ds) (deriveAq cf) (aqSyntax cf)
d3 <- sequence $ concatMap (spliceQQ $ hasAq cf) eps
return $ d1 ++ d2 ++ d3
where
eps = filter isNormal $ allEntryPoints cf
spliceQQ :: Bool -> String -> [Q Dec]
spliceQQ aq bs = if aq then maybe ([]) go (unAq bs) else go bs where
go nam =
[funD (mkName (initLower nam)) [clause [] (normalB
[|q (id :: $(conT typeName) -> $(conT typeName)) |]) []]]
typeName = mkName bs
deriveEp s = instanceD (cxt []) (appT (conT ''Entrypoint) (conT $ mkName s))
[funD 'parse
[clause []
(normalB $ compose (varE $ mkName $ "p"++s) (varE $ mkName $ "tokens")) []
]]
deriveAq cf (_,i,a) = (fmap concat $ sequence $ map deriveAqLift $ cf2data cf) >>= addAq where
addAq ds = do
v <- newName "a"
let nAqToken = mkName "AqToken"
d <- instanceD
(cxt [])
(appT (conT ''Aq) $ conT nAqToken)
[funD 'aq [clause [conP nAqToken [varP v]] (normalB $ aqDec (varE v)) []]]
return $ d:ds
aqDec v =
[|either error return . parseExp . drop $(lie) . reverse . drop $(lae) . reverse $ $(v)|]
(lie, lae) = (lift $ length i,lift $ length a)
deriveAqLift (c,f_cs) = maybe reg aq (unAq c) where
reg = sequence [instanceD (cxt []) (conT ''Lift `appT` typ) [cases >>= funD 'lift ]]
aq rc = sequence [instanceD (cxt []) (conT ''Lift `appT` typ) [cases >>= funD 'lift ]]
typ = conT n
n = mkName c
cases = do
s <- newName "s"
let cons = map doCon f_cs
return $ cons
deriveAqSpecialLift s =
instanceD (cxt []) (conT ''Lift `appT` typ) [cases >>= funD 'lift ] where
typ = conT n
n = mkName (rename s)
aqn = mkName (renameAq s)
cases = do
v <- newName "l"
let aqe = [| return (either error id (parseExp $(varE v))) |]
aq = clause [conP aqn [varP v]] (normalB aqe) []
con = doConSpec s
return $ aq : [con]
doCon :: (String,[String]) -> Q Clause
doCon (fun,cats) = case unAqs fun of
Just x -> do
v <- newName "l"
let aqn = mkName fun
aqe = [|aq $(varE v)|]
clause [conP aqn [varP v]] (normalB aqe) []
Nothing -> case unAq fun of
Nothing -> hlp fun
Just x -> if x `elem` specialCatsP then doConSpec x else hlp x
where
hlp real = do
vs <- mapM newName (map (const "a") cats)
let c = mkName real
aqc = mkName fun
args = [ [| lift $(varE n) |] | n <- vs ]
e = foldl (\e1 e2 -> [| appE $e1 $e2 |]) [| conE c |] args
clause [conP aqc (map varP vs)] (normalB e) []
doConSpec :: String -> Q Clause
doConSpec s = do
v <- newName "a"
let
n = mkName (rename s)
e = case s of
"Integer" -> [| litE (IntegerL $(varE v)) |]
"Double" -> [| litE (RationalL (toRational $(varE v))) |]
"String" -> [| litE (StringL $(varE v)) |]
"Ident" -> [| $(varE $ mkName "lift") $(varE v) |]
"Char" -> [| litE (charL $(varE v)) |]
-- _ -> error ( "s )
clause [conP n [varP v]] (normalB e) []
initLower :: String -> String
initLower [] = error "initLower : Empty list"
initLower (c:cs) = toLower c : cs