{-# LANGUAGE NoImplicitPrelude #-}

-- | This module splits a shell command line into a list of strings,
--   one for each command / filename
module IHaskell.Eval.ParseShell (parseShell) where

import           IHaskellPrelude

import           Text.ParserCombinators.Parsec

eol :: Parser Char
eol :: Parser Char
eol = forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"\n\r" forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"end of line"

quote :: Parser Char
quote :: Parser Char
quote = forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\"'

-- | @manyTillEnd p end@ from normal @manyTill@ in that it appends the result of @end@
manyTillEnd :: Parser a -> Parser [a] -> Parser [a]
manyTillEnd :: forall a. Parser a -> Parser [a] -> Parser [a]
manyTillEnd Parser a
p Parser [a]
end = Parser [a]
scan
  where
    scan :: Parser [a]
scan = Parser [a]
end forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> do
             a
x <- Parser a
p
             [a]
xs <- Parser [a]
scan
             forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ a
x forall a. a -> [a] -> [a]
: [a]
xs

manyTillEnd1 :: Parser a -> Parser [a] -> Parser [a]
manyTillEnd1 :: forall a. Parser a -> Parser [a] -> Parser [a]
manyTillEnd1 Parser a
p Parser [a]
end = do
  a
x <- Parser a
p
  [a]
xs <- forall a. Parser a -> Parser [a] -> Parser [a]
manyTillEnd Parser a
p Parser [a]
end
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ a
x forall a. a -> [a] -> [a]
: [a]
xs

unescapedChar :: Parser Char -> Parser String
unescapedChar :: Parser Char -> Parser String
unescapedChar Parser Char
p = forall tok st a. GenParser tok st a -> GenParser tok st a
try forall a b. (a -> b) -> a -> b
$ do
  Char
x <- forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"\\"
  Char
_ <- forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead Parser Char
p
  forall (m :: * -> *) a. Monad m => a -> m a
return [Char
x]

quotedString :: Parser [Char]
quotedString :: Parser String
quotedString = do
  Char
_ <- Parser Char
quote forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"expected starting quote"
  (forall a. Parser a -> Parser [a] -> Parser [a]
manyTillEnd forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar (Parser Char -> Parser String
unescapedChar Parser Char
quote) forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Parser Char
quote) forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"unexpected in quoted String "

unquotedString :: Parser [Char]
unquotedString :: Parser String
unquotedString = forall a. Parser a -> Parser [a] -> Parser [a]
manyTillEnd1 forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar Parser String
end
  where
    end :: Parser String
end = Parser Char -> Parser String
unescapedChar forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
space
          forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead Parser Char
eol forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return [])

word :: Parser [Char]
word :: Parser String
word = Parser String
quotedString forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Parser String
unquotedString forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"word"

separator :: Parser String
separator :: Parser String
separator = forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
space forall s u (m :: * -> *) a.
ParsecT s u m a -> String -> ParsecT s u m a
<?> String
"separator"

-- | Input must terminate in a space character (like a \n)
shellWords :: Parser [String]
shellWords :: Parser [String]
shellWords = forall tok st a. GenParser tok st a -> GenParser tok st a
try (forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (m :: * -> *) a. Monad m => a -> m a
return []) forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> do
               String
x <- Parser String
word
               String
_rest1 <- forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m t
anyToken)
               String
_ss <- Parser String
separator
               String
_rest2 <- forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m t
anyToken)
               [String]
xs <- Parser [String]
shellWords
               forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ String
x forall a. a -> [a] -> [a]
: [String]
xs

parseShell :: String -> Either ParseError [String]
parseShell :: String -> Either ParseError [String]
parseShell String
str = forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
parse Parser [String]
shellWords String
"shell" (String
str forall a. [a] -> [a] -> [a]
++ String
"\n")