encoding/Data/Encoding/Helper/Template.hs
Henning Guenther eeee054f1e Rewrite to support more sources and changing the encoding dynamically
Now it's possible to change the character encoding while de-/encoding.
Also, it's possible to use any data structure as a source or target of the de-/encoding process.

darcs-hash:20090221203100-a4fee-6da31f2e37c30a3f5cd5f10af71984209488bb0b
2009-02-21 12:31:00 -08:00

75 lines
2.9 KiB
Haskell

{-# LANGUAGE TemplateHaskell #-}
module Data.Encoding.Helper.Template where
import Data.Encoding.Base
import Data.Char
import Data.Maybe (mapMaybe)
import Data.Map as Map (fromList,lookup)
import Data.Array
import Language.Haskell.TH
makeISOInstance :: String -> FilePath -> Q [Dec]
makeISOInstance name file = do
let rname = mkName name
trans <- runIO (readTranslation file)
mp <- encodingMap (validTranslations trans)
arr <- decodingArray (fillTranslations trans)
return [ DataD [] rname [] [NormalC rname []] [''Show]
, InstanceD [] (AppT (ConT ''Encoding) (ConT rname))
[FunD 'encodeChar
[Clause [WildP] (NormalB $ AppE (VarE 'encodeWithMap) (VarE $ mkName "mp"))
[ValD (VarP $ mkName "mp") (NormalB mp) []]
]
,FunD 'decodeChar
[Clause [WildP] (NormalB $ AppE (VarE 'decodeWithArray) (VarE $ mkName "arr"))
[ValD (VarP $ mkName "arr") (NormalB arr) []]
]
]
]
createCharArray :: [(Integer,Maybe Char)] -> Integer -> Integer -> Q Exp
createCharArray lst = createArray (map (\(x,y) -> (x,case y of
Nothing -> ConE 'Nothing
Just c -> AppE (ConE 'Just) (LitE $ CharL c))
) lst)
createArray :: [(Integer,Exp)] -> Integer -> Integer -> Q Exp
createArray lst from to = return $ AppE
(AppE
(VarE 'array)
(TupE [LitE $ IntegerL from,LitE $ IntegerL to]))
(ListE [ TupE [LitE $ IntegerL x,y]
| (x,y) <- lst ])
decodingArray :: [(Integer,Maybe Char)] -> Q Exp
decodingArray trans = createCharArray trans 0 255
encodingMap :: [(Integer,Char)] -> Q Exp
encodingMap trans = return $ AppE
(VarE 'fromList)
(ListE [ TupE [LitE $ CharL to,LitE $ IntegerL from]
| (from,to) <- trans])
readTranslation :: FilePath -> IO [(Integer,Maybe Char)]
readTranslation file = do
cont <- readFile file
return $ mapMaybe (\ln -> case ln of
[] -> Nothing
('#':xs) -> Nothing
_ -> case words ln of
(src:"#UNDEFINED":_) -> Just (read src,Nothing) -- XXX: Find a better way to handle this
(src:trg:_) -> Just (read src,Just $ chr $ read trg)
_ -> Nothing
) (lines cont)
fillTranslations :: [(Integer,Maybe Char)] -> [(Integer,Maybe Char)]
fillTranslations = fillTranslations' (-1)
where
fillTranslations' n ((n',c):cs) = (map (\i -> (i,Nothing)) [n+1..n'-1])++((n',c):fillTranslations' n' cs)
fillTranslations' n [] = map (\i -> (i,Nothing)) [n+1..255]
validTranslations :: [(Integer,Maybe Char)] -> [(Integer,Char)]
validTranslations = mapMaybe (\(n,mc) -> case mc of
Nothing -> Nothing
Just c -> Just (n,c))