packages feed

atomo-0.4: src/Atomo/QuasiQuotes.hs

{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS -fno-warn-name-shadowing #-}
module Atomo.QuasiQuotes
    ( p
    , e
    , es
    ) where

import Control.Monad.State hiding (lift)
import Data.Maybe (fromJust)
import Data.Typeable
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import System.IO.Unsafe
import Text.Parsec
import qualified Language.Haskell.TH as TH

import Atomo.Core
import Atomo.Helpers (fromHaskell')
import Atomo.Lexer
import Atomo.Parser
import Atomo.Parser.Base (Parser, blockOf, end)
import Atomo.Parser.Expr
import Atomo.Pattern (toDefinePattern)
import Atomo.Types


qqEnv :: Env
qqEnv = snd $ unsafePerformIO $
    runVM (initCore >> return (particle "ok")) startEnv

-- | Pattern quasi-quoter.
p :: QuasiQuoter
p = QuasiQuoter quotePatternExp undefined

-- | Single expression quasi-quoter.
e :: QuasiQuoter
e = QuasiQuoter quoteExprExp undefined

-- | Quasi-quoter for multiple expressions (a block of code).
es :: QuasiQuoter
es = QuasiQuoter quoteExprsExp undefined

withLocation :: (String -> (String, Int, Int) -> a) -> (a -> Q Exp) -> String -> TH.ExpQ
withLocation p c s = do
    l <- TH.location
    c $ p s
        ( TH.loc_filename l
        , fst $ TH.loc_start l
        , snd $ TH.loc_start l
        )

parsing :: Typeable a => Parser a -> String -> (String, Int, Int) -> a
parsing p s (file, line, col) =
    -- here be dragons
    fromHaskell' $ unsafePerformIO (runWith go (qqEnv))
  where
    go = liftM haskell $ continue lexer pp "<qq>" s

    pp = do
        pos <- getPosition
        setPosition $
            flip setSourceName file $
            flip setSourceLine line $
            setSourceColumn pos col
        r <- p
        end <|> eof
        return r

quotePatternExp :: String -> TH.ExpQ
quotePatternExp = withLocation (parsing (liftM (fromJust . toDefinePattern) pExpr)) lift

quoteExprExp :: String -> TH.ExpQ
quoteExprExp = withLocation (parsing pExpr) lift

quoteExprsExp :: String -> TH.ExpQ
quoteExprsExp = withLocation (parsing (blockOf pExpr)) (fmap ListE . mapM lift)