rtk-0.12: test/golden/block/BlockQQ.hs
-- Generated by RTK from grammar 'Block'. Do not edit by hand.
{-# LANGUAGE TemplateHaskell #-}
module BlockQQ
where
import qualified Data.Char as C
import qualified Data.Map as M
import Data.List
import Data.Maybe
import qualified Data.Generics as Generics
import qualified Data.Data as Data
import qualified Language.Haskell.TH as TH
import Language.Haskell.TH.Quote
import BlockLexer
import BlockParser
qqShortcuts :: M.Map String String
-- A $name metavariable is rewritten to $Type:name using the qqShortcuts
-- table below. The rewrite is purely textual, so it would also fire inside
-- the quoted language's own string literals: write $$name there to escape
-- it and get the literal text $name. Each '$$' pair directly before a
-- metavariable stands for one literal '$' (so $$$x is a literal '$'
-- followed by the metavariable $x). A '$' not followed by an identifier is
-- never rewritten and needs no escape, and an explicit $Type:name antiquote
-- (the character after the name is ':') passes through untouched.
-- A plain character scan rather than a regex: metavariables are recognized
-- regardless of what follows the name - including a newline or the end of
-- the quote, which the previous regex's terminator class missed.
replaceAllPatterns :: String -> Either String String
replaceAllPatterns [] = Right []
replaceAllPatterns s@('$' : _) =
let (dollars, rest) = span (== '$') s
in case rest of
(c1 : _) | C.isAlpha c1 || c1 == '_' ->
let (varName, post) = span (\ ch -> C.isAlphaNum ch || ch == '_') rest
escCount = length dollars - 1
keptPre = replicate (div escCount 2) '$'
in case post of
(':' : _) -> ((dollars ++ varName) ++) <$> replaceAllPatterns post
_ | odd escCount -> ((keptPre ++ '$' : varName) ++) <$> replaceAllPatterns post
_ -> case catMaybes $ map (\ prefix -> M.lookup prefix qqShortcuts) $ reverse $ inits varName of
[] -> Left $ unlines
[ "Unknown metavariable $" ++ varName ++ " in quasi-quote:"
, "no prefix of '" ++ varName ++ "' is a known shortcut. Known shortcuts:"
, " " ++ intercalate ", " (M.keys qqShortcuts)
, "To include the literal text $" ++ varName ++ " in the quoted code"
, "(e.g. inside a string literal), escape it as $$" ++ varName ++ "." ]
(rule : _) -> ((keptPre ++ '$' : rule ++ ":" ++ varName) ++) <$> replaceAllPatterns post
_ -> (dollars ++) <$> replaceAllPatterns rest
replaceAllPatterns (c : rest) = (c :) <$> replaceAllPatterns rest
-- The generated lexer and parser encode error positions as "LINE:COL:message"
-- so structured-diagnostic callers can split them; render them back
-- human-readably for quasi-quote compile errors. Positions refer to the quote
-- body (padded with a start token in front).
rtkRenderError :: String -> String
rtkRenderError err =
case span (/= ':') err of
(l, ':' : rest1) | [(line, "")] <- (reads l :: [(Int, String)]) ->
case span (/= ':') rest1 of
(c, ':' : msg) | [(col, "")] <- (reads c :: [(Int, String)]) ->
"line " ++ show line ++ ", column " ++ show col ++ ": " ++ msg
_ -> err
_ -> err
qqShortcuts = M.fromList [ ("program","Program"),("block","Block"),("exp","Exp"),("function","Function"),("ident","Ident"),("paramList","ParamList"),("statement","Statement"),("statementList","StatementList")]
-- A quasi-quote pattern must match an AST parsed from anywhere in a source
-- file, while the pattern itself was parsed from the quote body - so every
-- RtkPos position field becomes a wildcard in generated patterns.
-- (Expressions need no special case: the compile-time position they embed
-- is equality-transparent.)
rtkPosWildPat :: RtkPos -> Maybe (TH.Q TH.Pat)
rtkPosWildPat _ = Just TH.wildP
quoteBlockExp :: Data.Data a => String -> (Program -> a) -> String -> TH.ExpQ
quoteBlockExp dummy func s = do
s1 <- either fail return (replaceAllPatterns s)
ast <- case scanTokens (dummy ++ " " ++ s1 ++ " " ++ dummy) >>= parseBlock of
Left err -> fail (rtkRenderError err)
Right a -> return a
let expr = func ast
dataToExpQ (const Nothing `Generics.extQ` antiProgramExp `Generics.extQ` antiFunctionExp `Generics.extQ` antiIdentExp `Generics.extQ` antiBlockExp `Generics.extQ` antiStatementExp `Generics.extQ` antiExpExp) expr
quoteBlockPat :: Data.Data a => String -> (Program -> a) -> String -> TH.PatQ
quoteBlockPat dummy func s = do
s1 <- either fail return (replaceAllPatterns s)
ast <- case scanTokens (dummy ++ " " ++ s1 ++ " " ++ dummy) >>= parseBlock of
Left err -> fail (rtkRenderError err)
Right a -> return a
let expr = func ast
dataToPatQ (const Nothing `Generics.extQ` rtkPosWildPat `Generics.extQ` antiProgramPat `Generics.extQ` antiFunctionPat `Generics.extQ` antiIdentPat `Generics.extQ` antiBlockPat `Generics.extQ` antiStatementPat `Generics.extQ` antiExpPat) expr
antiExpExp :: Exp -> Maybe (TH.Q TH.Exp )
antiExpExp ( Anti_Exp v) = Just $ TH.varE (TH.mkName v)
antiExpExp _ = Nothing
antiStatementExp :: [ Statement ] -> Maybe (TH.Q TH.Exp)
antiStatementExp ((Anti_Statement v):rest) =
let restExp = dataToExpQ (const Nothing `Generics.extQ` antiProgramExp `Generics.extQ` antiFunctionExp `Generics.extQ` antiIdentExp `Generics.extQ` antiBlockExp `Generics.extQ` antiStatementExp `Generics.extQ` antiExpExp) rest
lvar = TH.varE $ TH.mkName v
in Just [| $lvar ++ $restExp |]
antiStatementExp _ = Nothing
antiBlockExp :: Block -> Maybe (TH.Q TH.Exp )
antiBlockExp ( Anti_Block v) = Just $ TH.varE (TH.mkName v)
antiBlockExp _ = Nothing
antiIdentExp :: [ Ident ] -> Maybe (TH.Q TH.Exp)
antiIdentExp ((Anti_Ident v):rest) =
let restExp = dataToExpQ (const Nothing `Generics.extQ` antiProgramExp `Generics.extQ` antiFunctionExp `Generics.extQ` antiIdentExp `Generics.extQ` antiBlockExp `Generics.extQ` antiStatementExp `Generics.extQ` antiExpExp) rest
lvar = TH.varE $ TH.mkName v
in Just [| $lvar ++ $restExp |]
antiIdentExp _ = Nothing
antiFunctionExp :: Function -> Maybe (TH.Q TH.Exp )
antiFunctionExp ( Anti_Function v) = Just $ TH.varE (TH.mkName v)
antiFunctionExp _ = Nothing
antiProgramExp :: Program -> Maybe (TH.Q TH.Exp )
antiProgramExp ( Anti_Program v) = Just $ TH.varE (TH.mkName v)
antiProgramExp _ = Nothing
antiExpPat :: Exp -> Maybe (TH.Q TH.Pat )
antiExpPat ( Anti_Exp v) = Just $ TH.varP (TH.mkName v)
antiExpPat _ = Nothing
antiStatementPat :: [ Statement ] -> Maybe (TH.Q TH.Pat)
antiStatementPat [Anti_Statement v] = Just $ TH.varP (TH.mkName v)
antiStatementPat _ = Nothing
antiBlockPat :: Block -> Maybe (TH.Q TH.Pat )
antiBlockPat ( Anti_Block v) = Just $ TH.varP (TH.mkName v)
antiBlockPat _ = Nothing
antiIdentPat :: [ Ident ] -> Maybe (TH.Q TH.Pat)
antiIdentPat [Anti_Ident v] = Just $ TH.varP (TH.mkName v)
antiIdentPat _ = Nothing
antiFunctionPat :: Function -> Maybe (TH.Q TH.Pat )
antiFunctionPat ( Anti_Function v) = Just $ TH.varP (TH.mkName v)
antiFunctionPat _ = Nothing
antiProgramPat :: Program -> Maybe (TH.Q TH.Pat )
antiProgramPat ( Anti_Program v) = Just $ TH.varP (TH.mkName v)
antiProgramPat _ = Nothing
-- This grammar's quasi-quoters work in expression and pattern contexts only
quoteBlockType _ = fail "this quasi-quoter cannot be used in a type context"
quoteBlockDecs _ = fail "this quasi-quoter cannot be used in a declaration context"
getProgram ( Ctr__Program__0 _ s) = s
program :: QuasiQuoter
program = QuasiQuoter (quoteBlockExp "tok_Program_dummy_9" getProgram ) (quoteBlockPat "tok_Program_dummy_9" getProgram ) quoteBlockType quoteBlockDecs
getBlock ( Ctr__Program__1 _ s) = s
block :: QuasiQuoter
block = QuasiQuoter (quoteBlockExp "tok_Block_dummy_8" getBlock ) (quoteBlockPat "tok_Block_dummy_8" getBlock ) quoteBlockType quoteBlockDecs
getExp ( Ctr__Program__2 _ s) = s
exp :: QuasiQuoter
exp = QuasiQuoter (quoteBlockExp "tok_Exp_dummy_7" getExp ) (quoteBlockPat "tok_Exp_dummy_7" getExp ) quoteBlockType quoteBlockDecs
getFunction ( Ctr__Program__3 _ s) = s
function :: QuasiQuoter
function = QuasiQuoter (quoteBlockExp "tok_Function_dummy_6" getFunction ) (quoteBlockPat "tok_Function_dummy_6" getFunction ) quoteBlockType quoteBlockDecs
getIdent ( Ctr__Program__4 _ s) = s
ident :: QuasiQuoter
ident = QuasiQuoter (quoteBlockExp "tok_Ident_dummy_5" getIdent ) (quoteBlockPat "tok_Ident_dummy_5" getIdent ) quoteBlockType quoteBlockDecs
getParamList ( Ctr__Program__5 _ s) = s
paramList :: QuasiQuoter
paramList = QuasiQuoter (quoteBlockExp "tok_ParamList_dummy_4" getParamList ) (quoteBlockPat "tok_ParamList_dummy_4" getParamList ) quoteBlockType quoteBlockDecs
getStatement ( Ctr__Program__6 _ s) = s
statement :: QuasiQuoter
statement = QuasiQuoter (quoteBlockExp "tok_Statement_dummy_3" getStatement ) (quoteBlockPat "tok_Statement_dummy_3" getStatement ) quoteBlockType quoteBlockDecs
getStatementList ( Ctr__Program__7 _ s) = s
statementList :: QuasiQuoter
statementList = QuasiQuoter (quoteBlockExp "tok_StatementList_dummy_2" getStatementList ) (quoteBlockPat "tok_StatementList_dummy_2" getStatementList ) quoteBlockType quoteBlockDecs