packages feed

alms-0.6.6: src/Meta/Quasi.hs

module Meta.Quasi (
  pa, ty, ex, dc,
  prQ, tdQ, atQ, caQ, bnQ, fdQ, meQ, qeQ, tpQ, seQ, sgQ,
) where

import Meta.QuoteData
import Meta.THHelpers
import Syntax.Parser
import AST
import Util

import Data.Generics
import qualified Language.Haskell.TH as TH
import Language.Haskell.TH.Quote (QuasiQuoter(..))

toAstQ :: (Data a, ToSyntax b) => a -> TH.Q b
toAstQ x = whichS' (toExpQ False x) (toPatQ False x)

toAstQ' :: (Data a, ToSyntax b) => a -> TH.Q b
toAstQ' x = whichS' (toExpQ True x) (toPatQ True x)

toExpQ :: Data a => Bool -> a -> TH.ExpQ
toExpQ False x = dataToExpQ antiExp moduleQuals x
toExpQ True  x = do
  TH.AppE _ stx <- dataToExpQ antiExp moduleQuals x
  return stx

toPatQ :: Data a => Bool -> a -> TH.PatQ
toPatQ False x = dataToPatQ antiPat moduleQuals x
toPatQ True  x = do
  TH.ConP _ [_, stx] <- dataToPatQ antiPat moduleQuals x
  return stx

moduleQuals :: [(String, String)]
moduleQuals  = [ ("AST.Type",        "AST"),
                 ("AST.Kind",        "AST"),
                 ("AST.Patt",        "AST"),
                 ("AST.Ident",       "AST"),
                 ("AST.Expr",        "AST"),
                 ("AST.Decl",        "AST"),
                 ("AST.Notable",     "AST") ]

antiExp :: Data a => a -> Maybe TH.ExpQ
antiExp  = antiGen

antiPat :: Data a => a -> Maybe TH.PatQ
antiPat  = antiGen
           `extQ`  antiLocPat
           `extQ`  antiUnitPat
           `extQ`  antiRawPat

antiGen :: forall a b. (Data a, ToSyntax b) => a -> Maybe (TH.Q b)
antiGen  = $(expandAntibles [''Raw, ''Renamed] 'toAstQ syntaxTable)
         $ const Nothing

antiLocPat :: Loc -> Maybe TH.PatQ
antiLocPat _ = Just TH.wildP

antiUnitPat :: () -> Maybe TH.PatQ
antiUnitPat _ = Just TH.wildP

antiRawPat :: Raw -> Maybe TH.PatQ
antiRawPat _ = Just TH.wildP

---
--- Syntax helpers
---

mkvarE :: String -> TH.ExpQ
mkvarE  = TH.varE . TH.mkName

mkvarP :: String -> TH.PatQ
mkvarP "_" = TH.wildP
mkvarP n   = TH.varP (TH.mkName n)

---
--- Quasiquoters
---

pa, ty, ex, dc, meQ, prQ, tdQ, atQ, caQ, bnQ, fdQ, qeQ, tpQ, seQ, sgQ
  :: QuasiQuoter

ex  = mkQuasi "ex" parseExpr
dc  = mkQuasi "dc" parseDecl
ty  = mkQuasi "ty" (withDots True parseType)
pa  = mkQuasi "pa" parsePatt
meQ = mkQuasi "meQ" parseModExp
prQ = mkQuasi "prQ" parseProg
tdQ = mkQuasi "tdQ" parseTyDec
atQ = mkQuasi "atQ" parseAbsTy
caQ = mkQuasi "caQ" parseCaseAlt
bnQ = mkQuasi "bnQ" parseBinding
fdQ = mkQuasi "fdQ" parseField
qeQ = mkQuasi "qeQ" parseQExp
tpQ = mkQuasi "tpQ" parseTyPat
seQ = mkQuasi "seQ" parseSigExp
sgQ = mkQuasi "sgQ" parseSigItem

mkQuasi :: forall stx note.
           (Typeable1 note, Typeable1 stx,
            Data (note Raw), Data (stx Raw),
            LocAst (N (note Raw) (stx Raw)),
            Data (note Renamed), Data (stx Renamed),
            LocAst (N (note Renamed) (stx Renamed))) =>
           String ->
           (forall i. Tag i => P (N (note i) (stx i))) ->
           QuasiQuoter
mkQuasi name parser = (newQuasi name) { quoteExp = qast, quotePat = qast }
  where
  qast s =
    join $
      parseQuasi s $ \filename iflag lflag ->
        case iflag of
          "+'" -> do
            stx <- parser :: P (N (note Renamed) (stx Renamed))
            convert' filename stx

{-
src/Meta/Quasi.hs:115:13:
    Could not deduce (Typeable1 stx) arising from a use of convert'
    from the context (Data (note Raw),
                      Data (stx Raw),
                      LocAst (N (note Raw) (stx Raw)),
                      Data (note Renamed),
                      Data (stx Renamed),
                      LocAst (N (note Renamed) (stx Renamed)))
      bound by the type signature for
                 mkQuasi :: (Data (note Raw), Data (stx Raw),
                             LocAst (N (note Raw) (stx Raw)), Data (note Renamed),
                             Data (stx Renamed), LocAst (N (note Renamed) (stx Renamed))) =>
                            String
                            -> (forall i. Tag i => P (N (note i) (stx i))) -> QuasiQuoter
      at src/Meta/Quasi.hs:(99,12)-(106,22)
    or from (ToSyntax a)
      bound by the inferred type of
               qast :: ToSyntax a => String -> TH.Q a
      at src/Meta/Quasi.hs:(109,3)-(124,38)
    Possible fix:
      add (Typeable1 stx) to the context of
        the inferred type of qast :: ToSyntax a => String -> TH.Q a
        or the type signature for
             mkQuasi :: (Data (note Raw), Data (stx Raw),
                         LocAst (N (note Raw) (stx Raw)), Data (note Renamed),
                         Data (stx Renamed), LocAst (N (note Renamed) (stx Renamed))) =>
                        String
                        -> (forall i. Tag i => P (N (note i) (stx i))) -> QuasiQuoter
    In a stmt of a 'do' block: convert' filename stx
    In the expression:
      do { stx <- parser :: P (N (note Renamed) (stx Renamed));
           convert' filename stx }
    In a case alternative:
        "+'"
          -> do { stx <- parser :: P (N (note Renamed) (stx Renamed));
                  convert' filename stx }
-}

          "+" -> do
            stx <- parser :: P (N (note Renamed) (stx Renamed))
            convert filename lflag stx
          "'" -> do
            stx <- parser :: P (N (note Raw) (stx Raw))
            convert' filename stx
          _        -> do
            stx <- parser :: P (N (note Raw) (stx Raw))
            convert filename lflag stx
  convert filename flag stx =
    return . maybe toAstQ toLocAstQ flag $
               scrubWhen (\loc -> file loc == filename) stx
  convert' filename stx = do
    return . toAstQ' $ scrubWhen (\loc -> file loc == filename) stx

deriveLocAsts 'toAstQ syntaxTable