module FormalLanguage.CFG.QQ where
import Control.Applicative ((<$>),(<*>),empty)
import Control.Monad hiding (mapM)
import Control.Monad.Trans.State.Strict (evalStateT)
import Data.ByteString.Char8 (pack)
import Data.Default (def)
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Text.Trifecta.Delta (Delta (Directed))
import Text.Trifecta (parseString,Parser)
import Text.Trifecta.Result (Result (..), ErrInfo (..))
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Control.Lens
import Data.List (transpose,sort,group)
import Data.Traversable (mapM)
import Data.Foldable (concat)
import Prelude hiding (mapM,concat)
import FormalLanguage.CFG.Grammar
import FormalLanguage.CFG.Outside
import FormalLanguage.CFG.Parser
import FormalLanguage.CFG.PrettyPrint.ANSI
import FormalLanguage.CFG.TH
formalLangFile = quoteFile formalLanguage
formalLanguage = QuasiQuoter
{ quoteDec = parseFormalLanguage empty
, quoteExp = error "there is only a Dec quoter"
, quotePat = error "there is only a Dec quoter"
, quoteType = error "there is only a Dec quoter"
}
parseFormalLanguage :: GrammarParser Parser () -> String -> Q [Dec]
parseFormalLanguage ps s = do
loc <- location
let (lpos,cpos) = loc_start loc
let r = parseString ((evalStateT . runGrammarParser) (parseEverything ps) def) (Directed (pack "via QQ") (fromIntegral lpos) 0 0 0) $ trim s
case r of
(Failure (ErrInfo f _)) -> do
runIO . printDoc $ f
error "aborting parseFormalLanguage"
(Success g) -> do
let l = uniquePrefixLength g
concat <$> mapM (thCodeGen l) g
trim ('\n':xs) = trim xs
trim xs = xs
uniquePrefixLength :: Seq Grammar -> Int
uniquePrefixLength xs
| l == 0 = 0
| l == 1 = 0
| otherwise = go 1 . transpose $ xs^..folded.grammarName
where l = Seq.length xs
go :: Int -> [String] -> Int
go acc [] = error $ "for whatever reason, there are two grammars with the same name!" ++ show xs
go acc (xs:xss) = if (maximum . map length . group $ sort xs) > 1 then go (acc+1) xss else acc