CLASE (empty) → 2008.9.23
raw patch · 13 files changed
+1657/−0 lines, 13 filesdep +basedep +containersdep +filepathsetup-changed
Dependencies added: base, containers, filepath, mtl, parsec, template-haskell
Files
- CLASE.cabal +39/−0
- Data/Cursor/CLASE/Bound.hs +19/−0
- Data/Cursor/CLASE/Gen/Adapters.hs +174/−0
- Data/Cursor/CLASE/Gen/Language.hs +466/−0
- Data/Cursor/CLASE/Gen/Persistence.hs +271/−0
- Data/Cursor/CLASE/Gen/PrintM.hs +18/−0
- Data/Cursor/CLASE/Gen/Util.hs +241/−0
- Data/Cursor/CLASE/Language.hs +169/−0
- Data/Cursor/CLASE/Persistence.hs +172/−0
- Data/Cursor/CLASE/Traversal.hs +38/−0
- Data/Cursor/CLASE/Util.hs +18/−0
- LICENSE +30/−0
- Setup.hs +2/−0
+ CLASE.cabal view
@@ -0,0 +1,39 @@+Name: CLASE+Version: 2008.9.23+Cabal-Version: >= 1.2+License: BSD3+Build-Type: Simple+License-File: LICENSE+Author: Tristan Allwood+Maintainer: clase@zonetora.co.uk+Homepage: http://www.zonetora.co.uk/clase/+Stability: alpha+Synopsis: Cursor Library for A Structured Editor+Description: A library to aid the development of structured editors that+ require a zipper-like interface to the language being edited.+Category: Data+Tested-With: GHC ==6.8.3++Library+ Build-Depends: base,+ parsec >= 2.1.0.1,+ containers >= 0.1.0.2,+ template-haskell,+ filepath >= 1.1.0.0,+ mtl >= 1.1.0.1++ Exposed-Modules: + Data.Cursor.CLASE.Language,+ Data.Cursor.CLASE.Bound,+ Data.Cursor.CLASE.Persistence,+ Data.Cursor.CLASE.Traversal,+ Data.Cursor.CLASE.Util,+ Data.Cursor.CLASE.Gen.Language,+ Data.Cursor.CLASE.Gen.Adapters,+ Data.Cursor.CLASE.Gen.Persistence++ Other-Modules:+ Data.Cursor.CLASE.Gen.Util,+ Data.Cursor.CLASE.Gen.PrintM++ Extensions:
+ Data/Cursor/CLASE/Bound.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE GADTs, MultiParamTypeClasses #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Bound(+ Bound(..),+ inBindingScope+) where++import Data.Cursor.CLASE.Language++class (Language l) => Bound l t where+ bindingHook :: Context l from to -> t -> t+++inBindingScope :: (Bound l t) => (a -> t) -> Cursor l x a -> t+inBindingScope fn (Cursor it ctx _) = foldUp (fn it) ctx++foldUp :: (Bound l t) => t -> Path l (Context l) a b -> t+foldUp t Stop = t+foldUp t (Step ctx nxt) = foldUp (bindingHook ctx t) nxt
+ Data/Cursor/CLASE/Gen/Adapters.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE TemplateHaskell, PatternSignatures #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Gen.Adapters(adapterGen) where++import Data.List+import Data.Maybe+import Data.Cursor.CLASE.Gen.Util+import Language.Haskell.TH+import Data.Cursor.CLASE.Gen.PrintM+import System.FilePath+import System.IO++import qualified Data.Map as Map+import Data.Map (Map)++adapterGen :: [String] -> Name -> [Name] -> String -> Q [Dec]+adapterGen moduleNames rootName acceptableNames gendLanguage = do+ nameMap <- buildMap acceptableNames++ fileOut <- runIO $ openFile (joinPath moduleNames <.> "hs") WriteMode++ let rootNameModule = nameModule rootName+ let moduleName = concat . intersperse "." $ moduleNames+++ runIO . runPrint fileOut $ do+ printHeader moduleName (fromMaybe "" rootNameModule) gendLanguage++ printClasses rootName nameMap++ printVisitCursor rootName++ printInstanceHeader rootName acceptableNames++ let contextCtrs = buildContextCtrs nameMap++ printVisitStep rootName nameMap contextCtrs++ printVisitPartial rootName acceptableNames contextCtrs++ printCursor+ runIO $ hFlush fileOut+ runIO $ hClose fileOut++ return [] ++printHeader :: String -> String -> String -> PrintM ()+printHeader modName rootModName rootLangModName = do+ printLn . unlines $ [ "{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FlexibleContexts,"+ , " UndecidableInstances, RankNTypes, GADTs, TypeFamilies #-}"+ , "{-# OPTIONS_GHC -Wall -fno-warn-orphans -fno-warn-name-shadowing #-}"++ , "module " ++ modName ++ " where"+ , "{- AUTOGENERATED (See Data.Cursor.CLASE.Gen.Adapters) -}"+ , ""+ , "import " ++ rootModName + , "import " ++ rootLangModName+ , "import Data.Cursor.CLASE.Language"+ , "import Data.Cursor.CLASE.Bound"+ , "import Data.Cursor.CLASE.Traversal"+ ]++printClasses :: Name -> Map Name DataType -> PrintM ()+printClasses rootName = mapM_ (uncurry printClass) . Map.toList+ where+ rootNameS = nameBase rootName++ printClass :: Name -> DataType -> PrintM ()+ printClass clNam (DataType _ ctrs) = do+ printLn $ "class " ++ rootNameS ++ "TraversalAdapter" ++ clNamS ++ " t where"+ mapM_ printCases ctrs+ printLn ""+ where+ clNamS = nameBase clNam++ printCases :: Constructor -> PrintM ()+ printCases ctr = do+ printLn $ " visit" ++ ctrNameS ++ " :: " ++ tipe+ where+ tipe = concat . intersperse " -> " $ clNamS : + (map (const "t") . filter isNavigable . ctrKids $ ctr) ++ ["t"]+ ctrNameS = nameBase .ctrName $ ctr ++ printClass _ _ = error "printClass for wraps list not supported [yet]!"+ + ++printVisitCursor :: Name -> PrintM ()+printVisitCursor nam = do+ printLn . unlines $ + [ "class " ++ (nameBase nam) ++ "TraversalAdapterCursor t where"+ , " visitCursor :: " ++ (nameBase nam) ++ " -> t -> t"+ ]++printInstanceHeader :: Name -> [Name] -> PrintM ()+printInstanceHeader rootName okNames = do+ printLn $ "instance (" ++ preconds +++ "\n " ++ rootNameS ++ "TraversalAdapterCursor t," +++ "\n Bound " ++ rootNameS ++ " t) => Traversal " ++ rootNameS ++ " t where\n"+ where+ preconds = concat . intersperse "\n " . + map (\n -> rootNameS ++ "TraversalAdapter" ++ n ++ " t,") $ okNameS++ rootNameS = nameBase rootName+ okNameS = map nameBase okNames+ ++printVisitStep :: Name -> Map Name DataType -> [ContextCtr] -> PrintM ()+printVisitStep rootName nameMap ctxCtrs = do+ printLn . unlines $ + [ " visitStep it recurse = case reify it of"+ , " TW x -> visitStep' x it recurse"+ , " where"+ , " visitStep' :: (" ++ preconds ++ ") =>"+ , " TypeRepI a -> a -> (forall b . Reify " ++ rootNameS ++ " b => Movement " ++ rootNameS ++ " Down a b -> t) -> t"+ ]+ mapM_ (uncurry printVisitStepCase) (Map.toList nameMap)+ printLn ""+ where+ preconds = concat . intersperse ",\n " . + map (\n -> rootNameS ++ "TraversalAdapter" ++ n ++ " t") .+ map nameBase . + Map.keys $ nameMap+ rootNameS = nameBase rootName++ printVisitStepCase :: Name -> DataType -> PrintM ()+ printVisitStepCase tipe (DataType _ ctrs) = do+ printLn $ " visitStep' " ++ tipeS ++ "T it recurse = case it of"+ mapM_ printVisitStepCtrCase ctrs+ where+ tipeS = nameBase tipe++ printVisitStepCtrCase (Ctr ctrName kids) = do+ printLn $ " " ++ ctrNameS ++ " " ++ underscorePattern ++ " -> visit" ++ ctrNameS ++ " it " ++ recursePatterns+ where+ ctrNameS = nameBase ctrName+ underscorePattern = unwords $ replicate (length kids) "_" + recursePatterns = unwords . map (\k -> "(recurse (MW " ++ (downCtrName k) ++ "))") . filter ( (== ctrName) . ctxCtrCtrTo) $ ctxCtrs+ --recursePatterns = unwords . map (\k -> "(recurse (MW M" ++ ctrNameS ++ "To" ++ (nameBase . childType $ k) ++ "))") . filter isNavigable $ kids+ + printVisitStepCase _ _ = error "Can't prinit visitStep case for list dts yet"+++printVisitPartial :: Name -> [Name] -> [ContextCtr] -> PrintM ()+printVisitPartial rootName okNames ctxCtrs = do+ printLn . unlines $ + [ " visitPartial (CW ctx) = visitPartial' ctx"+ , " where"+ , " visitPartial' :: (" ++ preconds ++ ") =>"+ , " ContextI a b -> b -> t -> (forall c . Reify " ++ rootNameS ++ " c => Movement " ++ rootNameS ++ " Down b c -> t) -> t"+ , " visitPartial' ctx it hole recurse = case ctx of"+ ]+ mapM_ printCtrCase ctxCtrs+ printLn ""+ where+ rootNameS :: String+ rootNameS = nameBase rootName++ preconds :: String+ preconds = concat . intersperse ",\n " . + map (\n -> rootNameS ++ "TraversalAdapter" ++ n ++ " t") $ okNameS+ okNameS = map nameBase okNames++ printCtrCase :: ContextCtr -> PrintM ()+ printCtrCase cc = do+ printLn $ " " ++ (ctxCtrName cc) ++ " " ++ underscores ++ " -> visit" ++ (nameBase . ctxCtrCtrTo $ cc) ++ " it " ++ recursePatterns+ where+ underscores = unwords $ replicate (numCCArgs cc) "_"+ recursePatterns = unwords . map (\k -> if k == cc + then "hole"+ else "(recurse (MW " ++ (downCtrName k) ++ "))") . filter ( (==(ctxCtrCtrTo cc) ) . ctxCtrCtrTo) $ ctxCtrs++printCursor :: PrintM ()+printCursor = printLn $ " cursor = visitCursor"
+ Data/Cursor/CLASE/Gen/Language.hs view
@@ -0,0 +1,466 @@+{-# LANGUAGE TemplateHaskell, PatternSignatures #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Gen.Language(languageGen) where++import Control.Arrow+import Control.Monad+import Data.List+import Data.Map (Map)+import Data.Ord+import Data.Function+import Data.Maybe+import Data.Set (Set)+import Data.Cursor.CLASE.Gen.Util+import Data.Cursor.CLASE.Gen.PrintM+import System.FilePath+import Language.Haskell.TH+import qualified Data.Map as Map+import qualified Data.Set as Set+import System.IO++languageGen :: [String] -> Name -> [Name] -> Q [Dec]+languageGen moduleNames rootName acceptableNames = do+ nameMap <- buildMap acceptableNames+ + fileOut <- runIO $ openFile (joinPath moduleNames <.> "hs") WriteMode++ let rootNameModule = nameModule rootName+ let moduleName = concat . intersperse "." $ moduleNames++ runIO . runPrint fileOut $ do+ printHeader moduleName rootNameModule (nameBase rootName)+ printLn ""++ printTypeRep nameMap+ printLn ""++ printReify rootName nameMap+ printLn ""++ let contextCtrs = buildContextCtrs nameMap++ printContext contextCtrs+ printLn ""++ printContextToMovement contextCtrs+ printLn ""++ printBuildOne contextCtrs+ printLn ""++ let leftRightNames = buildLeftRightNames nameMap+ printMovement contextCtrs leftRightNames+ printLn ""++ printInvertMovement contextCtrs leftRightNames+ printLn ""++ printMovementEq contextCtrs leftRightNames+ printLn ""++ printUnbuildOne contextCtrs leftRightNames+ printLn ""++ printReifyDirection contextCtrs+ printLn ""++ printDownMovements rootName contextCtrs+ printLn ""++ printGenericMoveLeft contextCtrs nameMap rootName+ printLn ""++ printGenericMoveRight contextCtrs nameMap rootName+ printLn ""++{-+ printToStringMovement contextCtrs leftRightNames+ printLn ""++ printContextReps contextCtrs+ printLn ""++ printMoveToRoot rootName+ printLn ""+-}++ runIO $ hFlush fileOut+ runIO $ hClose fileOut++ return []++printHeader :: String -> Maybe String -> String -> PrintM ()+printHeader modName mRootModName rootName = do+ printLn . unlines $ + [ "{-# LANGUAGE GADTs, MultiParamTypeClasses, TypeFamilies, TypeOperators, ScopedTypeVariables, ExistentialQuantification #-}"+ , "{-# OPTIONS_GHC -Wall -fno-warn-orphans -fno-warn-overlapping-patterns #-}"+ , "{- AUTOGENERATED (See Data.Cursor.CLASE.Gen.Language) -}"+ , "module " ++ modName ++ "("+ , " ContextI(..)"+ , " ,TypeRepI(..)"+ , " ,MovementI(..)"+ , " ,Context(..)"+ , " ,Movement(..)"+ , " ,TypeRep(..)"+ , ") where"+ , "import Data.Maybe"+ , "import Data.Cursor.CLASE.Util"+ , "import Control.Arrow"+ , maybe "" ("import " ++) mRootModName+ , "import Data.Cursor.CLASE.Language"+ , ""+ , "instance Language " ++ rootName ++ " where"+ , " data Context " ++ rootName ++ " from to = CW (ContextI from to)"+ , " data Movement " ++ rootName ++ " d from to = MW (MovementI d from to)"+ , " data TypeRep " ++ rootName ++ " t = TW (TypeRepI t)"+ , ""+ , " buildOne (CW x) = buildOneI x"+ , " unbuildOne (MW m) a = fmap (first CW) (unbuildOneI m a)"+ , " invertMovement (MW x) = MW (invertMovementI x)"+ , " movementEq (MW x) (MW y) = fmap snd $ movementEqI x y"+ , " reifyDirection (MW x) = reifyDirectionI x"+ , " contextToMovement (CW x) = MW (contextToMovementI x)"+ , " downMoves (TW t) = map (\\(ExistsR x) -> ExistsR (MW x)) (downMovesI t)"+ , " moveLeft (MW m) = fmap (\\(ExistsR x) -> ExistsR (MW x)) (moveLeftI m)"+ , " moveRight (MW m) = fmap (\\(ExistsR x) -> ExistsR (MW x)) (moveRightI m)"+ ]++buildLeftRightNames :: Map Name DataType -> Set Name+buildLeftRightNames = Set.fromList . map dtChildName . filter isWrapsList . Map.elems++printTypeRep :: Map Name DataType -> PrintM ()+printTypeRep nmap = do+ printLn "data TypeRepI a where"+ mapM_ printTypeRepLine (Map.keys nmap)+ where+ printTypeRepLine :: Name -> PrintM ()+ printTypeRepLine name = printLn $ " " ++ (nameBase name) ++ "T :: TypeRepI " ++ (nameBase name)+++printReify :: Name -> Map Name DataType -> PrintM ()+printReify langName nmap = do+ mapM_ printReifyInstance (Map.keys nmap)+ where+ printReifyInstance :: Name -> PrintM ()+ printReifyInstance name = do+ printLn . unwords $ ["instance Reify", (nameBase langName),+ (nameBase name), "where"]+ printLn $ " reify = const $ TW " ++ (nameBase name) ++ "T"+ printLn ""++printContext :: [ContextCtr] -> PrintM ()+printContext ctrs = do+ printLn "data ContextI a b where"+ mapM_ printContextCtr ctrs+ where+ printContextCtr :: ContextCtr -> PrintM ()+ printContextCtr cc = do+ printLn $ " " ++ (ctxCtrName cc) ++ " :: " ++ tipes ++ " " ++ (typeFrom) ++ " " ++ (typeTo)+ where+ tipes = concat . intersperse " -> " $ (ctxArgs) ++ ["ContextI"]+ typeFrom = nameBase . ctxCtrTypeFrom $ cc+ typeTo = nameBase . ctxCtrTypeTo $ cc++ ctxListArgs+ | ctxCtrIsList cc = replicate 2 ("[" ++ typeFrom ++ "]")+ | otherwise = []+ ctxArgs = (ctxCtrArgsBefore cc) ++ ctxListArgs ++ (ctxCtrArgsAfter cc)++printContextToMovement :: [ContextCtr] -> PrintM ()+printContextToMovement ctrs = do+ printLn "contextToMovementI :: ContextI a b -> MovementI Up a b"+ mapM_ printContextToMovementLine ctrs+ where+ printContextToMovementLine :: ContextCtr -> PrintM ()+ printContextToMovementLine cc = do+ printLn $ "contextToMovementI " ++ pattern ++ " = " ++ movPattern+ where+ pattern = "(" ++ vars ++ ")"+ movPattern = "(MUp " ++ (downCtrName cc) ++ ")"+ vars = unwords $ [ctxCtrName cc] ++ replicate (numCCArgs cc) "_"++printBuildOne :: [ContextCtr] -> PrintM ()+printBuildOne ctrs = do+ printLn "buildOneI :: ContextI a b -> a -> b"+ mapM_ printBuildOneLine ctrs+ where+ printBuildOneLine :: ContextCtr -> PrintM ()+ printBuildOneLine cc = do+ printLn $ "buildOneI (" ++ pattern ++ ") h = " ++ (ctrPattern)+ where+ (pattern, ctrPattern) = buildPatterns cc++buildPatterns :: ContextCtr -> (String, String)+buildPatterns cc = (pattern, ctrPattern)+ where+ ctrPattern = unwords $ [nameBase . ctxCtrCtrTo $ cc] ++ argsPattern+ pattern = unwords $ [ctxCtrName cc] ++ varsPattern++ argsPattern = preVars ++ ctxArgs ++ postVars++ varsPattern = preVars ++ ctxVars ++ postVars+ (preVars, postVars) = second (take (length $ ctxCtrArgsAfter cc)) . + splitAt (length $ ctxCtrArgsBefore cc) $ vars+ + ctxVars+ | ctxCtrIsList cc = ["l", "r"]+ | otherwise = []++ ctxArgs+ | ctxCtrIsList cc = ["((reverse l) ++ [h] ++ r)"]+ | otherwise = ["h"]++ vars :: [String] + vars = map (('x':) . show) [(0::Integer)..]++buildApplyMovementPatterns :: ContextCtr -> (String, String)+buildApplyMovementPatterns cc = (ctxPattern, ctrPattern)+ where+ ctxPattern = unwords $ [ctxCtrName cc] ++ argsPattern+ ctrPattern = unwords $ [nameBase . ctxCtrCtrTo $ cc] ++ varsPattern++ argsPattern = preVars ++ ctxArgs ++ postVars+ varsPattern = preVars ++ ctxVars ++ postVars++ (preVars, postVars) = second (take (length $ ctxCtrArgsAfter cc)) . + splitAt (length $ ctxCtrArgsBefore cc) $ vars++ ctxVars+ | ctxCtrIsList cc = ["(h:es)"]+ | otherwise = ["h"]++ ctxArgs+ | ctxCtrIsList cc = ["[] es"]+ | otherwise = []+ + vars :: [String]+ vars = map (('x':) . show) [(0::Integer)..]++buildLeftRightPatterns :: ContextCtr -> String -> String -> (String, String)+buildLeftRightPatterns cc lop rop = (ctxPatternBefore, ctxPatternAfter)+ where+ ctxPatternBefore = unwords $ [ctxCtrName cc] ++ beforePattern+ ctxPatternAfter = unwords $ [ctxCtrName cc] ++ afterPattern++ beforePattern = preVars ++ bArgs ++ postVars+ afterPattern = preVars ++ aArgs ++ postVars++ (preVars, postVars) = second (take (length $ ctxCtrArgsAfter cc)) . + splitAt (length $ ctxCtrArgsBefore cc) $ vars++ bArgs+ | ctxCtrIsList cc = ["l", "r"]+ | otherwise = error "CtxCtr is not list!"++ aArgs+ | ctxCtrIsList cc = ["(" ++ lop ++ "l" ++")","(" ++ rop ++ "r" ++ ")"]+ | otherwise = error "CtxCtr is not list!"+ + vars :: [String]+ vars = map (('x':) . show) [(0::Integer)..]++printMovement :: [ContextCtr] -> Set Name -> PrintM ()+printMovement downRoutes _ {- TODO leftRights -} = do+ printLn "data MovementI d a b where"+ printLn " MUp :: MovementI Down b a -> MovementI Up a b"+ mapM_ printDownMovement downRoutes+ --mapM_ printLeftRight (Set.toList leftRights)+ where+ printDownMovement :: ContextCtr -> PrintM ()+ printDownMovement cc = do+ printLn $ " " ++ (downCtrName cc) ++ " :: MovementI Down " ++ fromS ++ " " ++ toS+ where+ fromS = nameBase . ctxCtrTypeTo $ cc+ toS = nameBase . ctxCtrTypeFrom $ cc++{-+ printLeftRight :: Name -> PrintM ()+ printLeftRight name = do+ printLn $ " M" ++ nameS ++ "Left" ++ rest+ printLn $ " M" ++ nameS ++ "Right" ++ rest+ where+ nameS = nameBase name + rest = " :: Movement " ++ nameS ++ " " ++ nameS+-}++printMovementEq :: [ContextCtr] -> Set Name -> PrintM ()+printMovementEq downRoutes leftRights = do+ printLn "movementEqI :: MovementI d x y -> MovementI d a b -> Maybe (TyEq x a, TyEq y b)"+ printLn "movementEqI (MUp a) (MUp b) = fmap (\\(x,y) -> (y,x)) $ movementEqI a b"+ mapM_ printDownMovementEq downRoutes+ mapM_ printLeftRightEq (Set.toList leftRights)+ printLn "movementEqI _ _ = Nothing"+ where+ printDownMovementEq :: ContextCtr -> PrintM ()+ printDownMovementEq cc = do+ printLn $ "movementEqI " ++ (downCtrName cc) ++ " " ++ (downCtrName cc) ++ " = Just (Eq, Eq)"++ printLeftRightEq :: Name -> PrintM ()+ printLeftRightEq name = do+ printLn $ "movementEqI " ++ (nameS ++ "Left") ++ " " ++ (nameS ++ "Left") ++ " = Just (Eq, Eq)"+ printLn $ "movementEqI " ++ (nameS ++ "Right") ++ " " ++ (nameS ++ "Right") ++ " = Just (Eq, Eq)"+ where+ nameS = "M" ++ nameBase name++printInvertMovement :: [ContextCtr] -> Set Name -> PrintM ()+printInvertMovement ctxCtrs leftRights = do+ printLn "invertMovementI :: MovementI d a b -> MovementI (Invert d) b a"+ printLn "invertMovementI (MUp dwn) = dwn"+ mapM_ printInvertDownRoute downPatterns+ mapM_ printInvertLeftRights (Set.toList leftRights)+ where+ downPatterns = map getDownCtr $ ctxCtrs++ getDownCtr :: ContextCtr -> String+ getDownCtr ctxCtr = sDownCtr+ where+ sDownCtr = liftM3 (\x y z -> "M" ++ x ++ "To" ++ y ++ z) + (nameBase . ctxCtrCtrTo) + (nameBase . ctxCtrTypeFrom) + (maybe "" show . ctxCtrOffset) ctxCtr ++ printInvertDownRoute :: String -> PrintM ()+ printInvertDownRoute sDownCtr = do+ printLn $ "invertMovementI " ++ sDownCtr ++ " = MUp (" ++ sDownCtr ++ ")"++ printInvertLeftRights :: Name -> PrintM ()+ printInvertLeftRights name = do+ printLn $ "invertMovementI " ++ (nameS ++ "Left = IMLeftRight " ++ nameS ++ "Right")+ printLn $ "invertMovementI " ++ (nameS ++ "Right = IMLeftRight " ++ nameS ++ "Left")+ where+ nameS = "M" ++ nameBase name++printUnbuildOne :: [ContextCtr] -> Set Name -> PrintM ()+printUnbuildOne contextCtrs leftRights = do+ printLn . unlines $ + [ "unbuildOneI :: MovementI Down a b -> a -> Maybe (ContextI b a, b)",+ "unbuildOneI mov here = case mov of"]+ downMoveCases+ leftRightMoveCases+ printLn $ " _ -> Nothing"+ where+ downMoveCases = mapM_ downMoveCase contextCtrs++ downMoveCase cc = do+ printLn $ " " ++ (downCtrName cc) ++ " -> case here of"+ printLn $ " (" ++ ctrPattern ++ ") -> " ++ "Just $ (" ++ ctrctxPattern ++ ", h)"+ printLn $ " _ -> Nothing"+ where+ (ctrctxPattern, ctrPattern) = buildApplyMovementPatterns cc++ leftRightMoveCases = mapM_ leftRightMoveCase (Set.toList leftRights)++ leftRightMoveCase name = do+ printLn $ " M" ++ nameBase name ++ "Left -> case step of"+ mapM_ leftMoveCase ctxCtrs+ printLn $ " _ -> Nothing"+ printLn $ " M" ++ nameBase name ++ "Right -> case step of"+ mapM_ rightMoveCase ctxCtrs+ printLn $ " _ -> Nothing"+ where+ ctxCtrs = filter (liftM2 (&&) ((== name) . ctxCtrTypeFrom)+ (ctxCtrIsList)) contextCtrs++ leftMoveCase = moveCase "l" "tail " "it:"+ rightMoveCase = moveCase "r" "it:" "tail " ++ moveCase lr y z ctxCtr = do+ printLn $ " (" ++ ctxCtrPatternBefore ++ ") -> if' (null " ++ lr ++ ") " ++ + "Nothing " +++ "(Just $ ((head " ++ lr ++ "), " ++ ctxCtrPatternAfter ++ ")"+ where+ (ctxCtrPatternBefore, ctxCtrPatternAfter) = buildLeftRightPatterns ctxCtr y z+++printReifyDirection :: [ContextCtr] -> PrintM ()+printReifyDirection ctrs = do+ printLn $ "reifyDirectionI :: MovementI d a b -> DirectionT d"+ printLn $ "reifyDirectionI d = case d of"+ printLn $ " (MUp _) -> UpT"+ mapM_ reifyDirectionDown ctrs+ where+ reifyDirectionDown :: ContextCtr -> PrintM ()+ reifyDirectionDown cc = printLn $ " " ++ (downCtrName cc) ++ " -> DownT"++printGenericMoveLR :: String -> (ContextCtr -> [Child] -> Maybe (Child, Maybe Int)) -> [ContextCtr] -> Map Name DataType -> Name -> PrintM ()+printGenericMoveLR leftOrRight beforeOrAfterFn ctxcts dataMap rootName = do+ printLn $ "move" ++ leftOrRight ++ "I :: MovementI Down a x -> Maybe (ExistsR " ++ (nameBase rootName) ++ " (MovementI Down a))"+ printLn $ "move" ++ leftOrRight ++ "I mov = case mov of"+ mapM_ genericMove ctxcts+ printLn " _ -> Nothing"+ where+ genericMove :: ContextCtr -> PrintM ()+ genericMove cc+ | isJust nextKid = do+ printLn $ " " ++ (downCtrName cc) ++ " -> Just $ ExistsR " ++ notListMovement+ | otherwise = return ()+ where+ currName = ctxCtrCtrTo cc+ notListMovement = "M" ++ nameBase currName ++ "To" ++ nxtName+ --TODO listMovement = "M" ++ nameBase lstNxtName ++ leftOrRight+ --TODO lstNxtName = ctxCtrTypeFrom cc++ (Just ctr) = liftM (head . filter ( (== (ctxCtrCtrTo cc)) . ctrName ) . dtCtrs) . + Map.lookup (ctxCtrTypeTo cc) $ dataMap+ nextKid@(~(Just (child, moffset))) = beforeOrAfterFn cc (ctrKids ctr)+ nxtName = (nameBase . childType $ child) ++ (maybe "" show moffset)+ ++printGenericMoveRight :: [ContextCtr] -> Map Name DataType -> Name -> PrintM ()+printGenericMoveRight = printGenericMoveLR "Right" grabNextChild+ where+ grabNextChild :: ContextCtr -> [Child] -> Maybe (Child, Maybe Int)+ grabNextChild cc kids = liftM (id &&& calcOffset . childType) nextKid+ where+ calcOffset :: Name -> Maybe Int+ calcOffset nam+ | length allOtherKidsWithTheSameName > 1 = Just (length otherKidsWithTheSameNameBefore)+ | otherwise = Nothing+ where+ otherKidsWithTheSameNameBefore = filter (== nam) $ beforeKids ++ [currKid] + allOtherKidsWithTheSameName = otherKidsWithTheSameNameBefore ++ (filter (== nam) afterKids)+ nextKid = listToMaybe . filter isNavigable . drop 1 . drop (length beforeKids) $ kids+ beforeKids = ctxCtrTypesBefore cc+ afterKids = ctxCtrTypesAfter cc+ currKid = ctxCtrTypeFrom cc++printGenericMoveLeft :: [ContextCtr] -> Map Name DataType -> Name -> PrintM ()+printGenericMoveLeft = printGenericMoveLR "Left" grabNextChild+ where+ grabNextChild :: ContextCtr -> [Child] -> Maybe (Child, Maybe Int)+ grabNextChild cc kids = liftM (id &&& calcOffset . childType) nextKid+ where+ calcOffset :: Name -> Maybe Int+ calcOffset nam+ | length allOtherKidsWithTheSameName > 1 = Just (pred . length $ otherKidsWithTheSameNameBefore)+ | otherwise = Nothing+ where+ otherKidsWithTheSameNameBefore = filter (== nam) $ beforeKids++ allOtherKidsWithTheSameName = otherKidsWithTheSameNameBefore ++ (filter (== nam) [currKid] ++ afterKids)++ nextKid = listToMaybe . filter isNavigable . reverse . take (length beforeKids) $ kids+ beforeKids = ctxCtrTypesBefore cc+ afterKids = ctxCtrTypesAfter cc+ currKid = ctxCtrTypeFrom cc+++printDownMovements :: Name -> [ContextCtr] -> PrintM ()+printDownMovements langName ctxCtrs = do+ printLn $ "downMovesI :: TypeRepI a -> [ExistsR " ++ lNameS ++ " (MovementI Down a)]"+ printLn $ "downMovesI tr = case tr of "+ mapM_ (uncurry printTrCase) ctrsByTypeTo+ where+ lNameS = nameBase langName++ ctrsByTypeTo :: [(Name, [ContextCtr])]+ ctrsByTypeTo = map ((ctxCtrTypeTo . head) &&& id) . + groupBy ((==) `on` ctxCtrTypeTo) . + sortBy (comparing ctxCtrTypeTo) $ ctxCtrs++ printTrCase :: Name -> [ContextCtr] -> PrintM ()+ printTrCase trCase localCtrs = do+ printLn $ " " ++ (nameBase trCase) ++ "T -> [" ++ dctrs ++ "]"+ where+ dctrs = concat . intersperse ", " . map (\x -> "(ExistsR " ++ x ++ ")") $ downCtrs+ downCtrs = map downCtrName localCtrs
+ Data/Cursor/CLASE/Gen/Persistence.hs view
@@ -0,0 +1,271 @@+{-# LANGUAGE TemplateHaskell, PatternSignatures #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Gen.Persistence(persistenceGen) where++import Language.Haskell.TH+import Data.Cursor.CLASE.Gen.Util+import Data.Cursor.CLASE.Gen.PrintM+import System.IO+import System.FilePath+import Data.List+import Data.Maybe+import Control.Monad++persistenceGen :: [String] -> Name -> [Name] -> String -> Q [Dec]+persistenceGen moduleNames rootName acceptableNames gendLanguage = do+ nameMap <- buildMap acceptableNames++ let contextCtrs = buildContextCtrs nameMap++ fileOut <- runIO $ openFile (joinPath moduleNames <.> "hs") WriteMode++ let rootNameModule = nameModule rootName+ let moduleName = concat . intersperse "." $ moduleNames+++ runIO . runPrint fileOut $ do+ printHeader moduleName (fromMaybe "" rootNameModule) gendLanguage++ printClassHeader rootName++ printShowMovement contextCtrs++ printMovementUpDownLines++ printShowTypeRep rootName acceptableNames++ printTypeRepParser rootName acceptableNames++ printTypeRepEq rootName acceptableNames++ printUpMovesParser rootName acceptableNames contextCtrs++ printDownMovesParser rootName acceptableNames contextCtrs++ printFooter++ runIO $ do+ hFlush fileOut+ hClose fileOut++ return []++printHeader :: String -> String -> String -> PrintM ()+printHeader modName rootModName rootLangModName = do+ printLn . unlines $ + [ "{-# LANGUAGE TypeFamilies #-}"+ , "{-# LANGUAGE GADTs #-}"+ , "{-# LANGUAGE UndecidableInstances #-}"+ , "{-# LANGUAGE FlexibleContexts #-}"+ , "{-# LANGUAGE ScopedTypeVariables #-}"+ , "{-# LANGUAGE PatternSignatures #-}"+ , "{-# LANGUAGE RankNTypes #-}"+ , "{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing -fno-warn-orphans -fno-warn-incomplete-patterns #-}"+ , "module " ++ modName ++ " where"+ , "{- AUTOGENERATED (See Data.Cursor.CLASE.Gen.Persistence) -}"+ , ""+ , "import " ++ rootModName+ , "import " ++ rootLangModName+ , "import Data.Cursor.CLASE.Language"+ , "import Data.Cursor.CLASE.Persistence"+ , "import qualified Text.ParserCombinators.Parsec.Language as P"+ , "import qualified Text.ParserCombinators.Parsec.Token as P"+ , "import Text.ParserCombinators.Parsec"+ , "import Data.Cursor.CLASE.Util"+ ]++printClassHeader :: Name -> PrintM ()+printClassHeader rootName = do+ printLn $ "instance (PersistenceAdapter " ++ rootNameS ++ ") => Persistable " ++ rootNameS ++ " where"+ printLn ""+ where+ rootNameS = nameBase rootName++printShowMovement :: [ContextCtr] -> PrintM ()+printShowMovement ctxCtrs = do+ printLns $+ [ " showMovement (MW x) = show' x"+ , " where"+ , " show' :: MovementI dir from to -> String"+ ]++ forM_ ctxCtrs printShowUpMovement+ forM_ ctxCtrs printShowDownMovement++ printLn ""+ where+ printShowUpMovement cc = printLn $+ " show' (MUp " ++ smupctr ++ ") = \"" ++ mupctrshown ++ "\""+ where+ smupctr = downCtrName cc+ mupctrshown = upCtrNameShown cc++ printShowDownMovement cc = printLn $+ " show' " ++ smupctr ++ " = \"" ++ smupctr ++ "\""+ where+ smupctr = downCtrName cc++printMovementUpDownLines :: PrintM ()+printMovementUpDownLines = do+ printLns $+ [ " movementParser UpT = upMovesParser"+ , " movementParser DownT = downMovesParser"+ , ""+ ]++printShowTypeRep :: Name -> [Name] -> PrintM ()+printShowTypeRep rootName acceptableNames = do+ let rootNameS = nameBase rootName+ printLns $+ [ " showTypeRep = showTypeRep'"+ , " where"+ , " showTypeRep' :: forall a . TypeRep " ++ rootNameS ++ " a -> String"+ ]++ forM_ acceptableNames $ \name -> do+ let nameS = nameBase name+ printLn $ " showTypeRep' (TW (" ++ nameS ++ "T :: TypeRepI a)) = \"" ++ nameS ++ "T\""++ printLn ""+++printTypeRepParser :: Name -> [Name] -> PrintM ()+printTypeRepParser rootName acceptableNames = do+ printLns $ + [ " typeRepParser = choice $ map (uncurry mkParser) itReps"+ , " where"+ , " itReps = [" ++ itRepLines ++ "]"+ , ""+ , " mkParser :: String -> Exists (TypeRep " ++ rootNameS ++ ") -> Parser (Exists (TypeRep " ++ rootNameS ++ "))"+ , " mkParser s v = try $ (symbol s >> return v)"+ , ""+ ]+ where+ rootNameS = nameBase rootName+ itRepLines = concat . intersperse ",\n " $ itReps+ + itReps = map (\name -> let nameS = (nameBase name ++ "T") in+ "(\"" ++ nameS ++ "\", (Exists (TW " ++ nameS ++ ")))") + acceptableNames++printTypeRepEq :: Name -> [Name] -> PrintM ()+printTypeRepEq rootName acceptableNames = do+ printLns $+ [ " typeRepEq = typeRepEq'"+ , " where"+ , " typeRepEq' :: forall a b . TypeRep " ++ rootNameS ++ " a -> TypeRep " ++ rootNameS ++ " b -> Maybe (TyEq a b)"+ ]++ printLns reps++ printLn " typeRepEq' _ _ = Nothing"+ printLn ""+ where+ rootNameS = nameBase rootName+ reps = map (\name -> let nameS = (nameBase name ++ "T") in+ " typeRepEq' (TW (" ++ nameS ++ " :: TypeRepI a)) (TW (" ++ + nameS ++ " :: TypeRepI b)) = Just Eq") $ acceptableNames+ +printUpMovesParser :: Name -> [Name] -> [ContextCtr] -> PrintM ()+printUpMovesParser rootName acceptableNames ctxctrs = do+ printLns $+ [ "upMovesParser :: forall a . (Reify " ++ rootNameS ++ " a) => Parser ((ExistsR " ++ rootNameS ++ " (Movement " ++ rootNameS ++ " Up a)))"+ , "upMovesParser = upMovesParser' (reify (undefined :: a))"+ , " where"+ , " upMovesParser' :: forall a . (Reify " ++ rootNameS ++ " a) => TypeRep " ++ rootNameS ++ " a -> "+ , " Parser ((ExistsR " ++ rootNameS ++ " (Movement " ++ rootNameS ++ " Up a)))"+ , " upMovesParser' (TW x) = case x of"+ ]++ printLns $ cases+ + printLn ""+ printLns $+ [ " use options = choice $ map (uncurry mkParser) options"+ , " c :: forall a b . (Reify " ++ rootNameS ++ " b) => " +++ "MovementI Up a b -> Parser (ExistsR " ++ rootNameS ++ " (Movement " ++ rootNameS ++ " Up a))"+ , " c = return . ExistsR . MW"+ , " mkParser p s = try (symbol s >> p)"+ ]+ printLn ""++ where+ rootNameS = nameBase rootName+ cases = concatMap mkOptions acceptableNames+ + mkOptions :: Name -> [String]+ mkOptions name + | null options = [ " (" ++ nameS ++ " :: TypeRepI a) -> use []"]+ | otherwise = [ " (" ++ nameS ++ " :: TypeRepI a) -> use options"+ , " where"+ , " options ="+ , " [ " ++ optionLines + , " ]"+ ]+ where+ nameS = nameBase name ++ "T"+ options = filter ((== name) . ctxCtrTypeFrom) ctxctrs+ optionLines = concat . intersperse "\n , " . map mkOptionLine $ options++ mkOptionLine ctxCtr = "(c $ (MUp " ++ dcs ++ "), \"" ++ ucs ++ "\")"+ where+ dcs = downCtrName ctxCtr+ ucs = upCtrNameShown ctxCtr+++printDownMovesParser :: Name -> [Name] -> [ContextCtr] -> PrintM ()+printDownMovesParser rootName acceptableNames ctxCtrs = do+ printLns $+ [ "downMovesParser :: forall a . (Reify " ++ rootNameS ++ " a) => Parser ((ExistsR " ++ rootNameS ++ " (Movement " ++ rootNameS ++ " Down a)))"+ , "downMovesParser = downMovesParser' (reify (undefined :: a))"+ ," where"+ ," downMovesParser' :: forall a . (Reify " ++ rootNameS ++ " a) => TypeRep " ++ rootNameS ++ " a -> "+ ," Parser ((ExistsR " ++ rootNameS ++ " (Movement " ++ rootNameS ++ " Down a)))"+ ," downMovesParser' (TW x) = case x of"+ ]++ printLns $ cases++ printLn ""++ printLns $ + [ " use options = choice $ map (uncurry mkParser) options"+ , " c :: forall a b . (Reify " ++ rootNameS ++ " b) => MovementI Down a b -> Parser (ExistsR " ++ rootNameS ++ " (Movement " ++ rootNameS ++ " Down a))"+ , " c = return . ExistsR . MW"+ , " mkParser p s = try (symbol s >> p)"+ ]++ printLn ""++ where+ rootNameS = nameBase rootName ++ cases = concatMap mkOptions acceptableNames++ mkOptions :: Name -> [String]+ mkOptions name + | null options = [ " (" ++ nameS ++ " :: TypeRepI a) -> use []"]+ | otherwise = [ " (" ++ nameS ++ " :: TypeRepI a) -> use options"+ , " where"+ , " options ="+ , " [ " ++ optionLines+ , " ]"+ ]+ where+ nameS = nameBase name ++ "T"++ options = filter ((== name) . ctxCtrTypeTo) ctxCtrs+ optionLines = concat . intersperse "\n , " . map mkOptionLine $ options++ mkOptionLine ctxCtr = "(c $ " ++ dcs ++ ", \"" ++ dcs ++ "\")"+ where+ dcs = downCtrName ctxCtr++printFooter :: PrintM ()+printFooter = printLns $+ [ "haskellParser :: P.TokenParser st"+ , "haskellParser = P.makeTokenParser P.haskellDef"+ , ""+ , "symbol :: String -> CharParser st String"+ , "symbol = P.symbol haskellParser"+ ]
+ Data/Cursor/CLASE/Gen/PrintM.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Data.Cursor.CLASE.Gen.PrintM where++import Control.Monad+import Control.Monad.Reader+import System.IO++newtype PrintM a = PrintM { runPrintM :: ReaderT Handle IO a }+ deriving Monad++runPrint :: Handle -> PrintM a -> IO a+runPrint h = flip runReaderT h . runPrintM++printLn :: String -> PrintM ()+printLn s = PrintM $ (ask >>= liftIO . flip hPutStrLn s)++printLns :: [String] -> PrintM ()+printLns s = PrintM $ (ask >>= liftIO . flip hPutStr (unlines s))
+ Data/Cursor/CLASE/Gen/Util.hs view
@@ -0,0 +1,241 @@+{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Gen.Util where++import Control.Monad+import Data.Map (Map)+import Data.Maybe+import Language.Haskell.TH+import qualified Data.Map as Map++data DataType = DataType {+ dtName :: Name,+ dtCtrs :: [Constructor]+ }+ | WrapsList {+ dtName :: Name,+ dtConName :: Name,+ dtChildName :: Name+ }++data Constructor = Ctr {+ ctrName :: Name,+ ctrKids :: [Child]+ }++data Child + = NonNavigable { childType :: Name }+ | Navigable { childType :: Name }++isWrapsList :: DataType -> Bool+isWrapsList (WrapsList _ _ _) = True+isWrapsList _ = False++constructors :: DataType -> [Constructor]+constructors d@(DataType {}) = dtCtrs d+constructors (WrapsList _ conName kidName) = [Ctr conName [Navigable kidName]]+++extractChildren :: DataType -> [Name]+extractChildren (DataType _ ctrs) = map ctrName ctrs+extractChildren (WrapsList _ cn _) = [cn]++isNavigable :: Child -> Bool+isNavigable (Navigable _) = True+isNavigable _ = False++buildMap :: [Name] -> Q (Map Name DataType)+buildMap okNames = do+ reifiedInfos <- mapM reify okNames+ let dts = map infoToDataType reifiedInfos + return . Map.fromList . zip okNames $ dts+ where+ infoToDataType :: Info -> DataType+ infoToDataType info+ | isSoloCtr &&+ onlyOneTypeInCtr &&+ (extractTypeNoList soloType) `elem` okNames &&+ isList soloType = WrapsList name soloCtrName soloNonListType+ | otherwise = DataType name (map mkCtr ctrs)+ where+ ctrs = extractConstructors info+ name = getInfoName info++ mkCtr :: Con -> Constructor+ mkCtr con = Ctr conName (map mkChild children)+ where+ children = extractChildTypesRaw $ con+ mkChild :: Type -> Child+ mkChild n+ | (extractTypeNoList n) `elem` okNames = Navigable (extractTypeNoList n)+ | otherwise = NonNavigable (extractType n)++ conName = getConName con++ isSoloCtr = length ctrs == 1+ headCtrsTypes = extractChildTypesRaw . head $ ctrs+ soloCtrName = getConName . head $ ctrs+ onlyOneTypeInCtr = length headCtrsTypes == 1+ soloType = head headCtrsTypes+ soloNonListType = extractTypeNoList soloType++data ContextCtr + = ListCC {+ ctxCtrName :: String,+ ctxCtrTypeFrom :: Name,+ ctxCtrTypeTo :: Name,+ ctxCtrCtrTo :: Name+ }+ | NormalCC {+ ctxCtrName :: String,+ ctxCtrOffset_ :: Maybe Int,+ ctxCtrTypesBefore :: [Name],+ ctxCtrTypesAfter :: [Name],+ ctxCtrTypeFrom :: Name,+ ctxCtrTypeTo :: Name,+ ctxCtrCtrTo :: Name+ }+ deriving (Eq, Show)++numCCArgs :: ContextCtr -> Int+numCCArgs cc+ | ctxCtrIsList cc = 2 + val+ | otherwise = val+ where + val = length (ctxCtrArgsBefore cc) + length (ctxCtrArgsAfter cc)+++downCtrName :: ContextCtr -> String+downCtrName cc = "M" ++ ctr ++ "To" ++ typ ++ moffset+ where+ ctr = nameBase . ctxCtrCtrTo $ cc+ typ = nameBase . ctxCtrTypeFrom $ cc+ moffset = maybe "" show . ctxCtrOffset $ cc++upCtrNameShown :: ContextCtr -> String+upCtrNameShown cc = mupctrshown+ where+ mupctrshown = "M" ++ typ ++ moffset ++ "To" ++ ctr++ ctr = nameBase . ctxCtrCtrTo $ cc+ typ = nameBase . ctxCtrTypeFrom $ cc+ moffset = maybe "" show . ctxCtrOffset $ cc++ctxCtrOffset :: ContextCtr -> Maybe Int+ctxCtrOffset (ListCC {}) = Nothing+ctxCtrOffset x = ctxCtrOffset_ x++ctxCtrIsList :: ContextCtr -> Bool+ctxCtrIsList (ListCC {}) = True+ctxCtrIsList _ = False++ctxCtrArgsBefore :: ContextCtr -> [String]+ctxCtrArgsBefore cc+ | ctxCtrIsList cc = []+ | otherwise = map nameBase . ctxCtrTypesBefore $ cc+ +ctxCtrArgsAfter :: ContextCtr -> [String]+ctxCtrArgsAfter cc+ | ctxCtrIsList cc = []+ | otherwise = map nameBase . ctxCtrTypesAfter $ cc++buildContextCtrs :: Map Name DataType -> [ContextCtr]+buildContextCtrs inMap = concatMap buildContextLines . Map.elems $ inMap+ where+ buildContextLines :: DataType -> [ContextCtr]+ buildContextLines (WrapsList dt cn ct) = [ListCC {+ ctxCtrName = (childName ++ "To" ++ conName),+ ctxCtrTypeFrom = ct,+ ctxCtrTypeTo = dt,+ ctxCtrCtrTo = cn+ }]+ where+ childName = nameBase ct+ conName = nameBase cn+ buildContextLines (DataType dtName cons) = concatMap mkNormalCCs cons+ where+ mkNormalCCs :: Constructor -> [ContextCtr]+ mkNormalCCs (Ctr cn kids) = catMaybes $ mapWithContext kids maybeMkNormalCC+ where+ conName = nameBase cn++ maybeMkNormalCC :: [Child] -> Child -> [Child] -> Maybe ContextCtr+ maybeMkNormalCC _ (NonNavigable _) _ = Nothing+ maybeMkNormalCC before (Navigable n) after = Just $ NormalCC {+ ctxCtrName = (childName ++ "To" ++ conName ++ count),+ ctxCtrOffset_ = mcount,+ ctxCtrTypesBefore = map childType before,+ ctxCtrTypesAfter = map childType after,+ ctxCtrTypeFrom = n,+ ctxCtrTypeTo = dtName,+ ctxCtrCtrTo = cn+ }+ where+ childName = nameBase n+ count = maybe "" show mcount+ mcount+ | null (sameSiblingsBefore ++ sameSiblingsAfter) = Nothing+ | otherwise = Just . length $ sameSiblingsBefore+ where+ sameSiblingsBefore = filter ( (==n) . childType ) before+ sameSiblingsAfter = filter ( (==n) . childType ) after++mapWithContext :: [a] -> ([a] -> a -> [a] -> b) -> [b]+mapWithContext xs f = mapWithContext' xs f []+ where+ mapWithContext' [] _ _ = []+ mapWithContext' (x:xs) f r = (f r x xs):(mapWithContext' xs f (r ++ [x]))++extractConstructors :: Info -> [Con]+extractConstructors (TyConI dec) = getConstructors dec+extractConstructors _ = []++getConstructors :: Dec -> [Con]+getConstructors (DataD _ _ _ cons _) = cons+getConstructors (NewtypeD _ _ _ con _) = [con]+getConstructors _ = []++getInfoName :: Info -> Name+getInfoName (TyConI (DataD _ n _ _ _)) = n+getInfoName (TyConI (NewtypeD _ n _ _ _)) = n+getInfoName x = error $ "Don't know how to get name for: " ++ show x++getConName :: Con -> Name+getConName (NormalC n _) = n+getConName (RecC n _) = n+getConName x = error $ "GetConName: " ++ show x++extractChildTypesRaw :: Con -> [Type]+extractChildTypesRaw con = case con of+ (RecC _ types) -> map thd $ types+ (NormalC _ types) -> map snd $ types+ _ -> []++extractTypeNoList :: Type -> Name+extractTypeNoList (ConT name) = name+extractTypeNoList (AppT (ConT lst) rhs)+ | lst == ''[] = (extractTypeNoList rhs)+extractTypeNoList x = error $ show x++isList :: Type -> Bool+isList (AppT (ConT lst) _) = lst == ''[]+isList _ = False++thd :: (a,b,c) -> c+thd (_,_,c) = c++extractType :: Type -> Name+extractType (ConT name) = name+extractType (AppT (ConT lst) rhs)+ | lst == ''[] = mkName $ "[" ++ nameBase (extractType rhs) ++ "]"+extractType x = error $ "Extract type; " ++ show x++extractChildTypes :: Con -> [Name]+extractChildTypes = catMaybes . map ect . extractChildTypesRaw + where+ ect :: Type -> Maybe Name+ ect (ConT name) = Just name+ ect (AppT (ConT lst) rhs)+ | lst == ''[] = ect rhs+ ect _ = Nothing+
+ Data/Cursor/CLASE/Language.hs view
@@ -0,0 +1,169 @@+{-# LANGUAGE TypeFamilies, EmptyDataDecls, GADTs, + ScopedTypeVariables,+ PatternSignatures,+ RankNTypes,+ MultiParamTypeClasses, NoMonomorphismRestriction #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Language where++import Data.Cursor.CLASE.Util+import Data.Maybe+import Control.Monad++{- Directions -}+data Up+data Down++type family Invert d :: *++type instance Invert Up = Down+type instance Invert Down = Up++data DirectionT a where+ UpT :: DirectionT Up+ DownT :: DirectionT Down+++{- Reify -} +class Reify l a where+ reify :: a -> TypeRep l a++data ExistsR l (r :: * -> *) where+ ExistsR :: (Reify l a) => r a -> ExistsR l r++{- Language -}+class Language l where+ data Context l :: * -> * -> *+ data Movement l :: * -> * -> * -> *+ data TypeRep l :: * -> *++ buildOne :: Context l a b -> a -> b++ unbuildOne :: Movement l Down a b -> a -> Maybe (Context l b a, b)++ invertMovement :: Movement l d a b -> Movement l (Invert d) b a+ + movementEq :: Movement l d a b -> Movement l d a c -> Maybe (TyEq b c)++ reifyDirection :: Movement l d a b -> DirectionT d++ contextToMovement :: Context l a b -> Movement l Up a b++ + downMoves :: TypeRep l a -> [ExistsR l (Movement l Down a)]+ moveLeft :: Movement l Down a x -> Maybe (ExistsR l (Movement l Down a))+ moveRight :: Movement l Down a x -> Maybe (ExistsR l (Movement l Down a))+++contextMovementEq :: (Language l) => Context l a b -> Movement l Up a c -> Maybe (TyEq b c)+contextMovementEq context mov = (contextToMovement context) `movementEq` mov++{- Paths -}+infixr 5 `Step`++data Path l r a b where+ Stop :: Path l r a a+ Step :: (Reify l b) => r a b -> Path l r b c -> Path l r a c++foldPath :: (forall from to . (Reify l to) => r from to -> from -> to) -> start -> Path l r start finish -> finish+foldPath _ val Stop = val+foldPath step val (Step ng np) = foldPath step (step ng val) np +++{- Cursor -}+data Cursor l x a = (Reify l a) => Cursor { + it :: a,+ ctx :: Path l (Context l) a l,+ log :: Route l a x+ }++data CursorWithMovement l d x from where+ CWM :: (Reify l to) => Cursor l x to -> Movement l d from to -> CursorWithMovement l d x from++rebuild :: (Language l) => Cursor l x a -> l+rebuild cursor = foldPath buildOne (it cursor) (ctx cursor) ++applyMovement :: (Language l, Reify l a, Reify l b) => + Movement l d a b -> Cursor l x a -> Maybe (Cursor l x b)+applyMovement mov (Cursor it ctx log) = case (reifyDirection mov) of+ UpT -> case ctx of+ (Step up ups) -> case (up `contextMovementEq` mov) of+ Just Eq -> Just $ Cursor (buildOne up it) ups (updateRoute mov log)+ Nothing -> Nothing+ Stop -> Nothing+ DownT -> fmap (\(ctx', it') -> Cursor it' (Step ctx' ctx) (updateRoute mov log)) + (unbuildOne mov it)++genericMoveUp :: (Language l) => Cursor l x a -> Maybe (CursorWithMovement l Up x a) +genericMoveUp (Cursor it (Step up ups) log) = Just $ CWM (Cursor (buildOne up it) ups (updateRoute upMov log)) upMov+ where+ upMov = contextToMovement up+genericMoveUp (Cursor _ Stop _) = Nothing++genericMoveDown :: (Language l) => Cursor l x a -> Maybe (CursorWithMovement l Down x a)+genericMoveDown cursor@Cursor {} = msum . map (\(ExistsR c) -> fmap (flip CWM c) . flip applyMovement cursor $ c) . downMoves . reify . it $ cursor++genericMoveLeft :: (Language l) => Cursor l x a -> Maybe (ExistsR l (Cursor l x)) +genericMoveLeft = genericMoveSideways moveLeft ++genericMoveRight :: (Language l) => Cursor l x a -> Maybe (ExistsR l (Cursor l x)) +genericMoveRight = genericMoveSideways moveRight++genericMoveSideways :: forall l x a . (Language l) => + (forall a z . Movement l Down a z -> Maybe (ExistsR l (Movement l Down a))) -> Cursor l x a -> Maybe (ExistsR l (Cursor l x)) +genericMoveSideways fn cursor = do+ (CWM cursor' upmov ) <- genericMoveUp cursor+ let downmov = invertMovement upmov+ (ExistsR newDownMov) <- fn downmov+ cursor'' <- applyMovement newDownMov cursor'+ return $ ExistsR cursor''++moveToRoot :: (Language l) => Cursor l x a -> Cursor l x l+moveToRoot cursor@(Cursor _ Stop _) = cursor+moveToRoot (Cursor it (Step up ups) log) = moveToRoot (Cursor (buildOne up it) ups (updateRoute (contextToMovement up) log))++{- Routes -}+data Route l from to where+ Route :: (Reify l mid) => Path l (Movement l Up) from mid ->+ Path l (Movement l Down) mid to -> Route l from to +++route_invariant :: forall l from to . (Language l) => Route l from to -> Bool+route_invariant (Route (Step mup Stop) + (Step mdown _)) = not . isJust $ res+ where+ mup' = invertMovement mup+ res = (mup' `movementEq` mdown)+route_invariant (Route (Step _ ups) downs) = route_invariant (Route ups downs)+route_invariant (Route Stop _) = True++updateRoute :: (Language l, + Reify l a, + Reify l b) => Movement l d a b -> Route l a c -> Route l b c+updateRoute mov route = case (reifyDirection mov) of+ UpT -> case route of+ Route (Step up ups) downs -> case (mov `movementEq` up) of+ Just Eq -> Route ups downs+ Nothing -> error $ "Precondition violation: route up =/= movement up!"+ Route Stop steps -> Route Stop (Step (invertMovement mov) steps)+ DownT -> case route of+ Route Stop sdowns@(Step down downs) -> case (mov `movementEq` down) of+ Just Eq -> Route Stop downs+ Nothing -> Route (Step (invertMovement mov) Stop) sdowns+ Route ups downs -> Route (Step (invertMovement mov) ups) downs++resetLog :: Cursor l x a -> Cursor l a a+resetLog (Cursor it ctx _) = (Cursor it ctx (Route Stop Stop))++appendRoute :: (Language l, Reify l a, Reify l b, Reify l c) => + Route l a b -> Route l b c -> Route l a c+appendRoute (Route Stop Stop) x = x+appendRoute (Route (Step up rst) y) r2 = updateRoute (invertMovement up)+ (appendRoute (Route rst y) r2)+appendRoute (Route Stop (Step dwn rst)) r2 = updateRoute (invertMovement dwn) + (appendRoute (Route Stop rst) r2)++followRoute :: (Language l) => Cursor l x a -> Route l a c -> Maybe (Cursor l x c)+followRoute cursor (Route Stop Stop) = Just $ cursor+followRoute cursor@Cursor{} route@(Route (Step mup _) _) = (applyMovement mup cursor) >>= (\cursor' -> followRoute cursor' (updateRoute mup route))+followRoute cursor@Cursor{} route@(Route Stop (Step mdown _)) = (applyMovement mdown cursor) >>= (\cursor' -> followRoute cursor' (updateRoute mdown route))
+ Data/Cursor/CLASE/Persistence.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE PatternSignatures #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE GADTs #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Persistence(+ showCursor,+ showRoute,+ parseCursor,+ parseRoute,+ Persistable(..),+ PersistenceAdapter(..),+ RestoredCursor(..),+ RestoredRoute(..),+ RestoredPath(..),+ readParser+) where++import Data.Cursor.CLASE.Language+import qualified Text.ParserCombinators.Parsec.Language as P+import qualified Text.ParserCombinators.Parsec.Token as P+import Text.ParserCombinators.Parsec+import Data.Cursor.CLASE.Util+import Control.Monad+import Control.Arrow++class (Language l, + PersistenceAdapter l, + Reify l l) => Persistable l where+ + showMovement :: (Movement l d from to) -> String++ movementParser :: Reify l a => DirectionT d -> Parser ((ExistsR l (Movement l d a)))++ showTypeRep :: TypeRep l a -> String++ typeRepParser :: Parser (Exists (TypeRep l))++ typeRepEq :: TypeRep l a -> TypeRep l b -> Maybe (TyEq a b)+++class PersistenceAdapter l where+ showL :: l -> String+ parseL :: Parser l++data RestoredCursor l where+ RestoredCursor :: (Reify l x) => Cursor l x a -> RestoredCursor l++data RestoredRoute l from where+ RestoredRoute :: (Reify l to) => Route l from to -> RestoredRoute l from++data RestoredPath l r a where+ RestoredPath :: (Reify l b) => Path l r a b -> RestoredPath l r a++readParser :: (Show a, Read a) => Bool -> Parser a+readParser b+ | b = readParserP 11+ | otherwise = readParserP 0++readParserP :: (Show a, Read a) => Int -> Parser a +readParserP n = do+ cString <- getInput+ case readsPrec n cString of+ [(val, rest)] -> do+ setInput rest+ return val+ x -> error $ "readParser fail: " ++ show x ++ " - " ++ show cString++showCursor :: forall l x a . (Persistable l) => Cursor l x a -> String+showCursor cursor@(Cursor it _ log) = "Cursor { root = " ++ lS ++ ", " +++ "locationRep = " ++ itRepS ++ ", " ++ + "location = " ++ locS ++ ", " +++ "log = " ++ logS ++ + "}"+ where+ (Cursor root _ location) = moveToRoot $ resetLog cursor+ lS = showL root+ itRepS = showTypeRep ((reify it) :: TypeRep l a)+ locS = showRoute location+ logS = showRoute log+++showPath :: (Persistable l) => (forall a b . r a b -> Bool -> String) -> + Path l r from to -> Bool -> String+showPath _ Stop _ = "Stop"+showPath contents (Step c nxt) b+ | b = "(" ++ line ++ ")"+ | otherwise = line+ where+ line = "Step " ++ (contents c True) ++ " " ++ showPath contents nxt True ++showRoute :: (Persistable l) => Route l from to -> String+showRoute (Route mups mdowns) = "Route " ++ + showPath (const . showMovement) mups True ++ " " +++ showPath (const . showMovement) mdowns True++parseCursor :: (Persistable l) => String -> Maybe (RestoredCursor l)+parseCursor = ((error . show) ||| Just) . parse cursorParser "" +-- TODO: error . show == Nothing++parseRoute :: (Persistable l, + Reify l from) => Bool -> String -> Maybe (RestoredRoute l from)+parseRoute b = ((error . show) ||| Just) . parse (routeParser b) ""+-- TODO: error . show == Nothing++cursorParser :: forall l . (Persistable l) => Parser (RestoredCursor l)+cursorParser = do+ symbol "Cursor"+ braces $ do+ symbol "root" >> symbol "="+ (root :: l) <- parseL+ comma+ + symbol "locationRep" >> symbol "="+ (Exists (itRep :: TypeRep l from)) <- (typeRepParser :: Parser (Exists (TypeRep l)))+ comma++ symbol "location" >> symbol "="+ (RestoredRoute (loc :: Route l l from')) <- (routeParser False :: Parser (RestoredRoute l l))+ (locFrom :: TypeRep l from') <- return (reify (undefined :: from'))+ (Just (Eq :: TyEq from from')) <- return (itRep `typeRepEq` locFrom)++ comma++ symbol "log" >> symbol "="+ (RestoredRoute (log :: Route l from x)) <- (routeParser False :: Parser (RestoredRoute l from))++ maybe (fail "Couldn't build cursor") (return . RestoredCursor) $ process root loc log+ where+ process :: l -> Route l l from -> Route l from x -> Maybe (Cursor l x from)+ process l loc log = do+ let cursorAtRoot = Cursor l Stop (Route Stop Stop)+ (Cursor endPos ctx _) <- followRoute cursorAtRoot loc+ return $ Cursor endPos ctx log++pathParser :: forall a r l . (Reify l a) => Bool -> (forall b . (Reify l b) => Parser ((ExistsR l (r b)))) -> Parser (RestoredPath l r a)+pathParser b cargoParser = (try stopParser) <|> (if' b parens id stepParser)+ where+ stopParser = symbol "Stop" >> return (RestoredPath Stop)+ stepParser = do+ symbol "Step"+ (ExistsR part) <- cargoParser+ (RestoredPath rest) <- pathParser True cargoParser + return $ RestoredPath (Step part rest)++routeParser :: forall l a . (Persistable l, Reify l a) => Bool -> Parser (RestoredRoute l a)+routeParser b = (if' b parens id) $ do+ symbol "Route"+ (RestoredPath upMovs) <- pathParser True (movementParser UpT)+ (RestoredPath downMovs) <- pathParser True (movementParser DownT)++ let route = Route upMovs downMovs++ guard (route_invariant route)++ return $ RestoredRoute route+++haskellParser :: P.TokenParser st+haskellParser = P.makeTokenParser P.haskellDef++symbol :: String -> CharParser st String+symbol = P.symbol haskellParser+parens :: CharParser st a -> CharParser st a+parens = P.parens haskellParser+braces :: CharParser st a -> CharParser st a+braces = P.braces haskellParser+comma :: CharParser st String+comma = P.comma haskellParser
+ Data/Cursor/CLASE/Traversal.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE RankNTypes, MultiParamTypeClasses, TypeFamilies, GADTs, RelaxedPolyRec, PatternSignatures, ScopedTypeVariables #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Traversal(+ Traversal(..),+ completeTraversal+) where++import Data.Cursor.CLASE.Bound+import Data.Cursor.CLASE.Language++class (Bound l t) => Traversal l t where++ visitStep :: (Reify l a) => a -> (forall b . Reify l b => Movement l Down a b -> t) -> t++ visitPartial :: Context l a b -> b -> t -> (forall c . Reify l c => Movement l Down b c -> t) -> t++ cursor :: l -> t -> t+++completeTraversal :: forall l t x a . (Traversal l t) => Cursor l x a -> t+completeTraversal (Cursor it ctx _) = foldUp (cursor (undefined :: l) (visitStep it hook')) it ctx+ where+ hook' :: forall b . Reify l b => Movement l Down a b -> t+ hook' = hook it++hook :: forall l t a b . (Traversal l t, Reify l b) => a -> Movement l Down a b -> t+hook here movement = case unbuildOne movement here of+ Just (ctx, b) -> let hook' :: forall c . Reify l c => Movement l Down b c -> t+ hook' = hook b+ in bindingHook ctx (visitStep b hook')+ Nothing -> error "Bad movement in traversal!"+++foldUp :: (Traversal l t) => t -> a -> Path l (Context l) a b -> t+foldUp t _ Stop = t+foldUp t here (Step ctx nxt) = foldUp (bindingHook ctx (visitPartial ctx next t (hook next))) next nxt+ where+ next = buildOne ctx here
+ Data/Cursor/CLASE/Util.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE GADTs #-}+{-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-}+module Data.Cursor.CLASE.Util where+++data Exists a where+ Exists :: a b -> Exists a++data TyEq a b where+ Eq :: TyEq a a++data Id a where+ Id :: a -> Id a++if' :: Bool -> a -> a -> a+if' b x y+ | b = x+ | otherwise = y
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) Tristan Allwood++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain