ifx :: String -> ExpQ -> ExpQ -> ExpQ
ifx op a b = infixE (Just a) (varE $ mkName op) (Just b)
-getNameTyVarBndr :: TyVarBndr -> Name
-getNameTyVarBndr (PlainTV name) = name
-getNameTyVarBndr (KindedTV name _) = name
-
fun :: Name -> [PatQ] -> ExpQ -> DecQ
fun name args body = funD name [clause args (normalB body) []]
-genDSL :: Name -> DecsQ
-genDSL typename = reify typename >>= \info->case info of
- TyConI (DataD _ _ tyvars _ constructors _)
- -> mapM getConsName constructors >>= mkDSL typename tyvars
- t
- -> fail $ "mkConsClass only supports simple datatypes and not: " ++ show t
+class GenDSL a where genDSL :: a -> DecsQ
+instance GenDSL a => GenDSL [a] where genDSL = fmap concat . mapM genDSL
+instance GenDSL Name where
+ genDSL typename = reify typename >>= \info->case info of
+ TyConI (DataD _ _ tyvars _ constructors _)
+ -> mapM getConsName constructors >>= mkDSL typename tyvars
+ t
+ -> fail $ "mkConsClass only supports simple datatypes and not: " ++ show t
mkDSL :: Name -> [TyVarBndr] -> [(Name, [(Name, TypeQ)])] -> DecsQ
mkDSL typeName typeVars constructors = sequence [ mkClass, mkPrinter, mkCompiler, mkInterpreter ]
mkPredicate n = sigD (predicateName n) [t|$resultT -> $v Bool|]
resultT :: TypeQ
- resultT = appT v $ foldl appT (conT typeName) $ map (varT . getNameTyVarBndr) $ typeVars
+ resultT = appT v $ foldl appT (conT typeName) $ map (varT . getName) $ typeVars
+ where getName (PlainTV name) = name
+ getName (KindedTV name _) = name
mkPrinter :: DecQ
mkPrinter = instanceD (pure []) [t|$(conT $ className typeName) Printer|]
mkSelector consName ftotal fnum n = do
fresh <- newName "f"
fun (selectorName n) [varP fresh] $
- ifx ">>=" (varE fresh) $ lamCaseE (mkMatch:wilds)
+ [|$(varE fresh) >>= $(lamCaseE $ mkMatch:wilds)|]
where
mkMatch = do
fresh <- newName "e"
import Language.GenDSL as L
dsl :: QuasiQuoter
-dsl = QuasiQuoter
- { quoteExp = \s->location >>= parseExpr s
- , quotePat = undefined
- , quoteType = undefined
- , quoteDec = undefined
- }
+dsl = QuasiQuoter { quoteExp = parseDSL expr }
where
- parseExpr :: String -> Loc -> ExpQ
- parseExpr s loc = either (fail . show) id $ runParser p () file s
- where
- file = loc_filename loc
- (line, col) = loc_start loc
- p = getPosition >>= setPosition . mPos >> whiteSpace *> expr <* eof
- mPos p = setSourceName (setSourceLine (setSourceColumn p col) line) file
+ parseDSL :: Parser (Q e) -> String -> Q e
+ parseDSL ps s = do
+ loc <- location
+ let file = loc_filename loc
+ (line, col) = loc_start loc
+ p = getPosition >>= setPosition . mPos >> whiteSpace *> ps <* eof
+ mPos p = setSourceName (setSourceLine (setSourceColumn p col) line) file
+ either (fail . show) id $ runParser p () file s
-- Lexer
identifier,operator :: Parser String
, MonadState PS
, MonadReader PR
)
-data PS = PS {fresh :: [Int]}
+newtype PS = PS {fresh :: [Int]}
data PR = PR {context :: Ctx, indent :: Int}
data Ctx = CtxNo | CtxNullary | CtxNonfix | CtxInfix {assoc :: CtxAssoc, prio :: Int, branch :: CtxAssoc}
deriving Eq
instance DSL Printer
instance Expression Printer where
lit = printLit . show
- (+.) = printBinOp (leftctx 6) "+"
- (-.) = printBinOp (leftctx 6) "-"
- (*.) = printBinOp (leftctx 7) "*"
- (/.) = printBinOp (leftctx 7) "/"
- neg = printUnOp (nonectx 7) "!"
- (&.) = printBinOp (rightctx 3) "&"
- (|.) = printBinOp (rightctx 2) "|"
- not = printUnOp (nonectx 7) "!"
- (==.) = printBinOp (nonectx 4) "=="
- (/=.) = printBinOp (nonectx 4) "/="
- (<.) = printBinOp (nonectx 4) "<"
- (>.) = printBinOp (nonectx 4) ">"
- (<=.) = printBinOp (nonectx 4) "<"
- (>=.) = printBinOp (nonectx 4) ">"
+ (+.) = printBinOp "+" (leftctx 6)
+ (-.) = printBinOp "-" (leftctx 6)
+ (*.) = printBinOp "*" (leftctx 7)
+ (/.) = printBinOp "/" (leftctx 7)
+ neg = printUnOp "!" (nonectx 7)
+ (&.) = printBinOp "&" (rightctx 3)
+ (|.) = printBinOp "|" (rightctx 2)
+ not = printUnOp "!" (nonectx 7)
+ (==.) = printBinOp "==" (nonectx 4)
+ (/=.) = printBinOp "/=" (nonectx 4)
+ (<.) = printBinOp "<" (nonectx 4)
+ (>.) = printBinOp ">" (nonectx 4)
+ (<=.) = printBinOp "<" (nonectx 4)
+ (>=.) = printBinOp ">" (nonectx 4)
if' p t e = paren' CtxNonfix
$ printLit "if" >-> p
>^> printLit "then" >^> iindent (localctx CtxNonfix t)
printIndent = asks (flip replicate '\t' . indent) >>= printLit
infixl 1 >>>, >->, >^>
-printBinOp :: Ctx -> String -> Printer a1 -> Printer a2 -> Printer a3
-printBinOp thisctx op l r = paren' thisctx $
+printBinOp :: String -> Ctx -> Printer a1 -> Printer a2 -> Printer a3
+printBinOp op thisctx l r = paren' thisctx $
localctx (setBranch thisctx CtxLeft) l
>-> printLit op
>-> localctx (setBranch thisctx CtxRight) r
-printUnOp :: Ctx -> String -> Printer a -> Printer a
-printUnOp thisctx op l = paren' thisctx $
+printUnOp :: String -> Ctx -> Printer a -> Printer a
+printUnOp op thisctx l = paren' thisctx $
printLit (' ':op)
>-> localctx (setBranch thisctx CtxRight) l
printCons cons l = paren' CtxNonfix $ printLit cons >-> l
printRec :: String -> Printer a -> Printer a
-printRec op l = printUnOp CtxNo op $ accol l
+printRec op l = printUnOp op CtxNo $ accol l