diff options
| author | tv <tv@shackspace.de> | 2014-07-28 22:08:13 +0200 | 
|---|---|---|
| committer | tv <tv@shackspace.de> | 2014-07-28 22:08:13 +0200 | 
| commit | 91e07794826e15fa8c764cb7869c2f16bb0d9677 (patch) | |
| tree | 6221b8251f2a09568fbc8a664cd9198ef493eeef /src | |
| parent | 7f342643d8a5996ae7a7053e737db63fda48b451 (diff) | |
Scanner: initial commit (not activated)
Diffstat (limited to 'src')
| -rw-r--r-- | src/Scanner.hs | 258 | 
1 files changed, 258 insertions, 0 deletions
diff --git a/src/Scanner.hs b/src/Scanner.hs new file mode 100644 index 0000000..ba81abb --- /dev/null +++ b/src/Scanner.hs @@ -0,0 +1,258 @@ +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE FlexibleContexts #-} +module Scanner where + +import Control.Monad (forever) +import System.IO + +import Data.Ord +import Data.Bits +import Data.Char + +import Prelude hiding ((/)) + +import Control.Applicative +import Control.Monad.Error +import Control.Monad.State +import Control.Monad.Writer + +import Data.Time.Clock + + +type P = C +type I = C +type F = C + +data Token +    = CS [P] [I] F +    | Chr C +  deriving (Show) + +type ScanLog = [C] + +type ScanError = String + +data ScanState = ScanState +    { result :: Maybe Token +    , buffer :: [C] +    } + +emptyScanState = ScanState Nothing [] + + +newtype Scanner m a = Scanner +    (ErrorT ScanError (WriterT ScanLog (StateT ScanState m)) a) +  deriving +    ( Applicative +    , Functor +    , Monad +    , MonadIO +    , MonadState ScanState +    , MonadError ScanError +    , MonadWriter ScanLog +    ) + +runScanner :: Scanner m a -> m ((Either ScanError a, ScanLog), ScanState) +runScanner (Scanner a) = +    runStateT (runWriterT (runErrorT a)) emptyScanState + + +-- TODO max timeout +timeout = 1 + + +main :: IO () +main = do +    hSetEcho stdin False +    hSetBuffering stdin NoBuffering +    forever $ do + +        _ <- hLookAhead stdin -- wait for input + +        t0 <- getCurrentTime +        ((res, s), _) <- runScanner scan +        t1 <- getCurrentTime + +        putStrLn $ "====> \ESC[32;1m" ++ show s ++ "\ESC[m in " ++ +                    (show $ diffUTCTime t1 t0) +                    ++ ": \"\ESC[35m" ++ (concat $ map (colorize . toChar) s) +                    ++ "\ESC[m\"" +        case res of +            Left msg -> putStrLn $ "  error: " ++ msg +            Right _ -> return () + + +scan, scanESC, scanCS :: +    ( Monad m +    , MonadIO m +    , MonadError ScanError m +    , MonadState ScanState m +    , MonadWriter ScanLog m +    ) => m () + + +scan = do +    c <- liftIO $ hGetC stdin +    tell [c] +    case () of _ +                | c == 01/11 -> scanESC +                | otherwise -> return () + + +scanESC = do +    mb_c <- liftIO $ hWaitGetC timeout stdin +    whenJust mb_c $ \ c -> do +        tell [c] +        case () of _ +                    | c == 05/11 -> +                        -- CSI +                        scanCS + +                    | c == 01/11 -> +                        -- XXX M-F1 and other crazy chords may cause +                        -- \ESC\ESC... on wu, so we just recurse here... +                        scanESC + +                    | c == 04/15 -> +                        -- XXX Non-CSI SS3 +                        one $ between (04/00) (07/14) + +                    | otherwise -> return () + + +scanCS = do +    zeroOrMore $ between (03/00) (03/15)    -- parameter bytes +    zeroOrMore $ between (02/00) (02/15)    -- intermediate bytes +    one $ between (04/00) (07/14)           -- final byte + + +between :: C -> C -> (C -> Bool) +between lo hi = \ x -> lo <= x && x <= hi + + +zeroOrMore, one :: +    ( Monad m +    , MonadIO m +    , MonadError ScanError m +    , MonadState ScanState m +    , MonadWriter ScanLog m +    ) => (C -> Bool) -> m () + + +zeroOrMore p = do +    mb_c <- liftIO $ hWaitLookAheadC timeout stdin +    whenJust mb_c $ \ c -> +        when (p c) $ do +            _ <- liftIO $ hGetC stdin -- drop +            tell [c] +            modify $ \q -> q { buffer = buffer q ++ [c] } +            zeroOrMore p + + +one p = do +    mb_c <- liftIO $ hWaitLookAheadC timeout stdin +    whenJust mb_c $ \ c -> do +        if p c +            then do +                _ <- liftIO getChar +                tell [c] +                modify $ \q -> q { buffer = buffer q ++ [c] } +            else do +                throwError "expected one TODO" + + + + + + + + +whenJust :: Monad m => Maybe a -> (a -> m ()) -> m () +whenJust mb f = +    case mb of +        Just a -> f a +        Nothing -> return () + + + + +c / r = C c r + +data C = C { column :: Int, row :: Int } +    deriving (Eq) + +instance Show C where +  show C{..} =  +      (padl 2 '0' $ show column) ++ "/" ++ (padl 2 '0' $ show row) +    where +      padl n c s +        | length s < n = padl n c (c : s) +        | otherwise = s + + +instance Ord C where +    compare (C c1 r1) (C c2 r2) = +        case compare c1 c2 of +            EQ -> compare r1 r2 +            x -> x + + +fromChar :: Char -> C +fromChar c = let i = ord c in C ((shift i (-4)) .&. 0xf) (i .&. 0xf) + +toChar :: C -> Char +toChar (C col row) = chr $ (shift col 4) .|. row + + + + + +colorize :: Char -> String +colorize c +  | isPrint c = [c] +  | otherwise = "\ESC[1m" ++ (showLitChar c "") ++ "\ESC[22m" + + + + + +-- +hWaitGetChar t h = do +    ready <- hWaitForInput h t +    if ready +        then hGetChar h >>= return . Just +        else return Nothing + +hGetC h = hGetChar h >>= return . fromChar +hWaitGetC t h = do +    mb_ch <- hWaitGetChar t h +    case mb_ch of +        Nothing -> return Nothing +        Just ch -> return $ Just $ fromChar $ ch + +hWaitLookAheadC t h = do +    ready <- hWaitForInput h t +    if ready +        then hLookAhead h >>= return . Just . fromChar +        else return Nothing + + +-- CRUFT +--expect cx ca = +--    when (cx /= ca) $  +--        throwError $ "expected: " ++ (show cx) ++ ", got: " ++ (show ca) +-- +-- +-- +--    expect (01/11) c +-- +--    c <- (liftIO getChar) >>= return . fromChar +-- +--    tell [c] +-- +--    expect (05/11) c + +    --liftIO $ putStrLn $ (show c) ++ " -> " ++ (show s) + +  | 
