packages feed

adblock2privoxy-1.0.0: src/ParserExtTests.hs

module ParserExtTests (
parseMorse,
encodeMorse
) where
import Utils
import ParsecExt
import Control.Applicative hiding (many)
import Text.ParserCombinators.Parsec hiding ((<|>),State)
import Control.Monad
import Data.List
import Data.Maybe
import Control.Monad.State

---------------------------------------------------------------------------------------------
------------------------- parsec ext usage samples ------------------------------------------
---------------------------------------------------------------------------------------------

type ExampleCase = ([String], String, String)

parsersChain :: [StringStateParser ExampleCase]
parsersChain = square3 prefix mid suffix
        where -- all parsers except for last one should consume some input and give some output
            prefix = manyCases ((:[]) <$> (string "ab" <|> string "zz"))
            mid =    many1Cases $ (:[]) <$> letter            -- list of letters
            suffix = many1Cases $ try $ many1 alphaNum  
            

testParsecExt :: Either ParseError [([String], String, String)]
testParsecExt =  parse (cases parsersChain <* string "$$") "x" "abebz12$$"

testParseMorse :: Either ParseError [String]
testParseMorse = parseMorse "......-...-..---"

--------------------------------------------------------------------------------
--- Morse chars parsing: parse "......-...-..---" in all possible ways ---------
--------------------------------------------------------------------------------

morseChars :: [(String, Char)]
morseChars = [  (".-", 'A'), 
                ("-...", 'B'),
                ("-.-.", 'C'), 
                ("-..", 'D'),
                (".", 'E'),   
                ("..-.", 'F'),
                ("--.", 'G'), 
                ("....", 'H'),
                ("..", 'I'),  
                (".---", 'J'),
                ("-.-", 'K'), 
                (".-..", 'L'),
                ("--", 'M'),  
                ("-.", 'N'),
                ("---", 'O'), 
                (".--.", 'P'),
                ("--.-", 'Q'),    
                (".-.", 'R'),
                ("...", 'S'), 
                ("-", 'T'),
                ("..-", 'U'), 
                ("...-", 'V'),
                (".--", 'W'), 
                ("-..-", 'X'),
                ("-.--", 'Y'),    
                ("--..", 'Z'),
                ("-----", '0'),   
                (".----", '1'),
                ("..---", '2'),   
                ("...--", '3'),
                ("....-", '4'),   
                (".....", '5'),
                ("-....", '6'),   
                ("--...", '7'),
                ("---..", '8'),   
                ("----.", '9')]

morseCharCodes :: [String]
morseCharCodes = fst <$> morseChars

-- HELLO = "......-...-..---"
encodeMorse :: String -> String
encodeMorse s = join $ fst <$> catMaybes (code <$> s)
        where code c = find (\pair -> snd pair == c) morseChars
        
decodeMorse :: [String] -> String
decodeMorse ss = snd <$> catMaybes (code <$> ss)
        where code s = find (\pair -> fst pair == s) morseChars 


-- find possibilites to continue from a given prefix
findMorseSteps :: String -> [String] -> [String]
findMorseSteps prefix codes = case find (== prefix) codes of
                            Nothing -> case filter (isPrefixOf prefix) codes of 
                                            [] -> []
                                            filtered ->    findMorseSteps (prefix ++ ".") filtered
                                                        ++ findMorseSteps (prefix ++ "-") filtered
                            Just match -> [match]

morseStepParser :: [String] -> Parser String
morseStepParser [] = pzero
morseStepParser [step] = string step
morseStepParser (step:steps') = string step <|> morseStepParser steps'

morseParser :: Int -> StringStateParser (ZipListM String)
morseParser pos = do     acc' <- get
                         let acc = case acc' of
                                      Nothing -> ""
                                      Just val -> val
                             candidates = filter (\x -> isPrefixOf acc x && acc /= x) morseCharCodes
                             steps = drop (length acc) <$> findMorseSteps acc candidates
                             parser = morseStepParser steps    
                         res <- lift parser
                         put (Just $ acc ++ res)
                         return (zipListM $ (replicate pos "") ++ (res : repeat ""))
                  

morseParsers :: [StringStateParser (ZipListM String)]
morseParsers = repeat morseParser <*> [0 ..]

parseMorse :: String -> Either ParseError [String]
parseMorse s = (fmap.fmap) postProcess $ parseMorseRaw "x" s
            where 
            parseMorseRaw =  parse (cases $ morseParsers) 
            postProcess = decodeMorse.toLists 
            toLists = (takeWhile $ not.null) . getZipListM