module IHaskell.Eval.ParseShell (parseShell) where
import Prelude hiding (words)
import Text.ParserCombinators.Parsec hiding (manyTill)
import Control.Applicative hiding ((<|>), many, optional)
eol :: Parser Char
eol = oneOf "\n\r" <?> "end of line"
quote :: Parser Char
quote = char '\"'
manyTill :: Parser a -> Parser [a] -> Parser [a]
manyTill p end = scan
where
scan = end <|> do
x <- p
xs <- scan
return $ x:xs
manyTill1 p end = do x <- p
xs <- manyTill p end
return $ x : xs
unescapedChar :: Parser Char -> Parser String
unescapedChar p = try $ do
x <- noneOf "\\"
lookAhead p
return [x]
quotedString = do
quote <?> "expected starting quote"
(manyTill anyChar (unescapedChar quote) <* quote) <?> "unexpected in quoted String "
unquotedString = manyTill1 anyChar end
where end = unescapedChar space
<|> (lookAhead eol >> return [])
word = quotedString <|> unquotedString <?> "word"
separator :: Parser String
separator = many1 space <?> "separator"
words :: Parser [String]
words = try (eof *> return []) <|> do
x <- word
rest1 <- lookAhead (many anyToken)
ss <- separator
rest2 <- lookAhead (many anyToken)
xs <- words
return $ x : xs
parseShell :: String -> Either ParseError [String]
parseShell string = parse words "shell" (string ++ "\n")