Created
March 14, 2013 08:38
-
-
Save yuga/5159801 to your computer and use it in GitHub Desktop.
GNU sort コマンドの -k オプションの引数を Parsecでパースして、テキトウなデータ型 SortKey に格納するコード。
この結果を使用するプログラムをあとで書こうと思うのだけど、フラットなデータ型で持ちまわるのが便利か、それともASTのままでよかったのか、僕には未知数。
たしかに n と r のフラグだけはASTのままと不便だし...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module SortKey where | |
import Control.Applicative ( (<$>), (<*>), (<*), (*>) ) | |
import Control.Monad ( void ) | |
import Text.Parsec ( ParsecT, Stream, char, digit, eof, many, many1 | |
, option, runParser, space, (<|>) ) | |
import Text.Parsec.String ( Parser ) | |
data SortKeyAST = SortKeyAST StartF EndF | |
data StartF = SF Int StartC SortOpt | |
data StartC = SCNil | SC Int | |
data SortOpt = SONil | IsNum SortOpt | IsRev SortOpt | |
data EndF = EFNil | EF Int EndC SortOpt | |
data EndC = ECNil | EC Int | |
data SortKey = SortKey | |
{ startf :: Int | |
, startc :: Maybe Int | |
, endf :: Maybe Int | |
, endc :: Maybe Int | |
, isnum :: Bool | |
, isrev :: Bool | |
} | |
deriving Show | |
sortKey :: String -> SortKey | |
sortKey s = case runParser parseSortKey () "-k argument" s of | |
Left e -> error (show e) | |
Right ast -> toSortKey ast | |
parseSortKey :: Parser SortKeyAST | |
parseSortKey = (SortKeyAST <$> startF <*> endF) <* eof | |
startF :: Parser StartF | |
startF = SF <$> num <*> startC <*> sortOpt | |
startC :: Parser StartC | |
startC = option2 SCNil dot (SC <$> num) | |
endF :: Parser EndF | |
endF = option2 EFNil comma (EF <$> (separator *> num) <*> endC <*> sortOpt) | |
endC :: Parser EndC | |
endC = option2 ECNil dot (EC <$> num) | |
sortOpt :: Parser SortOpt | |
sortOpt = option SONil (isNum <|> isRev) | |
isNum :: Parser SortOpt | |
isNum = char 'n' >> IsNum <$> sortOpt | |
isRev :: Parser SortOpt | |
isRev = char 'r' >> IsRev <$> sortOpt | |
num :: Parser Int | |
num = read <$> many1 digit | |
separator :: Parser () | |
separator = void $ many space | |
dot :: Parser () | |
dot = void $ char '.' | |
comma :: Parser () | |
comma = void $ char ',' | |
option2 :: (Stream s m t) => a -> ParsecT s u m b -> ParsecT s u m a -> ParsecT s u m a | |
option2 x p1 p2 = do | |
mr <- (p1 >>= \r -> return (Just r)) <|> return Nothing | |
case mr of | |
Nothing -> return x | |
Just _ -> p2 | |
toSortKey :: SortKeyAST -> SortKey | |
toSortKey key = case key of | |
(SortKeyAST (SF startf sc opts1) (EF endf ec opts2)) -> | |
SortKey startf | |
(startc sc) | |
(Just endf) | |
(endc ec) | |
(isnum opts1 || isnum opts2) | |
(isrev opts1 || isrev opts2) | |
(SortKeyAST (SF startf sc opts1) EFNil) -> | |
SortKey startf | |
(startc sc) | |
Nothing | |
Nothing | |
(isnum opts1) | |
(isrev opts1) | |
where | |
startc SCNil = Nothing | |
startc (SC sc) = Just sc | |
endc ECNil = Nothing | |
endc (EC ec) = Just ec | |
isnum SONil = False | |
isnum (IsNum opts') = True | |
isnum (IsRev opts') = isnum opts' | |
isrev SONil = False | |
isrev (IsNum opts') = isrev opts' | |
isrev (IsRev opts') = True |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment