Ignore-this: dbcc883c561f2f074dd4739387dd3f43 darcs-hash:20090306150105-a4fee-b4d441cd38c758c803732e0c74a86a53d8db9c28
120 lines
4.9 KiB
Haskell
120 lines
4.9 KiB
Haskell
{-# LANGUAGE TemplateHaskell #-}
|
|
module Data.Encoding.Helper.Template where
|
|
|
|
import Data.Encoding.Base
|
|
import Data.Bits
|
|
import Data.Char
|
|
import Data.Maybe (mapMaybe)
|
|
import Data.Map as Map (fromList,lookup)
|
|
import Data.Array.Unboxed
|
|
import Data.Typeable
|
|
import Language.Haskell.TH
|
|
|
|
makeISOInstance :: String -> FilePath -> Q [Dec]
|
|
makeISOInstance name file = do
|
|
trans <- runIO (readTranslation 0 id file)
|
|
mp <- encodingMap (validTranslations trans)
|
|
arr <- decodingArray (fillTranslations 0 255 trans)
|
|
return $ encodingInstance 'encodeWithMap 'decodeWithArray 'encodeableWithMap name mp arr
|
|
|
|
makeJISInstance :: Int -> String -> FilePath -> Q [Dec]
|
|
makeJISInstance offset name file = do
|
|
trans <- runIO (readTranslation offset (\src -> (src `shiftR` 8,src .&. 0xFF)) file)
|
|
mp <- encodingMap2 (validTranslations trans)
|
|
arr <- decodingArray2 (fillTranslations (0x21,0x21) (0x7E,0x7E) trans)
|
|
return $ encodingInstance 'encodeWithMap2 'decodeWithArray2 'encodeableWithMap name mp arr
|
|
|
|
encodingInstance :: Name -> Name -> Name -> String -> Exp -> Exp -> [Dec]
|
|
encodingInstance enc dec able name mp arr
|
|
= [ DataD [] rname [] [NormalC rname []] [''Show,''Eq,''Typeable]
|
|
, ValD (VarP rmp) (NormalB mp) []
|
|
, InstanceD [] (AppT (ConT ''Encoding) (ConT rname))
|
|
[FunD 'encodeChar
|
|
[Clause [WildP] (NormalB $ AppE (VarE enc) (VarE rmp))
|
|
[]
|
|
]
|
|
,FunD 'decodeChar
|
|
[Clause [WildP] (NormalB $ AppE (VarE dec) (VarE rarr))
|
|
[ValD (VarP rarr) (NormalB arr) []]
|
|
]
|
|
,FunD 'encodeable
|
|
[Clause [WildP] (NormalB $ AppE (VarE able) (VarE rmp))
|
|
[]
|
|
]
|
|
]
|
|
]
|
|
where
|
|
rname = mkName name
|
|
rarr = mkName "arr"
|
|
rmp = mkName ("decoding_map_"++name)
|
|
|
|
createCharArray :: [(Integer,Maybe Char)] -> Integer -> Integer -> Q Exp
|
|
createCharArray lst f t = createArray (map (\(x,y) ->
|
|
(LitE $ IntegerL x,mbCharToExp y)
|
|
) lst) (LitE $ IntegerL f) (LitE $ IntegerL t)
|
|
|
|
createCharArray2 :: [((Integer,Integer),Maybe Char)] -> (Integer,Integer) -> (Integer,Integer) -> Q Exp
|
|
createCharArray2 lst (f1,f2) (t1,t2)
|
|
= createArray (map (\((x1,x2),y) ->
|
|
(TupE [integerExp x1,integerExp x2],mbCharToExp y)
|
|
) lst)
|
|
(TupE [integerExp f1,integerExp f2])
|
|
(TupE [integerExp t1,integerExp t2])
|
|
|
|
integerExp :: Integer -> Exp
|
|
integerExp i = LitE $ IntegerL i
|
|
|
|
mbCharToExp :: Maybe Char -> Exp
|
|
mbCharToExp Nothing = LitE (IntegerL (-1))
|
|
mbCharToExp (Just c) = LitE (IntegerL $ fromIntegral $ ord c)
|
|
|
|
createArray :: [(Exp,Exp)] -> Exp -> Exp -> Q Exp
|
|
createArray lst from to
|
|
= return $ AppE
|
|
(AppE
|
|
(VarE 'array)
|
|
(TupE [from,to]))
|
|
(ListE [TupE [x,y] | (x,y) <- lst])
|
|
|
|
decodingArray :: [(Integer,Maybe Char)] -> Q Exp
|
|
decodingArray trans = createCharArray trans 0 255
|
|
|
|
decodingArray2 :: [((Integer,Integer),Maybe Char)] -> Q Exp
|
|
decodingArray2 trans = createCharArray2 trans (0x21,0x21) (0x7E,0x7E)
|
|
|
|
encodingMap :: [(Integer,Char)] -> Q Exp
|
|
encodingMap trans = return $ AppE
|
|
(VarE 'fromList)
|
|
(ListE [ TupE [LitE $ CharL to,LitE $ IntegerL from]
|
|
| (from,to) <- trans])
|
|
|
|
encodingMap2 :: [((Integer,Integer),Char)] -> Q Exp
|
|
encodingMap2 trans = return $ AppE
|
|
(VarE 'fromList)
|
|
(ListE [ TupE [LitE $ CharL to,TupE [integerExp f1,integerExp f2]]
|
|
| ((f1,f2),to) <- trans])
|
|
|
|
readTranslation :: Int -> (Integer -> a) -> FilePath -> IO [(a,Maybe Char)]
|
|
readTranslation offset f file = do
|
|
cont <- readFile file
|
|
return $ mapMaybe (\ln -> case drop offset ln of
|
|
[src] -> Just (f src,Nothing)
|
|
[src,trg] -> Just (f src,Just $ chr $ fromIntegral trg)
|
|
_ -> Nothing) (parseTranslationTable cont)
|
|
|
|
parseTranslationTable :: String -> [[Integer]]
|
|
parseTranslationTable cont = filter (not.null) (map (\ln -> map read (takeWhile ((/='#').head) (words ln))) (lines cont))
|
|
|
|
fillTranslations :: (Ix a,Show a) => a -> a -> [(a,Maybe Char)] -> [(a,Maybe Char)]
|
|
fillTranslations f t = merge (range (f,t))
|
|
where
|
|
merge xs [] = map (\x -> (x,Nothing)) xs
|
|
merge [] cs = error $ "Data.Encoding.Helper.Template.fillTranslations: Character translations out of range: " ++ show cs
|
|
merge (x:xs) (y:ys) = if x < fst y
|
|
then (x,Nothing):(merge xs (y:ys))
|
|
else y:(merge xs ys)
|
|
|
|
validTranslations :: [(a,Maybe Char)] -> [(a,Char)]
|
|
validTranslations = mapMaybe (\(n,mc) -> case mc of
|
|
Nothing -> Nothing
|
|
Just c -> Just (n,c)) |