module Passman.Core.Mode
(
Mode
, modeS
, modeN
, modeC
, modeL
, validModes
, defaultMode
, (<+>)
, combineModes
, (<->)
, splitMode
, readModeMay
, readModeDef
, modeToConstraint
) where
import Control.Monad (mfilter)
import Data.Bits ((.|.), testBit, clearBit, setBit)
import Data.List (sort, (\\))
import Data.Maybe (fromMaybe)
import Text.Read
import qualified Text.Read.Lex as L
newtype Mode = Mode Int
deriving Eq
instance Show Mode where
show = map helper . splitMode
where
helper x
| x == modeS = 's'
| x == modeN = 'n'
| x == modeC = 'c'
| x == modeL = 'l'
| otherwise = error "show: Invalid sigleton mode"
instance Read Mode where
readPrec =
parens
( do L.Ident s <- lexP
case filter ((==) s . snd) modeStrings of
[(m,_)] -> return m
_ -> pfail
)
where
modeStrings = map (\m -> (m, show m)) validModes
readListPrec = readListPrecDefault
readList = readListDefault
lower, upper, numbers, symbols :: String
lower = ['a'..'z']
upper = ['A'..'Z']
numbers = ['0'..'9']
symbols = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
modeS, modeN, modeC, modeL :: Mode
modeS = Mode $ setBit 0 0
modeN = Mode $ setBit 0 1
modeC = Mode $ setBit 0 2
modeL = Mode $ setBit 0 3
defaultMode :: Mode
defaultMode = modeN <+> modeC <+> modeL
(<+>) :: Mode -> Mode -> Mode
Mode x <+> Mode y = Mode (x .|. y)
(<->) :: Mode -> Mode -> Maybe Mode
x <-> y = combineModes $ x' \\ y'
where
x' = splitMode x
y' = splitMode y
validModes :: [Mode]
validModes = map Mode [1..15]
splitMode :: Mode -> [Mode]
splitMode (Mode x)
| x == 0 = []
| testBit x 0 = modeS : splitMode (Mode $ clearBit x 0)
| testBit x 1 = modeN : splitMode (Mode $ clearBit x 1)
| testBit x 2 = modeC : splitMode (Mode $ clearBit x 2)
| testBit x 3 = modeL : splitMode (Mode $ clearBit x 3)
| otherwise = error "splitMode"
combineModes :: [Mode] -> Maybe Mode
combineModes = mfilter (Mode 0 /=) . return . foldr (<+>) (Mode 0)
readModeMay :: String -> Maybe Mode
readModeMay = combineModes . map helper
where
helper :: Char -> Mode
helper 's' = modeS
helper 'n' = modeN
helper 'c' = modeC
helper 'l' = modeL
helper _ = Mode 0
readModeDef :: String -> Mode
readModeDef = fromMaybe defaultMode . readModeMay
modeToConstraint :: Mode -> String
modeToConstraint = sort . concatMap helper . splitMode
where
helper :: Mode -> String
helper x
| x == modeS = symbols
| x == modeN = numbers
| x == modeC = upper
| x == modeL = lower
| otherwise = error "modeToConstraint: Invalid sigleton mode"