import Data.Char
import Control.Monad
+import Printer
+import Compiler
+import Interpreter
+
className,constructorName,selectorName,predicateName :: Name -> Name
className = mkName . (++"'") . stringName
constructorName = mkName . map toLower . stringName
stringName :: Name -> String
stringName (Name occ _) = occString occ
-numberedArgs :: [a] -> Q [Name]
-numberedArgs = zipWithM (\i _->newName $ "f" ++ show i) [0 :: Int ..]
-
adtFieldName :: Name -> Integer -> Name
adtFieldName consName idx = mkName $ map toLower (stringName consName) ++ "f" ++ show idx
-data Field = Field { fcons :: Name, ftotal :: Integer, fnum :: Integer, fname :: Name, ftype :: Type }
-
-toNameType :: Con -> [Field]
-toNameType (NormalC consName fs) = [Field {fcons=consName, ftotal=toInteger $ length fs, fnum=i, fname=adtFieldName consName i, ftype=t} | (_, t) <- fs | i <- [0..]]
-toNameType (RecC consName fs) = [Field consName (toInteger $ length fs) i n t | (n, _, t)<-fs | i <- [0..]]
-toNameType c = fail $ "Unsupported constructor type: " ++ show c
-
-getConsName :: Con -> Q Name
-getConsName (NormalC consName _)
+getConsName :: Con -> Q (Name, [(Name, TypeQ)])
+getConsName (NormalC consName fs)
| head (stringName consName) == ':' = fail "Infix constructors are not supported"
- | otherwise = pure consName
-getConsName (RecC consName _) = pure consName
+ | otherwise = pure (consName, [(adtFieldName consName i, pure t)|(_, t)<-fs | i<-[0..]])
+getConsName (RecC consName fs) = pure (consName, [(n, pure t) | (n, _, t)<-fs])
getConsName c = fail $ "Unsupported constructor type: " ++ show c
-int :: Integral a => a -> ExpQ
-int = litE . integerL . toInteger
-
-string :: String -> ExpQ
-string = litE . stringL
-
ifx :: String -> ExpQ -> ExpQ -> ExpQ
ifx op a b = infixE (Just a) (varE $ mkName op) (Just b)
genDSL :: Name -> DecsQ
genDSL typename = reify typename >>= \info->case info of
TyConI (DataD _ _ tyvars _ constructors _)
- -> mapM getConsName constructors >>= mkDSL typename tyvars (map toNameType constructors)
+ -> mapM getConsName constructors >>= mkDSL typename tyvars
t
- -> fail $ "mkConsClass only supports datatypes and not: " ++ show t
+ -> fail $ "mkConsClass only supports simple datatypes and not: " ++ show t
-mkDSL :: Name -> [TyVarBndr] -> [[Field]] -> [Name] -> DecsQ
-mkDSL typeName typeVars fields consNames = sequence [ mkClass, mkPrinter, mkCompiler, mkInterpreter ]
+mkDSL :: Name -> [TyVarBndr] -> [(Name, [(Name, TypeQ)])] -> DecsQ
+mkDSL typeName typeVars constructors = sequence [ mkClass, mkPrinter, mkCompiler, mkInterpreter ]
where
+ (consNames, fields) = unzip constructors
+
mkClass :: DecQ
mkClass = classD (pure []) (className typeName) [PlainTV (mkName "v")] []
- ( zipWith mkConstructor consNames fields
+ ( map (uncurry mkConstructor) constructors
++ concatMap (map mkSelector) fields
++ map mkPredicate consNames
)
where
- view a = varT (mkName "v") `appT` a
- arrow = appT . appT arrowT
+ v = varT $ mkName "v"
+ arrow x y = [t|$x-> $y|]
- mkConstructor :: Name -> [Field] -> DecQ
- mkConstructor n fs = sigD (constructorName n) $ foldr arrow resultT $ map (view . pure . ftype) fs
+ mkConstructor :: Name -> [(Name, TypeQ)] -> DecQ
+ mkConstructor n fs = sigD (constructorName n) $ foldr arrow resultT $ map (appT v . snd) fs
- mkSelector :: Field -> DecQ
- mkSelector f = sigD (selectorName (fname f)) $ resultT `arrow` view (pure $ ftype f)
+ mkSelector :: (Name, TypeQ) -> DecQ
+ mkSelector (n, t) = sigD (selectorName n) [t|$resultT -> $v $t|]
mkPredicate :: Name -> DecQ
- mkPredicate n = sigD (predicateName n) $ resultT `arrow` view (conT (mkName "Bool"))
+ mkPredicate n = sigD (predicateName n) [t|$resultT -> $v Bool|]
resultT :: TypeQ
- resultT = view $ foldl appT (conT typeName) $ map (varT . getNameTyVarBndr) $ typeVars
+ resultT = appT v $ foldl appT (conT typeName) $ map (varT . getNameTyVarBndr) $ typeVars
mkPrinter :: DecQ
- mkPrinter = instanceD (pure []) (appT (conT $ className typeName) (conT $ mkName "Printer"))
- $ zipWith mkConstructor consNames fields
- ++ concatMap (map mkSelector) fields
+ mkPrinter = instanceD (pure []) [t|$(conT $ className typeName) Printer|]
+ $ map (uncurry mkConstructor) constructors
+ ++ concatMap (map (mkSelector . fst)) fields
++ map mkPredicate consNames
where
- pl s = varE (mkName "printLit") `appE` string s
+ pl s = [|printLit $(lift s)|]
- mkConstructor :: Name -> [Field] -> DecQ
+ mkConstructor :: Name -> [(Name, TypeQ)] -> DecQ
mkConstructor consName fs = do
fresh <- sequence [newName "f" | _<- fs]
fun (constructorName consName) (map varP fresh) (pcons `appE` pargs fresh)
- where pcons = varE (mkName "printCons") `appE` string (stringName consName)
+ where pcons = [|printCons $(lift $ stringName consName)|]
pargs fresh = foldl (ifx ">->") (pl "") $ map varE fresh
- mkSelector :: Field -> DecQ
- mkSelector Field{fname=n} = do
- fresh <- newName "f"
- fun (selectorName n) [varP fresh] (ifx ">>" (varE fresh) $ pl ('.':stringName n))
+ mkSelector :: Name -> DecQ
+ mkSelector n = fun (selectorName n) [] [|\x->x >> $(pl ('.':stringName n))|]
mkPredicate :: Name -> DecQ
- mkPredicate n = do
- fresh <- newName "f"
- fun (predicateName n) [varP fresh] (ifx ">->" (pl $ stringName $ predicateName n) $ varE fresh)
+ mkPredicate n = fun (predicateName n) []
+ [|\x-> $(pl $ stringName $ predicateName n) >-> x|]
mkCompiler :: DecQ
- mkCompiler = instanceD (pure []) (appT (conT $ className typeName) (conT $ mkName "Compiler"))
- $ zipWith3 mkConstructor [0..] consNames fields
- ++ concat (zipWith (map . mkSelector) [0..] fields)
+ mkCompiler = instanceD (pure []) [t|$(conT $ className typeName) Compiler|]
+ $ zipWith (uncurry . mkConstructor) [0..] constructors
+ ++ concatMap (zipWith mkSelector [0..] . map fst) fields
++ zipWith mkPredicate [0..] consNames
where
- instrE e = varE (mkName "instr") `appE` listE e
-
- mkConstructor :: Integer -> Name -> [Field] -> DecQ
+ mkConstructor :: Integer -> Name -> [(Name, TypeQ)] -> DecQ
mkConstructor consNum consName fs = do
fresh <- sequence [newName "f" | _<-fs]
fun (constructorName consName) (map varP fresh)
$ ifx "*>" pushCons $ ifx "<*" (mkBody $ map varE fresh) storeHeap
- where storeHeap = instrE [conE (mkName "Sth") `appE` (ifx "+" (int 1) (int $ length fs))]
- mkBody = foldl (ifx "<*>") (varE (mkName "pure") `appE` conE consName)
- pushCons = instrE [conE (mkName "Push") `appE` int consNum]
+ where storeHeap = [|instr [Sth $ 1 + $(lift $ length fs)]|]
+ mkBody = foldl (ifx "<*>") [|pure $(conE consName)|]
+ pushCons = [|instr [Push $(lift consNum)]|]
- mkSelector :: Integer -> Field -> DecQ
- mkSelector consNum Field{fname=f} = do
- fresh <- newName "f"
- fun (selectorName f) [varP fresh]
- $ ifx ">>" (varE fresh) $ instrE [conE (mkName "Ldh") `appE` int consNum]
+ mkSelector :: Integer -> Name -> DecQ
+ mkSelector fn n = fun (selectorName n) [] [|\x->x >> instr [Ldh $(lift fn)]|]
mkPredicate :: Integer -> Name -> DecQ
- mkPredicate consNum consName = do
- fresh <- newName "f"
- fun (predicateName consName) [varP fresh]
- $ ifx ">>" (varE fresh) $ instrE
- [ conE (mkName "Ldh") `appE` int (-1)
- , conE (mkName "Push") `appE` int consNum
- , conE (mkName "Eq")
- ]
+ mkPredicate consNum consName = fun (predicateName consName) []
+ [|\x->x >> instr [Ldh (-1), Push $(lift consNum), Eq]|]
mkInterpreter :: DecQ
- mkInterpreter = instanceD (pure []) (appT (conT $ className typeName) (conT $ mkName "Interpreter"))
- $ zipWith mkConstructor consNames fields
- ++ concatMap (map mkSelector) fields
- ++ zipWith mkPredicate consNames fields
+ mkInterpreter = instanceD (pure []) [t|$(conT $ className typeName) Interpreter|]
+ $ map (uncurry mkConstructor) constructors
+ ++ concatMap (\(cn, fs)->zipWith (mkSelector cn (length fs)) [0..] (map fst fs)) constructors
+ ++ map (uncurry mkPredicate) constructors
where
- wildcase e = if length consNames == 1 then [] else
- [match wildP (normalB e) []]
-
- mkConstructor :: Name -> [Field] -> DecQ
+ mkConstructor :: Name -> [(Name, TypeQ)] -> DecQ
mkConstructor consName fs = do
fresh <- sequence [newName "f" | _<-fs]
fun (constructorName consName) (map varP fresh)
- $ foldl (ifx "<*>") (varE (mkName "pure") `appE` conE consName) (map varE fresh)
+ $ foldl (ifx "<*>") [|pure $(conE consName)|] (map varE fresh)
- mkSelector :: Field -> DecQ
- mkSelector f = do
+ mkSelector :: Name -> Int -> Int -> Name -> DecQ
+ mkSelector consName ftotal fnum n = do
fresh <- newName "f"
- fun (selectorName $ fname f) [varP fresh] $
- ifx ">>=" (varE fresh) $ lamCaseE $ mkMatch : wilds
+ fun (selectorName n) [varP fresh] $
+ ifx ">>=" (varE fresh) $ lamCaseE (mkMatch:wilds)
where
mkMatch = do
fresh <- newName "e"
- match (conP (fcons f) [if fnum f == i then (varP fresh) else wildP | i<-[0..ftotal f-1]])
- (normalB $ varE (mkName "pure") `appE` varE fresh) []
- wilds = wildcase (varE (mkName "fail") `appE` string "Exhausted case")
-
- mkPredicate :: Name -> [Field] -> DecQ
- mkPredicate n fs = do
- fresh <- newName "f"
- fun (predicateName n) [varP fresh] $ ifx "<$>" (lamCaseE (mkMatch:wilds)) (varE fresh)
- where mkMatch = match (conP n [wildP | _<-fs]) (normalB $ conE (mkName "True")) []
- wilds = wildcase (conE $ mkName "False")
+ match (conP consName [if fnum == i then varP fresh else wildP | i<-[0..ftotal-1]])
+ (normalB [|pure $(varE fresh)|]) []
+ wilds = if length consNames == 1 then [] else
+ [match wildP (normalB [|fail "Exhausted case"|]) []]
+
+ mkPredicate :: Name -> [(Name, TypeQ)] -> DecQ
+ mkPredicate n fs = fun (predicateName n) []
+ $ if length consNames == 1 then [|\_->true|] else
+ [|\x->x >>= \p->case p of $(conP n [wildP | _<-fs]) -> true; _ -> false|]