Skip to content

Instantly share code, notes, and snippets.

@yuga
Created March 14, 2013 08:38
Show Gist options
  • Save yuga/5159801 to your computer and use it in GitHub Desktop.
Save yuga/5159801 to your computer and use it in GitHub Desktop.
GNU sort コマンドの -k オプションの引数を Parsecでパースして、テキトウなデータ型 SortKey に格納するコード。 この結果を使用するプログラムをあとで書こうと思うのだけど、フラットなデータ型で持ちまわるのが便利か、それともASTのままでよかったのか、僕には未知数。 たしかに n と r のフラグだけはASTのままと不便だし...
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