anticiv-0.1.0.5: Network/Anticiv/Config.hs
module Network.Anticiv.Config where
import Control.Monad
import Data.Chatty.Atoms
import Data.Chatty.TST
import Data.List
import Text.Chatty.Parser
import Text.Chatty.Parser.Carrier
import Text.Chatty.Scanner
import Text.CTPL
data ValueRef = StrVal (Atom String) | IntVal (Atom Int) | StrList (Atom [String]) | Ctpl0 (Atom String) deriving Eq
data ValueTemp = StrValT String | IntValT Int | StrListT [String] | CtplT String | Ctpl0T String deriving (Eq,Show)
data Key = RefLeaf ValueRef | TempLeaf ValueTemp | Group Config | Module Config | Vocab Config
type Config = TST Key
instance Show ValueRef
parseConf :: ChParser m => m Config
parseConf = do
keys <- many parseKey
return $ foldr (uncurry tstInsert) EmptyTST keys
oneOf :: ChParser m => [Char] -> m Char
oneOf ks = do
k <- request
if k `elem` ks then return k else pabort
ident :: ChParser m => m String
ident = some $ oneOf (['A'..'Z']++['a'..'z']++"-")
parseKey :: ChParser m => m (String, Key)
parseKey = do
let grabl = do
k <- request
if k=='\n' then pabort else return k
comment = do
many white
matchs "#"
many grabl
match '\n'
many comment
parseLeaf ??? parseGroup ??? parseModule ??? parseVocab
parseLeaf :: ChParser m => m (String, Key)
parseLeaf = do
many white
nm <- ident
many white
match '='
let parseInt = do
many white
ds <- some digit
return $ IntValT $ foldl1 (\l r -> l*10+r) ds
grabq = (do
k <- request
case k of
'"' -> pabort
'\\' -> do
k <- request
ks <- grabq
return (k:ks)
_ -> do
ks <- grabq
return (k:ks)) ?? return []
parseStr = do
many white
match '"'
ks <- grabq
match '"'
return $ StrValT ks
parseStrList = do
many white
match '('
many white
strs <- many parseStr
many white
match ')'
return $ StrListT $ map (\(StrValT s) -> s) strs
parseCtpl = do
many white
matchs "CTPL"
many white
match '"'
cs <- grabq
match '"'
return $ CtplT cs
parseCtpl0 = do
many white
matchs "CTPL0"
many white
match '"'
cs <- grabq
match '"'
return $ Ctpl0T cs
v <- parseInt ?? parseStr ?? parseStrList ??? parseCtpl ??? parseCtpl0
many white
match ';'
return (nm,TempLeaf v)
parseGroup :: ChParser m => m (String, Key)
parseGroup = do
many white
matchs "Group"
many white
nm <- ident
many white
match '{'
sub <- parseConf
many white
match '}'
return (nm,Group sub)
parseModule :: ChParser m => m (String, Key)
parseModule = do
many white
matchs "Module"
many white
nm <- ident
many white
match '{'
sub <- parseConf
many white
match '}'
return (nm,Module sub)
parseVocab :: ChParser m => m (String, Key)
parseVocab = do
many white
matchs "Vocab"
many white
nm <- ident
many white
match '{'
sub <- parseConf
many white
match '}'
return (nm,Vocab sub)
readConf :: (ChScanner m,ChAtoms m) => m (Maybe Config)
readConf = do
inp <- mscanL
case runCarrierT inp parseConf of
[] -> return Nothing
(c:_) -> tmap atomify c >>= return . Just
instance Functor TST where
fmap f EmptyTST = EmptyTST
fmap f (TST c Nothing l m r) = TST c Nothing (fmap f l) (fmap f m) (fmap f r)
fmap f (TST c (Just h) l m r) = TST c (Just $ f h) (fmap f l) (fmap f m) (fmap f r)
tmap :: Monad m => (a -> m b) -> TST a -> m (TST b)
tmap _ EmptyTST = return EmptyTST
tmap f (TST c Nothing l m r) = do
l' <- tmap f l
m' <- tmap f m
r' <- tmap f r
return $ TST c Nothing l' m' r'
tmap f (TST c (Just h) l m r) = do
l' <- tmap f l
m' <- tmap f m
r' <- tmap f r
h' <- f h
return $ TST c (Just h') l' m' r'
atomify :: ChAtoms m => Key -> m Key
atomify (RefLeaf r) = return $ RefLeaf r
atomify (Group c) = tmap atomify c >>= return . Group
atomify (Module c) = tmap atomify c >>= return . Module
atomify (Vocab c) = return $ Vocab c
atomify (TempLeaf (IntValT i)) = do
a <- newAtom
putAtom a i
return $ RefLeaf $ IntVal a
atomify (TempLeaf (StrValT s)) = do
a <- newAtom
putAtom a s
return $ RefLeaf $ StrVal a
atomify (TempLeaf (StrListT l)) = do
a <- newAtom
putAtom a l
return $ RefLeaf $ StrList a
atomify (TempLeaf (CtplT s)) = do
a <- newAtom
case compileCTPL s of
Succ s' -> putAtom a s'
SyntaxFault -> error "Error compiling CTPL script: Syntax fault."
NoSuchProc s -> error ("Error compiling CTPL script: No such proc: "++s)
return $ RefLeaf $ Ctpl0 a
atomify (TempLeaf (Ctpl0T s)) = do
a <- newAtom
putAtom a s
return $ RefLeaf $ Ctpl0 a
getKey :: String -> Config -> Maybe Key
getKey s cx = case p of
[] -> Nothing
(c:_) -> Just c
where p = runCarrierT s $ do
let leaf c = do
nm <- ident
case tstLookup nm c of
Just k@RefLeaf{} -> return k
Just k@TempLeaf{} -> return k
_ -> pabort
modu c = do
match '%'
nm <- ident
match '/'
case tstLookup nm c of
Just (Module k) -> kget k
_ -> pabort
group c = do
nm <- ident
match '/'
case tstLookup nm c of
Just (Group k) -> kget k
_ -> pabort
vocab c = do
nm <- ident
match ':'
case tstLookup nm c of
Just (Vocab k) -> kget k
_ -> pabort
kget c = leaf c ??? modu c ??? group c ??? vocab c
kget cx
mgetKey :: String -> String -> Config -> Maybe Key
mgetKey m s c =
case getKey ("%"++m++"/"++s) c of
Just k -> Just k
Nothing -> getKey s c
getFirstKey :: [String] -> Config -> Maybe Key
getFirstKey [] _ = Nothing
getFirstKey (k:ks) c
| Just x <- getKey k c = Just x
| otherwise = getFirstKey ks c
mgetFirstKey :: String -> [String] -> Config -> Maybe Key
mgetFirstKey m ks c = flip getFirstKey c $ do
k <- ks
["%"++m++"/"++k, k]