{-
    Copyright 2012-2022 Vidar Holen

    This file is part of ShellCheck.
    https://www.shellcheck.net

    ShellCheck is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ShellCheck is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiWayIf #-}
module ShellCheck.Parser (parseScript, runTests) where

import ShellCheck.AST
import ShellCheck.ASTLib hiding (runTests)
import ShellCheck.Data
import ShellCheck.Interface
import ShellCheck.Prelude

import Control.Applicative ((<*), (*>))
import Control.Monad
import Control.Monad.Identity
import Control.Monad.Trans
import Data.Char
import Data.Functor
import Data.List (isPrefixOf, isInfixOf, isSuffixOf, partition, sortBy, intercalate, nub, find)
import Data.Maybe
import Data.Monoid
import GHC.Exts (sortWith)
import Prelude hiding (readList)
import System.IO
import Text.Parsec hiding (runParser, (<?>))
import Text.Parsec.Error
import Text.Parsec.Pos
import qualified Control.Monad.Reader as Mr
import qualified Control.Monad.State as Ms
import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map

import Test.QuickCheck.All (quickCheckAll)

type SCBase m = Mr.ReaderT (Environment m) (Ms.StateT SystemState m)
type SCParser m v = ParsecT String UserState (SCBase m) v

backslash :: Monad m => SCParser m Char
backslash :: forall (m :: * -> *). Monad m => SCParser m Char
backslash = Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\\'
linefeed :: Monad m => SCParser m Char
linefeed :: forall (m :: * -> *). Monad m => SCParser m Char
linefeed = do
    ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional ParsecT String UserState (SCBase m) Char
forall {m :: * -> *} {s} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m Char
carriageReturn
    c <- Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\n'
    readPendingHereDocs
    return c
singleQuote :: ParsecT s u m Char
singleQuote = Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\''
doubleQuote :: ParsecT s u m Char
doubleQuote = Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'"'
variableStart :: ParsecT s u m Char
variableStart = ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
upper ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
lower ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"_"
variableChars :: ParsecT s u m Char
variableChars = ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
upper ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
lower ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"_"
-- Chars to allow in function names
functionChars :: ParsecT s u m Char
functionChars = ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
variableChars ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
":+?-./^@,"
-- Chars to allow in functions using the 'function' keyword
extendedFunctionChars :: ParsecT s u m Char
extendedFunctionChars = ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
functionChars ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"[]*=!"
specialVariable :: ParsecT s u m Char
specialVariable = String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf ([String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String]
specialVariables)
paramSubSpecialChars :: ParsecT s u m Char
paramSubSpecialChars = String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"/:+-=%"
quotableChars :: String
quotableChars = String
"|&;<>()\\ '\t\n\r\xA0" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
doubleQuotableChars
quotable :: ParsecT s UserState m Char
quotable = ParsecT s UserState m Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
almostSpace ParsecT s UserState m Char
-> ParsecT s UserState m Char -> ParsecT s UserState m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT s UserState m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
quotableChars
bracedQuotable :: ParsecT s u m Char
bracedQuotable = String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"}\"$`'"
doubleQuotableChars :: String
doubleQuotableChars = String
"\\\"$`"
doubleQuotable :: ParsecT s u m Char
doubleQuotable = String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
doubleQuotableChars
whitespace :: ParsecT String UserState (SCBase m) Char
whitespace = String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
" \t" ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
forall {m :: * -> *} {s} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m Char
carriageReturn ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
almostSpace ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
linefeed
linewhitespace :: ParsecT s UserState m Char
linewhitespace = String -> ParsecT s UserState m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
" \t" ParsecT s UserState m Char
-> ParsecT s UserState m Char -> ParsecT s UserState m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
almostSpace

suspectCharAfterQuotes :: ParsecT s u m Char
suspectCharAfterQuotes = ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
variableChars ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'%'

extglobStartChars :: String
extglobStartChars = String
"?*@!+"
extglobStart :: ParsecT s u m Char
extglobStart = String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
extglobStartChars

unicodeDoubleQuotes :: String
unicodeDoubleQuotes = String
"\x201C\x201D\x2033\x2036"
unicodeSingleQuotes :: String
unicodeSingleQuotes = String
"\x2018\x2019"

prop_spacing1 :: Bool
prop_spacing1 = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing String
"  \\\n # Comment"
prop_spacing2 :: Bool
prop_spacing2 = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing String
"# We can continue lines with \\"
prop_spacing3 :: Bool
prop_spacing3 = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing String
"   \\\n #  --verbose=true \\"
spacing :: ParsecT s UserState m String
spacing = do
    x <- ParsecT s UserState m String -> ParsecT s UserState m [String]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT s UserState m Char -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT s UserState m Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
linewhitespace ParsecT s UserState m String
-> ParsecT s UserState m String -> ParsecT s UserState m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
continuation)
    optional readComment
    return $ concat x
  where
    continuation :: ParsecT s UserState m String
continuation = do
        ParsecT s UserState m String -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (String -> ParsecT s UserState m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\\\n")
        -- The line was continued. Warn if this next line is a comment with a trailing \
        whitespace <- ParsecT s UserState m Char -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT s UserState m Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
linewhitespace
        optional $ do
            x <- readComment
            when ("\\" `isSuffixOf` x) $
                parseProblem ErrorC 1143 "This backslash is part of a comment and does not continue the line."
        return whitespace

spacing1 :: ParsecT s UserState m String
spacing1 = do
    spacing <- ParsecT s UserState m String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing
    when (null spacing) $ fail "Expected whitespace"
    return spacing

prop_allspacing :: Bool
prop_allspacing = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing String
"#foo"
prop_allspacing2 :: Bool
prop_allspacing2 = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing String
" #foo\n # bar\n#baz\n"
prop_allspacing3 :: Bool
prop_allspacing3 = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing String
"#foo\n#bar\n#baz\n"
allspacing :: ParsecT String UserState (SCBase m) String
allspacing = do
    s <- ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing
    more <- option False (linefeed >> return True)
    if more then do
        rest <- allspacing
        return $ s ++ "\n" ++ rest
      else
        return s

allspacingOrFail :: ParsecT String UserState (SCBase m) String
allspacingOrFail = do
    s <- ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing
    when (null s) $ fail "Expected whitespace"
    return s

readUnicodeQuote :: ParsecT String UserState (SCBase m) Token
readUnicodeQuote = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    c <- oneOf (unicodeSingleQuotes ++ unicodeDoubleQuotes)
    id <- endSpan start
    parseProblemAtId id WarningC 1110 "This is a unicode quote. Delete and retype it (or quote to make literal)."
    return $ T_Literal id [c]

carriageReturn :: ParsecT s u m Char
carriageReturn = do
    pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    char '\r'
    parseProblemAt pos ErrorC 1017 "Literal carriage return. Run script through tr -d '\\r' ."
    return '\r'

almostSpace :: ParsecT s UserState m Char
almostSpace =
    [ParsecT s UserState m Char] -> ParsecT s UserState m Char
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
        Char -> String -> ParsecT s UserState m Char
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m,
 Stream s m Char) =>
Char -> String -> ParsecT s UserState m Char
check Char
'\xA0' String
"unicode non-breaking space",
        Char -> String -> ParsecT s UserState m Char
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m,
 Stream s m Char) =>
Char -> String -> ParsecT s UserState m Char
check Char
'\x200B' String
"unicode zerowidth space"
    ]
  where
    check :: Char -> String -> ParsecT s UserState m Char
check Char
c String
name = do
        Severity -> Integer -> String -> ParsecT s UserState m ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s UserState m ()
parseNote Severity
ErrorC Integer
1018 (String -> ParsecT s UserState m ())
-> String -> ParsecT s UserState m ()
forall a b. (a -> b) -> a -> b
$ String
"This is a " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
". Delete and retype it."
        Char -> ParsecT s UserState m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
c
        Char -> ParsecT s UserState m Char
forall a. a -> ParsecT s UserState m a
forall (m :: * -> *) a. Monad m => a -> m a
return Char
' '

--------- Message/position annotation on top of user state
data ParseNote = ParseNote SourcePos SourcePos Severity Code String deriving (Line -> ParseNote -> String -> String
[ParseNote] -> String -> String
ParseNote -> String
(Line -> ParseNote -> String -> String)
-> (ParseNote -> String)
-> ([ParseNote] -> String -> String)
-> Show ParseNote
forall a.
(Line -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Line -> ParseNote -> String -> String
showsPrec :: Line -> ParseNote -> String -> String
$cshow :: ParseNote -> String
show :: ParseNote -> String
$cshowList :: [ParseNote] -> String -> String
showList :: [ParseNote] -> String -> String
Show, ParseNote -> ParseNote -> Bool
(ParseNote -> ParseNote -> Bool)
-> (ParseNote -> ParseNote -> Bool) -> Eq ParseNote
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ParseNote -> ParseNote -> Bool
== :: ParseNote -> ParseNote -> Bool
$c/= :: ParseNote -> ParseNote -> Bool
/= :: ParseNote -> ParseNote -> Bool
Eq)
data Context =
        ContextName SourcePos String
        | ContextAnnotation [Annotation]
        | ContextSource String
    deriving (Line -> Context -> String -> String
[Context] -> String -> String
Context -> String
(Line -> Context -> String -> String)
-> (Context -> String)
-> ([Context] -> String -> String)
-> Show Context
forall a.
(Line -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Line -> Context -> String -> String
showsPrec :: Line -> Context -> String -> String
$cshow :: Context -> String
show :: Context -> String
$cshowList :: [Context] -> String -> String
showList :: [Context] -> String -> String
Show)

data HereDocContext =
        HereDocPending Id Dashed Quoted String [Context] -- on linefeed, read this T_HereDoc
    deriving (Line -> HereDocContext -> String -> String
[HereDocContext] -> String -> String
HereDocContext -> String
(Line -> HereDocContext -> String -> String)
-> (HereDocContext -> String)
-> ([HereDocContext] -> String -> String)
-> Show HereDocContext
forall a.
(Line -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
$cshowsPrec :: Line -> HereDocContext -> String -> String
showsPrec :: Line -> HereDocContext -> String -> String
$cshow :: HereDocContext -> String
show :: HereDocContext -> String
$cshowList :: [HereDocContext] -> String -> String
showList :: [HereDocContext] -> String -> String
Show)

data UserState = UserState {
    UserState -> Id
lastId :: Id,
    UserState -> Map Id (SourcePos, SourcePos)
positionMap :: Map.Map Id (SourcePos, SourcePos),
    UserState -> [ParseNote]
parseNotes :: [ParseNote],
    UserState -> Map Id [Token]
hereDocMap :: Map.Map Id [Token],
    UserState -> [HereDocContext]
pendingHereDocs :: [HereDocContext]
}
initialUserState :: UserState
initialUserState = UserState {
    lastId :: Id
lastId = Line -> Id
Id (Line -> Id) -> Line -> Id
forall a b. (a -> b) -> a -> b
$ -Line
1,
    positionMap :: Map Id (SourcePos, SourcePos)
positionMap = Map Id (SourcePos, SourcePos)
forall k a. Map k a
Map.empty,
    parseNotes :: [ParseNote]
parseNotes = [],
    hereDocMap :: Map Id [Token]
hereDocMap = Map Id [Token]
forall k a. Map k a
Map.empty,
    pendingHereDocs :: [HereDocContext]
pendingHereDocs = []
}

codeForParseNote :: ParseNote -> Integer
codeForParseNote (ParseNote SourcePos
_ SourcePos
_ Severity
_ Integer
code String
_) = Integer
code

getLastId :: ParsecT s UserState m Id
getLastId = UserState -> Id
lastId (UserState -> Id)
-> ParsecT s UserState m UserState -> ParsecT s UserState m Id
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s UserState m UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState

getNextIdBetween :: SourcePos -> SourcePos -> ParsecT s UserState m Id
getNextIdBetween SourcePos
startPos SourcePos
endPos = do
    state <- ParsecT s UserState m UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
    let newId = Id -> Id
incId (UserState -> Id
lastId UserState
state)
    let newMap = Id
-> (SourcePos, SourcePos)
-> Map Id (SourcePos, SourcePos)
-> Map Id (SourcePos, SourcePos)
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert Id
newId (SourcePos
startPos, SourcePos
endPos) (UserState -> Map Id (SourcePos, SourcePos)
positionMap UserState
state)
    putState $ state {
        lastId = newId,
        positionMap = newMap
    }
    return newId
  where incId :: Id -> Id
incId (Id Line
n) = Line -> Id
Id (Line -> Id) -> Line -> Id
forall a b. (a -> b) -> a -> b
$ Line
nLine -> Line -> Line
forall a. Num a => a -> a -> a
+Line
1

getNextIdSpanningTokens :: Token -> Token -> ParsecT String UserState (SCBase m) Id
getNextIdSpanningTokens Token
startTok Token
endTok = do
    (start, _) <- Id -> SCParser m (SourcePos, SourcePos)
forall (m :: * -> *).
Monad m =>
Id -> SCParser m (SourcePos, SourcePos)
getSpanForId (Token -> Id
getId Token
startTok)
    (_, end)   <- getSpanForId (getId endTok)
    getNextIdBetween start end

-- Get an ID starting from the first token of the list, and ending after the last
getNextIdSpanningTokenList :: [Token] -> ParsecT String UserState (SCBase m) Id
getNextIdSpanningTokenList [Token]
list =
    case [Token]
list of
    [] -> do
        pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        getNextIdBetween pos pos
    (Token
h:[Token]
_) ->
        Token -> Token -> ParsecT String UserState (SCBase m) Id
forall {m :: * -> *}.
Monad m =>
Token -> Token -> ParsecT String UserState (SCBase m) Id
getNextIdSpanningTokens Token
h ([Token] -> Token
forall a. HasCallStack => [a] -> a
last [Token]
list)

-- Get the span covered by an id
getSpanForId :: Monad m => Id -> SCParser m (SourcePos, SourcePos)
getSpanForId :: forall (m :: * -> *).
Monad m =>
Id -> SCParser m (SourcePos, SourcePos)
getSpanForId Id
id =
    (SourcePos, SourcePos)
-> Id -> Map Id (SourcePos, SourcePos) -> (SourcePos, SourcePos)
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault (String -> (SourcePos, SourcePos)
forall a. HasCallStack => String -> a
error (String -> (SourcePos, SourcePos))
-> String -> (SourcePos, SourcePos)
forall a b. (a -> b) -> a -> b
$ String -> String
pleaseReport String
"no parser span for id") Id
id (Map Id (SourcePos, SourcePos) -> (SourcePos, SourcePos))
-> ParsecT
     String UserState (SCBase m) (Map Id (SourcePos, SourcePos))
-> ParsecT String UserState (SCBase m) (SourcePos, SourcePos)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
        ParsecT String UserState (SCBase m) (Map Id (SourcePos, SourcePos))
forall {m :: * -> *} {s}.
Monad m =>
ParsecT s UserState m (Map Id (SourcePos, SourcePos))
getMap

-- Create a new id with the same span as an existing one
getNewIdFor :: Monad m => Id -> SCParser m Id
getNewIdFor :: forall (m :: * -> *). Monad m => Id -> SCParser m Id
getNewIdFor Id
id = Id -> SCParser m (SourcePos, SourcePos)
forall (m :: * -> *).
Monad m =>
Id -> SCParser m (SourcePos, SourcePos)
getSpanForId Id
id SCParser m (SourcePos, SourcePos)
-> ((SourcePos, SourcePos)
    -> ParsecT String UserState (SCBase m) Id)
-> ParsecT String UserState (SCBase m) Id
forall a b.
ParsecT String UserState (SCBase m) a
-> (a -> ParsecT String UserState (SCBase m) b)
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (SourcePos -> SourcePos -> ParsecT String UserState (SCBase m) Id)
-> (SourcePos, SourcePos) -> ParsecT String UserState (SCBase m) Id
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry SourcePos -> SourcePos -> ParsecT String UserState (SCBase m) Id
forall {m :: * -> *} {s}.
Monad m =>
SourcePos -> SourcePos -> ParsecT s UserState m Id
getNextIdBetween

data IncompleteInterval = IncompleteInterval SourcePos

startSpan :: ParsecT s u m IncompleteInterval
startSpan = SourcePos -> IncompleteInterval
IncompleteInterval (SourcePos -> IncompleteInterval)
-> ParsecT s u m SourcePos -> ParsecT s u m IncompleteInterval
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition

endSpan :: IncompleteInterval -> ParsecT s UserState m Id
endSpan (IncompleteInterval SourcePos
start) = do
    endPos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    getNextIdBetween start endPos

getSpanPositionsFor :: ParsecT s u m a -> ParsecT s u m (SourcePos, SourcePos)
getSpanPositionsFor ParsecT s u m a
m = do
    start <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    m
    end <- getPosition
    return (start, end)

addToHereDocMap :: Id -> [Token] -> ParsecT s UserState m ()
addToHereDocMap Id
id [Token]
list = do
    state <- ParsecT s UserState m UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
    let map = UserState -> Map Id [Token]
hereDocMap UserState
state
    putState $ state {
        hereDocMap = Map.insert id list map
    }

addPendingHereDoc :: Id -> Dashed -> Quoted -> String -> ParsecT s UserState m ()
addPendingHereDoc Id
id Dashed
d Quoted
q String
str = do
    state <- ParsecT s UserState m UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
    context <- getCurrentContexts
    let docs = UserState -> [HereDocContext]
pendingHereDocs UserState
state
    putState $ state {
        pendingHereDocs = HereDocPending id d q str context : docs
    }

popPendingHereDocs :: ParsecT s UserState m [HereDocContext]
popPendingHereDocs = do
    state <- ParsecT s UserState m UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
    let pending = UserState -> [HereDocContext]
pendingHereDocs UserState
state
    putState $ state {
        pendingHereDocs = []
    }
    return . reverse $ pendingHereDocs state

getMap :: ParsecT s UserState m (Map Id (SourcePos, SourcePos))
getMap = UserState -> Map Id (SourcePos, SourcePos)
positionMap (UserState -> Map Id (SourcePos, SourcePos))
-> ParsecT s UserState m UserState
-> ParsecT s UserState m (Map Id (SourcePos, SourcePos))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s UserState m UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
getParseNotes :: ParsecT s UserState m [ParseNote]
getParseNotes = UserState -> [ParseNote]
parseNotes (UserState -> [ParseNote])
-> ParsecT s UserState m UserState
-> ParsecT s UserState m [ParseNote]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s UserState m UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState

addParseNote :: ParseNote -> ParsecT s UserState m ()
addParseNote ParseNote
n = do
    irrelevant <- Integer -> ParsecT s UserState m Bool
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Integer -> m Bool
shouldIgnoreCode (ParseNote -> Integer
codeForParseNote ParseNote
n)
    unless irrelevant $ do
        state <- getState
        putState $ state {
            parseNotes = n : parseNotes state
        }

ignoreProblemsOf :: t (t m) b -> t (t m) b
ignoreProblemsOf t (t m) b
p = do
    systemState <- t m a -> t (t m) a
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (t m a -> t (t m) a) -> (m a -> t m a) -> m a -> t (t m) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> t m a
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> t (t m) a) -> m a -> t (t m) a
forall a b. (a -> b) -> a -> b
$ m a
forall s (m :: * -> *). MonadState s m => m s
Ms.get
    p <* (lift . lift . Ms.put $ systemState)

shouldIgnoreCode :: Integer -> m Bool
shouldIgnoreCode Integer
code = do
    context <- m [Context]
forall {m :: * -> *}. MonadState SystemState m => m [Context]
getCurrentContexts
    checkSourced <- Mr.asks checkSourced
    return $ any (contextItemDisablesCode checkSourced code) context

-- Does this item on the context stack disable warnings for 'code'?
contextItemDisablesCode :: Bool -> Integer -> Context -> Bool
contextItemDisablesCode :: Bool -> Integer -> Context -> Bool
contextItemDisablesCode Bool
alsoCheckSourced Integer
code = Bool -> Context -> Bool
disabling Bool
alsoCheckSourced
  where
    disabling :: Bool -> Context -> Bool
disabling Bool
checkSourced Context
item =
        case Context
item of
            ContextAnnotation [Annotation]
list -> (Annotation -> Bool) -> [Annotation] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Annotation -> Bool
disabling' [Annotation]
list
            ContextSource String
_ -> Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Bool
checkSourced
            Context
_ -> Bool
False
    disabling' :: Annotation -> Bool
disabling' (DisableComment Integer
n Integer
m) = Integer
code Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
n Bool -> Bool -> Bool
&& Integer
code Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
m
    disabling' Annotation
_ = Bool
False



getCurrentAnnotations :: Bool -> f [Annotation]
getCurrentAnnotations Bool
includeSource =
    (Context -> [Annotation]) -> [Context] -> [Annotation]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Context -> [Annotation]
get ([Context] -> [Annotation])
-> ([Context] -> [Context]) -> [Context] -> [Annotation]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Context -> Bool) -> [Context] -> [Context]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Bool -> Bool
not (Bool -> Bool) -> (Context -> Bool) -> Context -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Context -> Bool
isBoundary) ([Context] -> [Annotation]) -> f [Context] -> f [Annotation]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f [Context]
forall {m :: * -> *}. MonadState SystemState m => m [Context]
getCurrentContexts
  where
    get :: Context -> [Annotation]
get (ContextAnnotation [Annotation]
list) = [Annotation]
list
    get Context
_ = []
    isBoundary :: Context -> Bool
isBoundary (ContextSource String
_) = Bool -> Bool
not Bool
includeSource
    isBoundary Context
_ = Bool
False


shouldFollow :: String -> ParsecT s u m Bool
shouldFollow String
file = do
    context <- ParsecT s u m [Context]
forall {m :: * -> *}. MonadState SystemState m => m [Context]
getCurrentContexts
    if any isThisFile context
      then return False
      else
        if length (filter isSource context) >= 100
          then do
            parseProblem ErrorC 1092 "Stopping at 100 'source' frames :O"
            return False
          else
            return True
  where
    isSource :: Context -> Bool
isSource (ContextSource String
_) = Bool
True
    isSource Context
_ = Bool
False
    isThisFile :: Context -> Bool
isThisFile (ContextSource String
name) | String
name String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
file = Bool
True
    isThisFile Context
_= Bool
False

getSourceOverride :: m (Maybe String)
getSourceOverride = do
    context <- m [Context]
forall {m :: * -> *}. MonadState SystemState m => m [Context]
getCurrentContexts
    return . msum . map findFile $ takeWhile isSameFile context
  where
    isSameFile :: Context -> Bool
isSameFile (ContextSource String
_) = Bool
False
    isSameFile Context
_ = Bool
True

    findFile :: Context -> Maybe String
findFile (ContextAnnotation [Annotation]
list) = [Maybe String] -> Maybe String
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum ([Maybe String] -> Maybe String) -> [Maybe String] -> Maybe String
forall a b. (a -> b) -> a -> b
$ (Annotation -> Maybe String) -> [Annotation] -> [Maybe String]
forall a b. (a -> b) -> [a] -> [b]
map Annotation -> Maybe String
getFile [Annotation]
list
    findFile Context
_ = Maybe String
forall a. Maybe a
Nothing
    getFile :: Annotation -> Maybe String
getFile (SourceOverride String
str) = String -> Maybe String
forall a. a -> Maybe a
Just String
str
    getFile Annotation
_ = Maybe String
forall a. Maybe a
Nothing

-- Store potential parse problems outside of parsec

data SystemState = SystemState {
    SystemState -> [Context]
contextStack :: [Context],
    SystemState -> [ParseNote]
parseProblems :: [ParseNote]
}
initialSystemState :: SystemState
initialSystemState = SystemState {
    contextStack :: [Context]
contextStack = [],
    parseProblems :: [ParseNote]
parseProblems = []
}

data Environment m = Environment {
    forall (m :: * -> *). Environment m -> SystemInterface m
systemInterface :: SystemInterface m,
    forall (m :: * -> *). Environment m -> Bool
checkSourced :: Bool,
    forall (m :: * -> *). Environment m -> Bool
ignoreRC :: Bool,
    forall (m :: * -> *). Environment m -> String
currentFilename :: String,
    forall (m :: * -> *). Environment m -> Maybe Shell
shellTypeOverride :: Maybe Shell
}

parseProblem :: Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
level Integer
code String
msg = do
    pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    parseProblemAt pos level code msg

setCurrentContexts :: [Context] -> m ()
setCurrentContexts [Context]
c = (SystemState -> SystemState) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
Ms.modify (\SystemState
state -> SystemState
state { contextStack = c })
getCurrentContexts :: m [Context]
getCurrentContexts = (SystemState -> [Context]) -> m [Context]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
Ms.gets SystemState -> [Context]
contextStack

popContext :: m (Maybe Context)
popContext = do
    v <- m [Context]
forall {m :: * -> *}. MonadState SystemState m => m [Context]
getCurrentContexts
    case v of
        (Context
a:[Context]
r) -> do
            [Context] -> m ()
forall {m :: * -> *}. MonadState SystemState m => [Context] -> m ()
setCurrentContexts [Context]
r
            Maybe Context -> m (Maybe Context)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Context -> m (Maybe Context))
-> Maybe Context -> m (Maybe Context)
forall a b. (a -> b) -> a -> b
$ Context -> Maybe Context
forall a. a -> Maybe a
Just Context
a
        [] ->
            Maybe Context -> m (Maybe Context)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Context
forall a. Maybe a
Nothing

pushContext :: Context -> m ()
pushContext Context
c = do
    v <- m [Context]
forall {m :: * -> *}. MonadState SystemState m => m [Context]
getCurrentContexts
    setCurrentContexts (c:v)

parseProblemAtWithEnd :: SourcePos -> SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAtWithEnd SourcePos
start SourcePos
end Severity
level Integer
code String
msg = do
    irrelevant <- Integer -> m Bool
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Integer -> m Bool
shouldIgnoreCode Integer
code
    unless irrelevant $
        addParseProblem note
  where
    note :: ParseNote
note = SourcePos
-> SourcePos -> Severity -> Integer -> String -> ParseNote
ParseNote SourcePos
start SourcePos
end Severity
level Integer
code String
msg

addParseProblem :: ParseNote -> m ()
addParseProblem ParseNote
note =
    (SystemState -> SystemState) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
Ms.modify (\SystemState
state -> SystemState
state {
        parseProblems = note:parseProblems state
    })

parseProblemAt :: SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
pos = SourcePos -> SourcePos -> Severity -> Integer -> String -> m ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAtWithEnd SourcePos
pos SourcePos
pos

parseProblemAtId :: Monad m => Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId :: forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId Id
id Severity
level Integer
code String
msg = do
    (start, end) <- Id -> SCParser m (SourcePos, SourcePos)
forall (m :: * -> *).
Monad m =>
Id -> SCParser m (SourcePos, SourcePos)
getSpanForId Id
id
    parseProblemAtWithEnd start end level code msg

-- Store non-parse problems inside

parseNote :: Severity -> Integer -> String -> ParsecT s UserState m ()
parseNote Severity
c Integer
l String
a = do
    pos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    parseNoteAt pos c l a

parseNoteAt :: SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
pos Severity
c Integer
l String
a = ParseNote -> ParsecT s UserState m ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
ParseNote -> ParsecT s UserState m ()
addParseNote (ParseNote -> ParsecT s UserState m ())
-> ParseNote -> ParsecT s UserState m ()
forall a b. (a -> b) -> a -> b
$ SourcePos
-> SourcePos -> Severity -> Integer -> String -> ParseNote
ParseNote SourcePos
pos SourcePos
pos Severity
c Integer
l String
a
parseNoteAtId :: Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
parseNoteAtId Id
id Severity
c Integer
l String
a = do
    (start, end) <- Id -> SCParser m (SourcePos, SourcePos)
forall (m :: * -> *).
Monad m =>
Id -> SCParser m (SourcePos, SourcePos)
getSpanForId Id
id
    addParseNote $ ParseNote start end c l a

parseNoteAtWithEnd :: SourcePos
-> SourcePos
-> Severity
-> Integer
-> String
-> ParsecT s UserState m ()
parseNoteAtWithEnd SourcePos
start SourcePos
end Severity
c Integer
l String
a = ParseNote -> ParsecT s UserState m ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
ParseNote -> ParsecT s UserState m ()
addParseNote (ParseNote -> ParsecT s UserState m ())
-> ParseNote -> ParsecT s UserState m ()
forall a b. (a -> b) -> a -> b
$ SourcePos
-> SourcePos -> Severity -> Integer -> String -> ParseNote
ParseNote SourcePos
start SourcePos
end Severity
c Integer
l String
a

--------- Convenient combinators
thenSkip :: ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
thenSkip ParsecT s u m a
main ParsecT s u m a
follow = ParsecT s u m a
main ParsecT s u m a -> ParsecT s u m () -> ParsecT s u m a
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT s u m a -> ParsecT s u m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional ParsecT s u m a
follow

unexpecting :: String -> ParsecT s u m a -> ParsecT s u m ()
unexpecting String
s ParsecT s u m a
p = ParsecT s u m () -> ParsecT s u m ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m () -> ParsecT s u m ())
-> ParsecT s u m () -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$
    (ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT s u m a
p ParsecT s u m a -> ParsecT s u m () -> ParsecT s u m ()
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> ParsecT s u m ()
forall a. String -> ParsecT s u m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
"Unexpected " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s)) ParsecT s u m () -> ParsecT s u m () -> ParsecT s u m ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> () -> ParsecT s u m ()
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

notFollowedBy2 :: ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 = String -> ParsecT s u m a -> ParsecT s u m ()
forall {s} {u} {m :: * -> *} {a}.
String -> ParsecT s u m a -> ParsecT s u m ()
unexpecting String
""

isFollowedBy :: ParsecT s u m a -> ParsecT s u m Bool
isFollowedBy ParsecT s u m a
p = (ParsecT s u m Bool -> ParsecT s u m Bool
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s u m Bool -> ParsecT s u m Bool)
-> (ParsecT s u m Bool -> ParsecT s u m Bool)
-> ParsecT s u m Bool
-> ParsecT s u m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT s u m Bool -> ParsecT s u m Bool
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m Bool -> ParsecT s u m Bool)
-> ParsecT s u m Bool -> ParsecT s u m Bool
forall a b. (a -> b) -> a -> b
$ ParsecT s u m a
p ParsecT s u m a -> Bool -> ParsecT s u m Bool
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> Bool
True) ParsecT s u m Bool -> ParsecT s u m Bool -> ParsecT s u m Bool
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Bool -> ParsecT s u m Bool
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

reluctantlyTill :: ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m [a]
reluctantlyTill ParsecT s u m a
p ParsecT s u m a
end =
    (ParsecT s u m () -> ParsecT s u m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s u m a -> ParsecT s u m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT s u m a
end) ParsecT s u m () -> ParsecT s u m () -> ParsecT s u m ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof) ParsecT s u m () -> ParsecT s u m [a] -> ParsecT s u m [a]
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [a] -> ParsecT s u m [a]
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return []) ParsecT s u m [a] -> ParsecT s u m [a] -> ParsecT s u m [a]
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> do
        x <- ParsecT s u m a
p
        more <- reluctantlyTill p end
        return $ x:more
      ParsecT s u m [a] -> ParsecT s u m [a] -> ParsecT s u m [a]
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> [a] -> ParsecT s u m [a]
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return []

reluctantlyTill1 :: ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m [a]
reluctantlyTill1 ParsecT s u m a
p ParsecT s u m a
end = do
    ParsecT s u m a -> ParsecT s u m ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 ParsecT s u m a
end
    x <- ParsecT s u m a
p
    more <- reluctantlyTill p end
    return $ x:more

attempting :: ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
attempting ParsecT s u m a
rest ParsecT s u m a
branch =
    (ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT s u m a
branch ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT s u m a
rest) ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m a
rest

orFail :: ParsecT s u m a -> ParsecT s u m String -> ParsecT s u m a
orFail ParsecT s u m a
parser ParsecT s u m String
errorAction =
    ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT s u m a
parser ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (ParsecT s u m String
errorAction ParsecT s u m String
-> (String -> ParsecT s u m a) -> ParsecT s u m a
forall a b.
ParsecT s u m a -> (a -> ParsecT s u m b) -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> ParsecT s u m a
forall a. String -> ParsecT s u m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail)

-- Construct a node with a parser, e.g. T_Literal `withParser` (readGenericLiteral ",")
withParser :: (Id -> t -> b)
-> ParsecT s UserState m t -> ParsecT s UserState m b
withParser Id -> t -> b
node ParsecT s UserState m t
parser = do
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    contents <- parser
    id <- endSpan start
    return $ node id contents

wasIncluded :: ParsecT s u m a -> ParsecT s u m Bool
wasIncluded ParsecT s u m a
p = Bool -> ParsecT s u m Bool -> ParsecT s u m Bool
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option Bool
False (ParsecT s u m a
p ParsecT s u m a -> ParsecT s u m Bool -> ParsecT s u m Bool
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> ParsecT s u m Bool
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True)

acceptButWarn :: ParsecT s u m a
-> Severity -> Integer -> String -> ParsecT s u m ()
acceptButWarn ParsecT s u m a
parser Severity
level Integer
code String
note =
    ParsecT s u m () -> ParsecT s u m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT s u m () -> ParsecT s u m ())
-> ParsecT s u m () -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ ParsecT s u m () -> ParsecT s u m ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (do
        pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        parser
        parseProblemAt pos level code note
      )

parsecBracket :: ParsecT s u m t
-> (t -> ParsecT s u m a)
-> (t -> ParsecT s u m b)
-> ParsecT s u m b
parsecBracket ParsecT s u m t
before t -> ParsecT s u m a
after t -> ParsecT s u m b
op = do
    val <- ParsecT s u m t
before
    op val `thenSkip` after val <|> (after val *> fail "")

swapContext :: [Context] -> ParsecT s u m b -> ParsecT s u m b
swapContext [Context]
contexts ParsecT s u m b
p =
    ParsecT s u m [Context]
-> ([Context] -> ParsecT s u m ())
-> ([Context] -> ParsecT s u m b)
-> ParsecT s u m b
forall {s} {m :: * -> *} {t} {u} {t} {a} {b}.
Stream s m t =>
ParsecT s u m t
-> (t -> ParsecT s u m a)
-> (t -> ParsecT s u m b)
-> ParsecT s u m b
parsecBracket (ParsecT s u m [Context]
forall {m :: * -> *}. MonadState SystemState m => m [Context]
getCurrentContexts ParsecT s u m [Context]
-> ParsecT s u m () -> ParsecT s u m [Context]
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* [Context] -> ParsecT s u m ()
forall {m :: * -> *}. MonadState SystemState m => [Context] -> m ()
setCurrentContexts [Context]
contexts)
                  [Context] -> ParsecT s u m ()
forall {m :: * -> *}. MonadState SystemState m => [Context] -> m ()
setCurrentContexts
                  (ParsecT s u m b -> [Context] -> ParsecT s u m b
forall a b. a -> b -> a
const ParsecT s u m b
p)

withContext :: Context -> ParsecT s u m b -> ParsecT s u m b
withContext Context
entry ParsecT s u m b
p = ParsecT s u m ()
-> (() -> ParsecT s u m (Maybe Context))
-> (() -> ParsecT s u m b)
-> ParsecT s u m b
forall {s} {m :: * -> *} {t} {u} {t} {a} {b}.
Stream s m t =>
ParsecT s u m t
-> (t -> ParsecT s u m a)
-> (t -> ParsecT s u m b)
-> ParsecT s u m b
parsecBracket (Context -> ParsecT s u m ()
forall {m :: * -> *}. MonadState SystemState m => Context -> m ()
pushContext Context
entry) (ParsecT s u m (Maybe Context)
-> () -> ParsecT s u m (Maybe Context)
forall a b. a -> b -> a
const ParsecT s u m (Maybe Context)
forall {m :: * -> *}. MonadState SystemState m => m (Maybe Context)
popContext) (ParsecT s u m b -> () -> ParsecT s u m b
forall a b. a -> b -> a
const ParsecT s u m b
p)

called :: String -> ParsecT s u m b -> ParsecT s u m b
called String
s ParsecT s u m b
p = do
    pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    withContext (ContextName pos s) p

withAnnotations :: [Annotation] -> ParsecT s u m b -> ParsecT s u m b
withAnnotations [Annotation]
anns ParsecT s u m b
p =
    if [Annotation] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Annotation]
anns then ParsecT s u m b
p else Context -> ParsecT s u m b -> ParsecT s u m b
forall {s} {m :: * -> *} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
Context -> ParsecT s u m b -> ParsecT s u m b
withContext ([Annotation] -> Context
ContextAnnotation [Annotation]
anns) ParsecT s u m b
p

readConditionContents :: Bool -> ParsecT String UserState (SCBase m) Token
readConditionContents Bool
single =
    ParsecT String UserState (SCBase m) Token
readCondContents ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) Token
forall {s} {u} {m :: * -> *} {a} {a}.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`attempting` ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (do
                                pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
                                s <- readVariableName
                                spacing1
                                when (s `elem` commonCommands) $
                                    parseProblemAt pos WarningC 1014 "Use 'if cmd; then ..' to check exit code, or 'if [[ $(cmd) == .. ]]' to check output.")

  where
    spacingOrLf :: ParsecT String UserState (SCBase m) String
spacingOrLf = Bool -> ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) String
condSpacing Bool
True
    condSpacing :: Bool -> ParsecT String UserState (SCBase m) String
condSpacing Bool
required = do
        pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        space <- allspacing
        when (required && null space) $
            parseProblemAt pos ErrorC 1035 "You are missing a required space here."
        when (single && '\n' `elem` space) $
            parseProblemAt pos ErrorC 1080 "When breaking lines in [ ], you need \\ before the linefeed."
        return space

    typ :: ConditionType
typ = if Bool
single then ConditionType
SingleBracket else ConditionType
DoubleBracket
    readCondBinaryOp :: ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readCondBinaryOp = ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) (Token -> Token -> Token)
 -> ParsecT String UserState (SCBase m) (Token -> Token -> Token))
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall a b. (a -> b) -> a -> b
$ do
        ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional ParsecT String UserState (SCBase m) ()
forall {s} {m :: * -> *} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m ()
guardArithmetic
        op <- ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *} {s} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m (Token -> Token -> Token)
getOp
        spacingOrLf
        return op
      where
        flaglessOps :: [String]
flaglessOps = [ String
"==", String
"!=", String
"<=", String
">=", String
"=~", String
">", String
"<", String
"=" ]

        getOp :: ParsecT s UserState m (Token -> Token -> Token)
getOp = do
            start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
            op <- readRegularOrEscaped anyOp
            id <- endSpan start
            return $ TC_Binary id typ op

        anyOp :: ParsecT s u m String
anyOp = ParsecT s u m String
forall {s} {m :: * -> *} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m String
flagOp ParsecT s u m String
-> ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
flaglessOp ParsecT s u m String
-> ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT s u m String
forall a. String -> ParsecT s u m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail
                    String
"Expected comparison operator (don't wrap commands in []/[[]])"
        flagOp :: ParsecT s u m String
flagOp = ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ do
            s <- ParsecT s u m String
forall {s} {m :: * -> *} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m String
readOp
            when (s == "-a" || s == "-o") $ fail "Unexpected operator"
            return s
        flaglessOp :: ParsecT s u m String
flaglessOp =
            [ParsecT s u m String] -> ParsecT s u m String
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice ([ParsecT s u m String] -> ParsecT s u m String)
-> [ParsecT s u m String] -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ (String -> ParsecT s u m String)
-> [String] -> [ParsecT s u m String]
forall a b. (a -> b) -> [a] -> [b]
map (ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m String -> ParsecT s u m String)
-> (String -> ParsecT s u m String)
-> String
-> ParsecT s u m String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string) [String]
flaglessOps

        -- hacks to read quoted operators without having to read a shell word
    readEscaped :: ParsecT s u m String -> ParsecT s u m String
readEscaped ParsecT s u m String
p = ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ ParsecT s u m String
withEscape ParsecT s u m String
-> ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m String
withQuotes
      where
        withEscape :: ParsecT s u m String
withEscape = do
            Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\\'
            String -> String
escaped (String -> String) -> ParsecT s u m String -> ParsecT s u m String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s u m String
p
        withQuotes :: ParsecT s u m String
withQuotes = do
            c <- String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"'\""
            s <- p
            char c
            return $ escaped s
        escaped :: String -> String
escaped String
s = if (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s) String
"<>()" then Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:String
s else String
s

    readRegularOrEscaped :: ParsecT s u m String -> ParsecT s u m String
readRegularOrEscaped ParsecT s u m String
p = ParsecT s u m String -> ParsecT s u m String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String -> ParsecT s u m String
readEscaped ParsecT s u m String
p ParsecT s u m String
-> ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m String
p


    guardArithmetic :: ParsecT s u m ()
guardArithmetic = do
        ParsecT s u m () -> ParsecT s u m ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m () -> ParsecT s u m ())
-> (ParsecT s u m () -> ParsecT s u m ())
-> ParsecT s u m ()
-> ParsecT s u m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT s u m () -> ParsecT s u m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s u m () -> ParsecT s u m ())
-> ParsecT s u m () -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ ParsecT s u m Char -> ParsecT s u m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"+*/%") ParsecT s u m () -> ParsecT s u m () -> ParsecT s u m ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m String -> ParsecT s u m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"- ")
        Severity -> Integer -> String -> ParsecT s u m ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1076 (String -> ParsecT s u m ()) -> String -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$
            if Bool
single
            then String
"Trying to do math? Use e.g. [ $((i/2+7)) -ge 18 ]."
            else String
"Trying to do math? Use e.g. [[ $((i/2+7)) -ge 18 ]]."

    readCondUnaryExp :: ParsecT String UserState (SCBase m) Token
readCondUnaryExp = do
      op <- ParsecT String UserState (SCBase m) (Token -> Token)
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) (Token -> Token)
readCondUnaryOp
      pos <- getPosition
      liftM op readCondWord `orFail` do
          parseProblemAt pos ErrorC 1019 "Expected this to be an argument to the unary condition."
          return "Expected an argument for the unary operator"

    readCondUnaryOp :: ParsecT String UserState (SCBase m) (Token -> Token)
readCondUnaryOp = ParsecT String UserState (SCBase m) (Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token)
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) (Token -> Token)
 -> ParsecT String UserState (SCBase m) (Token -> Token))
-> ParsecT String UserState (SCBase m) (Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token)
forall a b. (a -> b) -> a -> b
$ do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        s <- readOp
        id <- endSpan start
        spacingOrLf
        return $ TC_Unary id typ s

    readOp :: ParsecT s u m String
readOp = ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ do
        Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'-' ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m Char
forall {m :: * -> *} {s} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m Char
weirdDash
        s <- ParsecT s u m Char -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter ParsecT s u m String
-> ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT s u m String
forall a. String -> ParsecT s u m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Expected a test operator"
        return ('-':s)

    weirdDash :: ParsecT s u m Char
weirdDash = do
        pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        oneOf "\x058A\x05BE\x2010\x2011\x2012\x2013\x2014\x2015\xFE63\xFF0D"
        parseProblemAt pos ErrorC 1100
            "This is a unicode dash. Delete and retype as ASCII minus."
        return '-'

    readCondWord :: ParsecT String UserState (SCBase m) Token
readCondWord = do
        ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 (ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> ParsecT String UserState (SCBase m) String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"]"))
        x <- ParsecT String UserState (SCBase m) Token
readNormalWord
        pos <- getPosition
        when (notArrayIndex x && endedWith "]" x && not (x `containsLiteral` "[")) $ do
            parseProblemAt pos ErrorC 1020 $
                "You need a space before the " ++ (if single then "]" else "]]") ++ "."
            fail "Missing space before ]"
        when (single && endedWith ")" x) $ do
            parseProblemAt pos ErrorC 1021
                "You need a space before the \\)"
            fail "Missing space before )"
        void spacing
        return x
      where endedWith :: String -> Token -> Bool
endedWith String
str (T_NormalWord Id
id s :: [Token]
s@(Token
_:[Token]
_)) =
                case [Token] -> Token
forall a. HasCallStack => [a] -> a
last [Token]
s of T_Literal Id
id String
s -> String
str String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` String
s
                               Token
_ -> Bool
False
            endedWith String
_ Token
_ = Bool
False
            notArrayIndex :: Token -> Bool
notArrayIndex (T_NormalWord Id
id s :: [Token]
s@(Token
_:T_Literal Id
_ String
t:[Token]
_)) = String
t String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
"["
            notArrayIndex Token
_ = Bool
True
            containsLiteral :: Token -> String -> Bool
containsLiteral Token
x String
s = String
s String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` Token -> String
onlyLiteralString Token
x

    readCondAndOp :: ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readCondAndOp = (Id -> ConditionType -> String -> Token -> Token -> Token)
-> String
-> Bool
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *} {b}.
Monad m =>
(Id -> ConditionType -> String -> b)
-> String -> Bool -> ParsecT String UserState (SCBase m) b
readAndOrOp Id -> ConditionType -> String -> Token -> Token -> Token
TC_And String
"&&" Bool
False ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (Id -> ConditionType -> String -> Token -> Token -> Token)
-> String
-> Bool
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *} {b}.
Monad m =>
(Id -> ConditionType -> String -> b)
-> String -> Bool -> ParsecT String UserState (SCBase m) b
readAndOrOp Id -> ConditionType -> String -> Token -> Token -> Token
TC_And String
"-a" Bool
True

    readCondOrOp :: ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readCondOrOp = do
        ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional ParsecT String UserState (SCBase m) ()
forall {s} {m :: * -> *} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m ()
guardArithmetic
        (Id -> ConditionType -> String -> Token -> Token -> Token)
-> String
-> Bool
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *} {b}.
Monad m =>
(Id -> ConditionType -> String -> b)
-> String -> Bool -> ParsecT String UserState (SCBase m) b
readAndOrOp Id -> ConditionType -> String -> Token -> Token -> Token
TC_Or String
"||" Bool
False ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (Id -> ConditionType -> String -> Token -> Token -> Token)
-> String
-> Bool
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *} {b}.
Monad m =>
(Id -> ConditionType -> String -> b)
-> String -> Bool -> ParsecT String UserState (SCBase m) b
readAndOrOp Id -> ConditionType -> String -> Token -> Token -> Token
TC_Or String
"-o" Bool
True

    readAndOrOp :: (Id -> ConditionType -> String -> b)
-> String -> Bool -> ParsecT String UserState (SCBase m) b
readAndOrOp Id -> ConditionType -> String -> b
node String
op Bool
requiresSpacing = do
        ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead ParsecT String UserState (SCBase m) Char
forall {m :: * -> *} {s} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m Char
weirdDash
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        x <- try $ string op
        id <- endSpan start
        condSpacing requiresSpacing
        return $ node id typ x

    readCondNullaryOrBinary :: ParsecT String UserState (SCBase m) Token
readCondNullaryOrBinary = do
      start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
      x <- readCondWord `attempting` (do
              pos <- getPosition
              lookAhead (char '[')
              parseProblemAt pos ErrorC 1026 $ if single
                  then "If grouping expressions inside [..], use \\( ..\\)."
                  else "If grouping expressions inside [[..]], use ( .. )."
            )
      id <- endSpan start
      (do
            pos <- getPosition
            isRegex <- regexOperatorAhead
            op <- readCondBinaryOp
            y <- if isRegex
                    then readRegex
                    else  readCondWord <|> (parseProblemAt pos ErrorC 1027 "Expected another argument for this operator." >> mzero)
            return (x `op` y)
          ) <|> ( do
            checkTrailingOp x
            return $ TC_Nullary id typ x
          )

    checkTrailingOp :: Token -> ParsecT String UserState (SCBase m) ()
checkTrailingOp Token
x = Maybe (ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ (Maybe (ParsecT String UserState (SCBase m) ())
 -> ParsecT String UserState (SCBase m) ())
-> Maybe (ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ do
        (T_Literal id str) <- Token -> Maybe Token
getTrailingUnquotedLiteral Token
x
        trailingOp <- find (`isSuffixOf` str) binaryTestOps
        return $ parseProblemAtId id ErrorC 1108 $
            "You need a space before and after the " ++ trailingOp ++ " ."

    readCondGroup :: ParsecT String UserState (SCBase m) Token
readCondGroup = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        pos <- getPosition
        lparen <- try $ readRegularOrEscaped (string "(")
        when (single && lparen == "(") $
            singleWarning pos
        when (not single && lparen == "\\(") $
            doubleWarning pos
        condSpacing single
        x <- readCondContents
        cpos <- getPosition
        rparen <- readRegularOrEscaped (string ")")
        id <- endSpan start
        condSpacing single
        when (single && rparen == ")") $
            singleWarning cpos
        when (not single && rparen == "\\)") $
            doubleWarning cpos
        return $ TC_Group id typ x

      where
        singleWarning :: SourcePos -> m ()
singleWarning SourcePos
pos =
            SourcePos -> Severity -> Integer -> String -> m ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
pos Severity
ErrorC Integer
1028 String
"In [..] you have to escape \\( \\) or preferably combine [..] expressions."
        doubleWarning :: SourcePos -> m ()
doubleWarning SourcePos
pos =
            SourcePos -> Severity -> Integer -> String -> m ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
pos Severity
ErrorC Integer
1029 String
"In [[..]] you shouldn't escape ( or )."


    -- Currently a bit of a hack since parsing rules are obscure
    regexOperatorAhead :: ParsecT s u m Bool
regexOperatorAhead = ParsecT s u m Bool -> ParsecT s u m Bool
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (do
        ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"=~") ParsecT s u m String
-> ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"~=")
        Bool -> ParsecT s u m Bool
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True)
          ParsecT s u m Bool -> ParsecT s u m Bool -> ParsecT s u m Bool
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Bool -> ParsecT s u m Bool
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
    readRegex :: ParsecT String UserState (SCBase m) Token
readRegex = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"regex" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        parts <- many1 readPart
        id <- endSpan start
        void spacing
        return $ T_NormalWord id parts
      where
        readPart :: ParsecT String UserState (SCBase m) Token
readPart = [ParsecT String UserState (SCBase m) Token]
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
            ParsecT String UserState (SCBase m) Token
readGroup,
            ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSingleQuoted,
            ParsecT String UserState (SCBase m) Token
readDoubleQuoted,
            ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpression,
            ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {s} {a}.
(MonadState s m, Stream s m Char) =>
ParsecT s UserState m a -> ParsecT s UserState m Token
readLiteralForParser (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ String -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
String -> ParsecT String UserState (SCBase m) Token
readNormalLiteral String
"( ",
            String -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s}.
Stream s m Char =>
String -> ParsecT s UserState m Token
readLiteralString String
"|",
            ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s}.
Stream s m Char =>
ParsecT s UserState m Token
readGlobLiteral
            ]
        readGlobLiteral :: ParsecT s UserState m Token
readGlobLiteral = do
            start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
            s <- extglobStart <|> oneOf "{}[]$"
            id <- endSpan start
            return $ T_Literal id [s]
        readGroup :: ParsecT String UserState (SCBase m) Token
readGroup = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"regex grouping" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
            start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
            p1 <- readLiteralString "("
            parts <- many (readPart <|> readRegexLiteral)
            p2 <- readLiteralString ")"
            id <- endSpan start
            return $ T_NormalWord id (p1:(parts ++ [p2]))
        readRegexLiteral :: ParsecT String UserState (SCBase m) Token
readRegexLiteral = do
            start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
            str <- readGenericLiteral1 (singleQuote <|> doubleQuotable <|> oneOf "()")
            id <- endSpan start
            return $ T_Literal id str
        readLiteralString :: String -> ParsecT s UserState m Token
readLiteralString String
s = do
            start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
            str <- string s
            id <- endSpan start
            return $ T_Literal id str

    readCondTerm :: ParsecT String UserState (SCBase m) Token
readCondTerm = do
        term <- ParsecT String UserState (SCBase m) Token
readCondNot ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readCondExpr
        condSpacing False
        return term

    readCondNot :: ParsecT String UserState (SCBase m) Token
readCondNot = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        char '!'
        id <- endSpan start
        spacingOrLf
        expr <- readCondExpr
        return $ TC_Unary id typ "!" expr

    readCondExpr :: ParsecT String UserState (SCBase m) Token
readCondExpr =
      ParsecT String UserState (SCBase m) Token
readCondGroup ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readCondUnaryExp ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readCondNullaryOrBinary

    readCondOr :: ParsecT String UserState (SCBase m) Token
readCondOr = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
chainl1 ParsecT String UserState (SCBase m) Token
readCondAnd ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readCondAndOp
    readCondAnd :: ParsecT String UserState (SCBase m) Token
readCondAnd = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
chainl1 ParsecT String UserState (SCBase m) Token
readCondTerm ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readCondOrOp
    readCondContents :: ParsecT String UserState (SCBase m) Token
readCondContents = ParsecT String UserState (SCBase m) Token
readCondOr


prop_a1 :: Bool
prop_a1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
" n++ + ++c"
prop_a2 :: Bool
prop_a2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"$N*4-(3,2)"
prop_a3 :: Bool
prop_a3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"n|=2<<1"
prop_a4 :: Bool
prop_a4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"n &= 2 **3"
prop_a5 :: Bool
prop_a5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"1 |= 4 && n >>= 4"
prop_a6 :: Bool
prop_a6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
" 1 | 2 ||3|4"
prop_a7 :: Bool
prop_a7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"3*2**10"
prop_a8 :: Bool
prop_a8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"3"
prop_a9 :: Bool
prop_a9 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"a^!-b"
prop_a10 :: Bool
prop_a10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"! $?"
prop_a11 :: Bool
prop_a11 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"10#08 * 16#f"
prop_a12 :: Bool
prop_a12 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"\"$((3+2))\" + '37'"
prop_a13 :: Bool
prop_a13 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"foo[9*y+x]++"
prop_a14 :: Bool
prop_a14 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"1+`echo 2`"
prop_a15 :: Bool
prop_a15 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"foo[`echo foo | sed s/foo/4/g` * 3] + 4"
prop_a16 :: Bool
prop_a16 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"$foo$bar"
prop_a17 :: Bool
prop_a17 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"i<(0+(1+1))"
prop_a18 :: Bool
prop_a18 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"a?b:c"
prop_a19 :: Bool
prop_a19 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"\\\n3 +\\\n  2"
prop_a20 :: Bool
prop_a20 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"a ? b ? c : d : e"
prop_a21 :: Bool
prop_a21 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"a ? b : c ? d : e"
prop_a22 :: Bool
prop_a22 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"!!a"
prop_a23 :: Bool
prop_a23 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents String
"~0"
readArithmeticContents :: Monad m => SCParser m Token
readArithmeticContents :: forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents =
    ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSequence
  where
    spacing :: ParsecT String UserState (SCBase m) String
spacing =
        let lf :: ParsecT s u m Char
lf = ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\\\n") ParsecT s u m String -> ParsecT s u m Char -> ParsecT s u m Char
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT s u m Char
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return Char
'\n'
        in ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
whitespace ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
lf)

    splitBy :: ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
splitBy ParsecT String UserState (SCBase m) Token
x [String]
ops = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
chainl1 ParsecT String UserState (SCBase m) Token
x ([String]
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *}.
Monad m =>
[String]
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readBinary [String]
ops)
    readBinary :: [String]
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readBinary [String]
ops = [String]
-> (Id -> String -> Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *} {b}.
Monad m =>
[String]
-> (Id -> String -> b) -> ParsecT String UserState (SCBase m) b
readComboOp [String]
ops Id -> String -> Token -> Token -> Token
TA_Binary
    readComboOp :: [String]
-> (Id -> String -> b) -> ParsecT String UserState (SCBase m) b
readComboOp [String]
op Id -> String -> b
token = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        op <- choice (map (\String
x -> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) String
 -> ParsecT String UserState (SCBase m) String)
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall a b. (a -> b) -> a -> b
$ do
                                        s <- String -> ParsecT String UserState (SCBase m) String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
x
                                        failIfIncompleteOp
                                        return s
                            ) op)
        id <- endSpan start
        spacing
        return $ token id op

    failIfIncompleteOp :: ParsecT s u m ()
failIfIncompleteOp = ParsecT s u m Char -> ParsecT s u m ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 (ParsecT s u m Char -> ParsecT s u m ())
-> ParsecT s u m Char -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"&|<>="

    -- Read binary minus, but also check for -lt, -gt and friends:
    readMinusOp :: ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readMinusOp = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        pos <- getPosition
        try $ do
            char '-'
            failIfIncompleteOp
        optional $ do
            (str, alt) <- lookAhead . choice $ map tryOp [
                ("lt", "<"),
                ("gt", ">"),
                ("le", "<="),
                ("ge", ">="),
                ("eq", "=="),
                ("ne", "!=")
              ]
            parseProblemAt pos ErrorC 1106 $ "In arithmetic contexts, use " ++ alt ++ " instead of -" ++ str
        id <- endSpan start
        spacing
        return $ TA_Binary id "-"
      where
        tryOp :: (String, b) -> ParsecT s UserState m (String, b)
tryOp (String
str, b
alt) = ParsecT s UserState m (String, b)
-> ParsecT s UserState m (String, b)
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s UserState m (String, b)
 -> ParsecT s UserState m (String, b))
-> ParsecT s UserState m (String, b)
-> ParsecT s UserState m (String, b)
forall a b. (a -> b) -> a -> b
$ do
            String -> ParsecT s UserState m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
str
            ParsecT s UserState m String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing1
            (String, b) -> ParsecT s UserState m (String, b)
forall a. a -> ParsecT s UserState m a
forall (m :: * -> *) a. Monad m => a -> m a
return (String
str, b
alt)

    readArrayIndex :: ParsecT String UserState (SCBase m) Token
readArrayIndex = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        char '['
        pos <- getPosition
        middle <- readStringForParser readArithmeticContents
        char ']'
        id <- endSpan start
        return $ T_UnparsedIndex id pos middle

    literal :: String -> ParsecT s UserState m Token
literal String
s = do
        start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        string s
        id <- endSpan start
        return $ T_Literal id s

    readVariable :: ParsecT String UserState (SCBase m) Token
readVariable = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        name <- readVariableName
        indices <- many readArrayIndex
        id <- endSpan start
        spacing
        return $ TA_Variable id name indices

    readExpansion :: ParsecT String UserState (SCBase m) Token
readExpansion = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        pieces <- many1 $ choice [
            readSingleQuoted,
            readDoubleQuoted,
            readNormalDollar,
            readBraced,
            readUnquotedBackTicked,
            literal "#",
            readNormalLiteral "+-*/=%^,]?:"
            ]
        id <- endSpan start
        spacing
        return $ TA_Expansion id pieces

    readGroup :: ParsecT String UserState (SCBase m) Token
readGroup = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        char '('
        s <- readSequence
        char ')'
        id <- endSpan start
        spacing
        return $ TA_Parentesis id s

    readArithTerm :: ParsecT String UserState (SCBase m) Token
readArithTerm = ParsecT String UserState (SCBase m) Token
readGroup ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readVariable ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readExpansion

    readSequence :: ParsecT String UserState (SCBase m) Token
readSequence = do
        ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
spacing
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        l <- readAssignment `sepBy` (char ',' >> spacing)
        id <- endSpan start
        return $ TA_Sequence id l

    readAssignment :: ParsecT String UserState (SCBase m) Token
readAssignment = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
chainr1 ParsecT String UserState (SCBase m) Token
readTrinary ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readAssignmentOp
    readAssignmentOp :: ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readAssignmentOp = [String]
-> (Id -> String -> Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *} {b}.
Monad m =>
[String]
-> (Id -> String -> b) -> ParsecT String UserState (SCBase m) b
readComboOp [String
"=", String
"*=", String
"/=", String
"%=", String
"+=", String
"-=", String
"<<=", String
">>=", String
"&=", String
"^=", String
"|="] Id -> String -> Token -> Token -> Token
TA_Assignment

    readTrinary :: ParsecT String UserState (SCBase m) Token
readTrinary = do
        x <- ParsecT String UserState (SCBase m) Token
readLogicalOr
        do
            start <- startSpan
            string "?"
            spacing
            y <- readTrinary
            string ":"
            spacing
            z <- readTrinary
            id <- endSpan start
            return $ TA_Trinary id x y z
         <|>
          return x

    readLogicalOr :: ParsecT String UserState (SCBase m) Token
readLogicalOr  = ParsecT String UserState (SCBase m) Token
readLogicalAnd ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"||"]
    readLogicalAnd :: ParsecT String UserState (SCBase m) Token
readLogicalAnd = ParsecT String UserState (SCBase m) Token
readBitOr ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"&&"]
    readBitOr :: ParsecT String UserState (SCBase m) Token
readBitOr  = ParsecT String UserState (SCBase m) Token
readBitXor ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"|"]
    readBitXor :: ParsecT String UserState (SCBase m) Token
readBitXor = ParsecT String UserState (SCBase m) Token
readBitAnd ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"^"]
    readBitAnd :: ParsecT String UserState (SCBase m) Token
readBitAnd = ParsecT String UserState (SCBase m) Token
readEquated ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"&"]
    readEquated :: ParsecT String UserState (SCBase m) Token
readEquated = ParsecT String UserState (SCBase m) Token
readCompared ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"==", String
"!="]
    readCompared :: ParsecT String UserState (SCBase m) Token
readCompared = ParsecT String UserState (SCBase m) Token
readShift ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"<=", String
">=", String
"<", String
">"]
    readShift :: ParsecT String UserState (SCBase m) Token
readShift = ParsecT String UserState (SCBase m) Token
readAddition ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"<<", String
">>"]
    readAddition :: ParsecT String UserState (SCBase m) Token
readAddition = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
chainl1 ParsecT String UserState (SCBase m) Token
readMultiplication ([String]
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *}.
Monad m =>
[String]
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readBinary [String
"+"] ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) (Token -> Token -> Token)
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) (Token -> Token -> Token)
readMinusOp)
    readMultiplication :: ParsecT String UserState (SCBase m) Token
readMultiplication = ParsecT String UserState (SCBase m) Token
readExponential ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"*", String
"/", String
"%"]
    readExponential :: ParsecT String UserState (SCBase m) Token
readExponential = ParsecT String UserState (SCBase m) Token
readAnyNegated ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
-> [String] -> ParsecT String UserState (SCBase m) Token
`splitBy` [String
"**"]

    readAnyNegated :: ParsecT String UserState (SCBase m) Token
readAnyNegated = ParsecT String UserState (SCBase m) Token
readNegated ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readAnySigned
    readNegated :: ParsecT String UserState (SCBase m) Token
readNegated = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        op <- oneOf "!~"
        id <- endSpan start
        spacing
        x <- readAnyNegated
        return $ TA_Unary id [op] x

    readAnySigned :: ParsecT String UserState (SCBase m) Token
readAnySigned = ParsecT String UserState (SCBase m) Token
readSigned ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readAnycremented
    readSigned :: ParsecT String UserState (SCBase m) Token
readSigned = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        op <- choice (map readSignOp "+-")
        id <- endSpan start
        spacing
        x <- readAnycremented
        return $ TA_Unary id [op] x
     where
        readSignOp :: Char -> ParsecT String UserState (SCBase m) Char
readSignOp Char
c = ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) Char)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall a b. (a -> b) -> a -> b
$ do
            Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
c
            ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
c
            ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
spacing
            Char -> ParsecT String UserState (SCBase m) Char
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Char
c

    readAnycremented :: ParsecT String UserState (SCBase m) Token
readAnycremented = ParsecT String UserState (SCBase m) Token
readNormalOrPostfixIncremented ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readPrefixIncremented
    readPrefixIncremented :: ParsecT String UserState (SCBase m) Token
readPrefixIncremented = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        op <- try $ string "++" <|> string "--"
        id <- endSpan start
        spacing
        x <- readArithTerm
        return $ TA_Unary id (op ++ "|") x

    readNormalOrPostfixIncremented :: ParsecT String UserState (SCBase m) Token
readNormalOrPostfixIncremented = do
        x <- ParsecT String UserState (SCBase m) Token
readArithTerm
        spacing
        do
            start <- startSpan
            op <- try $ string "++" <|> string "--"
            id <- endSpan start
            spacing
            return $ TA_Unary id ('|':op) x
         <|>
            return x



prop_readCondition :: Bool
prop_readCondition   = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[ \\( a = b \\) -a \\( c = d \\) ]"
prop_readCondition2 :: Bool
prop_readCondition2  = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ (a = b) || (c = d) ]]"
prop_readCondition3 :: Bool
prop_readCondition3  = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $c = [[:alpha:].~-] ]]"
prop_readCondition4 :: Bool
prop_readCondition4  = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $c =~ *foo* ]]"
prop_readCondition5 :: Bool
prop_readCondition5  = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $c =~ f( ]] )* ]]"
prop_readCondition5a :: Bool
prop_readCondition5a = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $c =~ a(b) ]]"
prop_readCondition5b :: Bool
prop_readCondition5b = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $c =~ f( ($var ]]) )* ]]"
prop_readCondition6 :: Bool
prop_readCondition6  = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $c =~ ^[yY]$ ]]"
prop_readCondition7 :: Bool
prop_readCondition7  = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ ${line} =~ ^[[:space:]]*# ]]"
prop_readCondition8 :: Bool
prop_readCondition8  = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $l =~ ogg|flac ]]"
prop_readCondition9 :: Bool
prop_readCondition9  = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[ foo -a -f bar ]"
prop_readCondition10 :: Bool
prop_readCondition10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[\na == b\n||\nc == d ]]"
prop_readCondition10a :: Bool
prop_readCondition10a = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[\na == b  ||\nc == d ]]"
prop_readCondition10b :: Bool
prop_readCondition10b = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ a == b\n||\nc == d ]]"
prop_readCondition11 :: Bool
prop_readCondition11 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ a == b ||\n c == d ]]"
prop_readCondition12 :: Bool
prop_readCondition12 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[ a == b \n -o c == d ]"
prop_readCondition13 :: Bool
prop_readCondition13 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ foo =~ ^fo{1,3}$ ]]"
prop_readCondition14 :: Bool
prop_readCondition14 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[ foo '>' bar ]"
prop_readCondition15 :: Bool
prop_readCondition15 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[ foo \">=\" bar ]"
prop_readCondition16 :: Bool
prop_readCondition16 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[ foo \\< bar ]"
prop_readCondition17 :: Bool
prop_readCondition17 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ ${file::1} = [-.\\|/\\\\] ]]"
prop_readCondition18 :: Bool
prop_readCondition18 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[ ]"
prop_readCondition19 :: Bool
prop_readCondition19 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[ '(' x \")\" ]"
prop_readCondition20 :: Bool
prop_readCondition20 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ echo_rc -eq 0 ]]"
prop_readCondition21 :: Bool
prop_readCondition21 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $1 =~ ^(a\\ b)$ ]]"
prop_readCondition22 :: Bool
prop_readCondition22 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ $1 =~ \\.a\\.(\\.b\\.)\\.c\\. ]]"
prop_readCondition23 :: Bool
prop_readCondition23 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ -v arr[$var] ]]"
prop_readCondition25 :: Bool
prop_readCondition25 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ lex.yy.c -ot program.l ]]"
prop_readCondition26 :: Bool
prop_readCondition26 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"[[ foo ]]\\\n && bar"
prop_readCondition27 :: Bool
prop_readCondition27 = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readConditionCommand String
"[[ x ]] foo"
prop_readCondition28 :: Bool
prop_readCondition28 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ x = [\"$1\"] ]]"
prop_readCondition29 :: Bool
prop_readCondition29 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCondition String
"[[ x = [*] ]]"

readCondition :: ParsecT String UserState (SCBase m) Token
readCondition = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"test expression" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    opos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    start <- startSpan
    open <- try (string "[[") <|> string "["
    let single = String
open String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"["
    let typ = if Bool
single then ConditionType
SingleBracket else ConditionType
DoubleBracket

    pos <- getPosition
    space <- allspacing
    when (null space) $
        parseProblemAtWithEnd opos pos ErrorC 1035 $ "You need a space after the " ++
            if single
                then "[ and before the ]."
                else "[[ and before the ]]."
    when (single && '\n' `elem` space) $
        parseProblemAt pos ErrorC 1080 "You need \\ before line feeds to break lines in [ ]."

    condition <- readConditionContents single <|> do
        guard . not . null $ space
        lookAhead $ string "]"
        id <- endSpan start
        return $ TC_Empty id typ

    cpos <- getPosition
    close <- try (string "]]") <|> string "]" <|> fail "Expected test to end here (don't wrap commands in []/[[]])"
    id <- endSpan start
    when (open == "[[" && close /= "]]") $ parseProblemAt cpos ErrorC 1033 "Test expression was opened with double [[ but closed with single ]. Make sure they match."
    when (open == "[" && close /= "]" ) $ parseProblemAt opos ErrorC 1034 "Test expression was opened with single [ but closed with double ]]. Make sure they match."
    spacing
    return $ T_Condition id typ condition

readAnnotationPrefix :: ParsecT s UserState m String
readAnnotationPrefix = do
    Char -> ParsecT s UserState m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'#'
    ParsecT s UserState m Char -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT s UserState m Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
linewhitespace
    String -> ParsecT s UserState m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"shellcheck"

prop_readAnnotation1 :: Bool
prop_readAnnotation1 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck disable=1234,5678\n"
prop_readAnnotation2 :: Bool
prop_readAnnotation2 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck disable=SC1234 disable=SC5678\n"
prop_readAnnotation3 :: Bool
prop_readAnnotation3 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck disable=SC1234 source=/dev/null disable=SC5678\n"
prop_readAnnotation4 :: Bool
prop_readAnnotation4 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck cats=dogs disable=SC1234\n"
prop_readAnnotation5 :: Bool
prop_readAnnotation5 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck disable=SC2002 # All cats are precious\n"
prop_readAnnotation6 :: Bool
prop_readAnnotation6 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck disable=SC1234 # shellcheck foo=bar\n"
prop_readAnnotation7 :: Bool
prop_readAnnotation7 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck disable=SC1000,SC2000-SC3000,SC1001\n"
prop_readAnnotation8 :: Bool
prop_readAnnotation8 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck disable=all\n"
prop_readAnnotation9 :: Bool
prop_readAnnotation9 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck source='foo bar' source-path=\"baz etc\"\n"
prop_readAnnotation10 :: Bool
prop_readAnnotation10 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation String
"# shellcheck disable='SC1234,SC2345' enable=\"foo\" shell='bash'\n"
prop_readAnnotation11 :: Bool
prop_readAnnotation11 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk (Bool -> ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) [Annotation]
readAnnotationWithoutPrefix Bool
False) String
"external-sources='true'"

readAnnotation :: ParsecT String UserState (SCBase m) [Annotation]
readAnnotation = String
-> ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [Annotation]
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"shellcheck directive" (ParsecT String UserState (SCBase m) [Annotation]
 -> ParsecT String UserState (SCBase m) [Annotation])
-> ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [Annotation]
forall a b. (a -> b) -> a -> b
$ do
    ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
readAnnotationPrefix
    ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT String UserState (SCBase m) Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
linewhitespace
    Bool -> ParsecT String UserState (SCBase m) [Annotation]
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) [Annotation]
readAnnotationWithoutPrefix Bool
True

readAnnotationWithoutPrefix :: Bool -> ParsecT String UserState (SCBase m) [Annotation]
readAnnotationWithoutPrefix Bool
sandboxed = do
    values <- ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [[Annotation]]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT String UserState (SCBase m) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readKey
    optional readAnyComment
    void linefeed <|> eof <|> do
        parseNote ErrorC 1125 "Invalid key=value pair? Ignoring the rest of this directive starting here."
        many (noneOf "\n")
        void linefeed <|> eof
    many linewhitespace
    return $ concat values
  where
    plainOrQuoted :: ParsecT String u m a -> ParsecT String u m a
plainOrQuoted ParsecT String u m a
p = ParsecT String u m a -> ParsecT String u m a
forall {m :: * -> *} {u} {b}.
Monad m =>
ParsecT String u m b -> ParsecT String u m b
quoted ParsecT String u m a
p ParsecT String u m a
-> ParsecT String u m a -> ParsecT String u m a
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String u m a
p
    quoted :: ParsecT String u m b -> ParsecT String u m b
quoted ParsecT String u m b
p = do
        c <- String -> ParsecT String u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"'\""
        start <- getPosition
        str <- many1 $ noneOf (c:"\n")
        char c <|> fail "Missing terminating quote for directive."
        subParse start p str
    readKey :: ParsecT String UserState (SCBase m) [Annotation]
readKey = do
        keyPos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        key <- many1 (letter <|> char '-')
        char '=' <|> fail "Expected '=' after directive key"
        annotations <- case key of
            String
"disable" -> ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [Annotation]
forall {m :: * -> *} {u} {b}.
Monad m =>
ParsecT String u m b -> ParsecT String u m b
plainOrQuoted (ParsecT String UserState (SCBase m) [Annotation]
 -> ParsecT String UserState (SCBase m) [Annotation])
-> ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [Annotation]
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Annotation
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m Annotation
readElement ParsecT String UserState (SCBase m) Annotation
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) [Annotation]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
`sepBy` Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
','
              where
                readElement :: ParsecT s u m Annotation
readElement = ParsecT s u m Annotation
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m Annotation
readRange ParsecT s u m Annotation
-> ParsecT s u m Annotation -> ParsecT s u m Annotation
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m Annotation
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m Annotation
readAll
                readAll :: ParsecT s u m Annotation
readAll = do
                    String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"all"
                    Annotation -> ParsecT s u m Annotation
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Annotation -> ParsecT s u m Annotation)
-> Annotation -> ParsecT s u m Annotation
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Annotation
DisableComment Integer
0 Integer
1000000
                readRange :: ParsecT s u m Annotation
readRange = do
                    from <- ParsecT s u m Integer
forall {s} {m :: * -> *} {b} {u}.
(Stream s m Char, Read b) =>
ParsecT s u m b
readCode
                    to <- choice [ char '-' *> readCode, return $ from+1 ]
                    return $ DisableComment from to
                readCode :: ParsecT s u m b
readCode = do
                    ParsecT s u m String -> ParsecT s u m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT s u m String -> ParsecT s u m ())
-> ParsecT s u m String -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"SC"
                    int <- ParsecT s u m Char -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit
                    return $ read int

            String
"enable" -> ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [Annotation]
forall {m :: * -> *} {u} {b}.
Monad m =>
ParsecT String u m b -> ParsecT String u m b
plainOrQuoted (ParsecT String UserState (SCBase m) [Annotation]
 -> ParsecT String UserState (SCBase m) [Annotation])
-> ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [Annotation]
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Annotation
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m Annotation
readName ParsecT String UserState (SCBase m) Annotation
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) [Annotation]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
`sepBy` Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
','
              where
                readName :: ParsecT s u m Annotation
readName = String -> Annotation
EnableComment (String -> Annotation)
-> ParsecT s u m String -> ParsecT s u m Annotation
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s u m Char -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'-')

            String
"source" -> do
                filename <- ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {u} {b}.
Monad m =>
ParsecT String u m b -> ParsecT String u m b
quoted (ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar) ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) String)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
" \n")
                return [SourceOverride filename]

            String
"source-path" -> do
                dirname <- ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {u} {b}.
Monad m =>
ParsecT String u m b -> ParsecT String u m b
quoted (ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar) ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) String)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
" \n")
                return [SourcePath dirname]

            String
"shell" -> do
                pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
                shell <- quoted (many1 anyChar) <|> (many1 $ noneOf " \n")
                when (isNothing $ shellForExecutable shell) $
                    parseNoteAt pos ErrorC 1103
                        "This shell type is unknown. Use e.g. sh or bash."
                return [ShellOverride shell]

            String
"extended-analysis" -> do
                pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
                value <- plainOrQuoted $ many1 letter
                case value of
                    String
"true" -> [Annotation] -> ParsecT String UserState (SCBase m) [Annotation]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return [Bool -> Annotation
ExtendedAnalysis Bool
True]
                    String
"false" -> [Annotation] -> ParsecT String UserState (SCBase m) [Annotation]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return [Bool -> Annotation
ExtendedAnalysis Bool
False]
                    String
_ -> do
                        SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
pos Severity
ErrorC Integer
1146 String
"Unknown extended-analysis value. Expected true/false."
                        [Annotation] -> ParsecT String UserState (SCBase m) [Annotation]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return []

            String
"external-sources" -> do
                pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
                value <- plainOrQuoted $ many1 letter
                case value of
                    String
"true" ->
                        if Bool
sandboxed
                        then do
                            SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
pos Severity
ErrorC Integer
1144 String
"external-sources can only be enabled in .shellcheckrc, not in individual files."
                            [Annotation] -> ParsecT String UserState (SCBase m) [Annotation]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return []
                        else [Annotation] -> ParsecT String UserState (SCBase m) [Annotation]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return [Bool -> Annotation
ExternalSources Bool
True]
                    String
"false" -> [Annotation] -> ParsecT String UserState (SCBase m) [Annotation]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return [Bool -> Annotation
ExternalSources Bool
False]
                    String
_ -> do
                        SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
pos Severity
ErrorC Integer
1145 String
"Unknown external-sources value. Expected true/false."
                        [Annotation] -> ParsecT String UserState (SCBase m) [Annotation]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return []

            String
_ -> do
                SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
keyPos Severity
WarningC Integer
1107 String
"This directive is unknown. It will be ignored."
                ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {t} {u} {a} {a}.
(Stream s m t, Show t) =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m [a]
`reluctantlyTill` ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
whitespace
                [Annotation] -> ParsecT String UserState (SCBase m) [Annotation]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return []

        many linewhitespace
        return annotations

readAnnotations :: ParsecT String UserState (SCBase m) [Annotation]
readAnnotations = do
    annotations <- ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [[Annotation]]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT String UserState (SCBase m) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readAnnotation ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) [Annotation]
forall {s} {m :: * -> *} {t} {u} {a} {a}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`thenSkip` ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing)
    return $ concat annotations

readComment :: ParsecT s UserState m String
readComment = do
    String -> ParsecT s UserState m String -> ParsecT s UserState m ()
forall {s} {u} {m :: * -> *} {a}.
String -> ParsecT s u m a -> ParsecT s u m ()
unexpecting String
"shellcheck annotation" ParsecT s UserState m String
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
readAnnotationPrefix
    ParsecT s UserState m String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readAnyComment

prop_readAnyComment :: Bool
prop_readAnyComment = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readAnyComment String
"# Comment"
readAnyComment :: ParsecT s u m String
readAnyComment = do
    Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'#'
    ParsecT s u m Char -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT s u m Char -> ParsecT s u m String)
-> ParsecT s u m Char -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"\r\n"

prop_readNormalWord :: Bool
prop_readNormalWord = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"'foo'\"bar\"{1..3}baz$(lol)"
prop_readNormalWord2 :: Bool
prop_readNormalWord2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"foo**(foo)!!!(@@(bar))"
prop_readNormalWord3 :: Bool
prop_readNormalWord3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"foo#"
prop_readNormalWord4 :: Bool
prop_readNormalWord4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"$\"foo\"$'foo\nbar'"
prop_readNormalWord5 :: Bool
prop_readNormalWord5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"${foo}}"
prop_readNormalWord6 :: Bool
prop_readNormalWord6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"foo/{}"
prop_readNormalWord7 :: Bool
prop_readNormalWord7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"foo\\\nbar"
prop_readNormalWord8 :: Bool
prop_readNormalWord8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSubshell String
"(foo\\ \nbar)"
prop_readNormalWord9 :: Bool
prop_readNormalWord9 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSubshell String
"(foo\\ ;\nbar)"
prop_readNormalWord10 :: Bool
prop_readNormalWord10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"\x201Chello\x201D"
prop_readNormalWord11 :: Bool
prop_readNormalWord11 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"\x2018hello\x2019"
prop_readNormalWord12 :: Bool
prop_readNormalWord12 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"hello\x2018"
readNormalWord :: ParsecT String UserState (SCBase m) Token
readNormalWord = String -> [String] -> ParsecT String UserState (SCBase m) Token
readNormalishWord String
"" [String
"do", String
"done", String
"then", String
"fi", String
"esac"]

readPatternWord :: ParsecT String UserState (SCBase m) Token
readPatternWord = String -> [String] -> ParsecT String UserState (SCBase m) Token
readNormalishWord String
"" [String
"esac"]

readNormalishWord :: String -> [String] -> ParsecT String UserState (SCBase m) Token
readNormalishWord String
end [String]
terms = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    pos <- getPosition
    x <- many1 (readNormalWordPart end)
    id <- endSpan start
    checkPossibleTermination pos x terms
    return $ T_NormalWord id x

readIndexSpan :: ParsecT String UserState (SCBase m) Token
readIndexSpan = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    x <- many (readNormalWordPart "]" <|> someSpace <|> otherLiteral)
    id <- endSpan start
    return $ T_NormalWord id x
  where
    someSpace :: ParsecT s UserState m Token
someSpace = do
        start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        str <- spacing1
        id <- endSpan start
        return $ T_Literal id str
    otherLiteral :: ParsecT s UserState m Token
otherLiteral = do
        start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        str <- many1 $ oneOf quotableChars
        id <- endSpan start
        return $ T_Literal id str

checkPossibleTermination :: SourcePos -> [Token] -> t String -> f ()
checkPossibleTermination SourcePos
pos [T_Literal Id
_ String
x] t String
terminators =
    Bool -> f () -> f ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (String
x String -> t String -> Bool
forall a. Eq a => a -> t a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` t String
terminators) (f () -> f ()) -> f () -> f ()
forall a b. (a -> b) -> a -> b
$
        SourcePos -> Severity -> Integer -> String -> f ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
pos Severity
WarningC Integer
1010 (String -> f ()) -> String -> f ()
forall a b. (a -> b) -> a -> b
$ String
"Use semicolon or linefeed before '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' (or quote to make it literal)."
checkPossibleTermination SourcePos
_ [Token]
_ t String
_ = () -> f ()
forall a. a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

readNormalWordPart :: String -> ParsecT String UserState (SCBase m) Token
readNormalWordPart String
end = do
    ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
end
    ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {s} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m ()
checkForParenthesis
    [ParsecT String UserState (SCBase m) Token]
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
        ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSingleQuoted,
        ParsecT String UserState (SCBase m) Token
readDoubleQuoted,
        ParsecT String UserState (SCBase m) Token
readGlob,
        ParsecT String UserState (SCBase m) Token
readNormalDollar,
        ParsecT String UserState (SCBase m) Token
readBraced,
        ParsecT String UserState (SCBase m) Token
readUnquotedBackTicked,
        ParsecT String UserState (SCBase m) Token
readProcSub,
        ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readUnicodeQuote,
        String -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
String -> ParsecT String UserState (SCBase m) Token
readNormalLiteral String
end,
        ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
readLiteralCurlyBraces
      ]
  where
    checkForParenthesis :: ParsecT s u m ()
checkForParenthesis =
        () -> ParsecT s u m ()
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return () ParsecT s u m () -> ParsecT s u m () -> ParsecT s u m ()
forall {s} {u} {m :: * -> *} {a} {a}.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`attempting` do
            pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
            lookAhead $ char '('
            parseProblemAt pos ErrorC 1036 "'(' is invalid here. Did you forget to escape it?"

    readLiteralCurlyBraces :: ParsecT s UserState m Token
readLiteralCurlyBraces = do
        start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        str <- findParam <|> literalBraces
        id <- endSpan start
        return $ T_Literal id str

    findParam :: ParsecT s u m String
findParam = ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"{}"
    literalBraces :: ParsecT s u m String
literalBraces = do
        pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        c <- oneOf "{}"
        parseProblemAt pos WarningC 1083 $
            "This " ++ [c] ++ " is literal. Check expression (missing ;/\\n?) or quote it."
        return [c]


readSpacePart :: ParsecT String UserState (SCBase m) Token
readSpacePart = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    x <- many1 whitespace
    id <- endSpan start
    return $ T_Literal id x

readDollarBracedWord :: ParsecT String UserState (SCBase m) Token
readDollarBracedWord = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    list <- many readDollarBracedPart
    id <- endSpan start
    return $ T_NormalWord id list

readDollarBracedPart :: ParsecT String UserState (SCBase m) Token
readDollarBracedPart = ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSingleQuoted ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readDoubleQuoted ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
                       ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s}.
Stream s m Char =>
ParsecT s UserState m Token
readParamSubSpecialChar ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readExtglob ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readNormalDollar ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
                       ParsecT String UserState (SCBase m) Token
readUnquotedBackTicked ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarBracedLiteral

readDollarBracedLiteral :: ParsecT String UserState (SCBase m) Token
readDollarBracedLiteral = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    vars <- (readBraceEscaped <|> ((\Char
x -> [Char
x]) <$> anyChar)) `reluctantlyTill1` bracedQuotable
    id <- endSpan start
    return $ T_Literal id $ concat vars

readParamSubSpecialChar :: ParsecT s UserState m Token
readParamSubSpecialChar = do
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    x <- many1 paramSubSpecialChars
    id <- endSpan start
    return $ T_ParamSubSpecialChar id x

prop_readProcSub1 :: Bool
prop_readProcSub1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readProcSub String
"<(echo test | wc -l)"
prop_readProcSub2 :: Bool
prop_readProcSub2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readProcSub String
"<(  if true; then true; fi )"
prop_readProcSub3 :: Bool
prop_readProcSub3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readProcSub String
"<( # nothing here \n)"
readProcSub :: ParsecT String UserState (SCBase m) Token
readProcSub = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"process substitution" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    dir <- try $ do
                    x <- oneOf "<>"
                    char '('
                    return [x]
    list <- readCompoundListOrEmpty
    allspacing
    char ')'
    id <- endSpan start
    return $ T_ProcSub id dir list

prop_readSingleQuoted :: Bool
prop_readSingleQuoted = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSingleQuoted String
"'foo bar'"
prop_readSingleQuoted2 :: Bool
prop_readSingleQuoted2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSingleQuoted String
"'foo bar\\'"
prop_readSingleQuoted4 :: Bool
prop_readSingleQuoted4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"'it's"
prop_readSingleQuoted5 :: Bool
prop_readSingleQuoted5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"foo='bar\ncow 'arg"
prop_readSingleQuoted6 :: Bool
prop_readSingleQuoted6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"foo='bar cow 'arg"
prop_readSingleQuoted7 :: Bool
prop_readSingleQuoted7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSingleQuoted String
"'foo\x201C\&bar'"
prop_readSingleQuoted8 :: Bool
prop_readSingleQuoted8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSingleQuoted String
"'foo\x2018\&bar'"
readSingleQuoted :: ParsecT String UserState (SCBase m) Token
readSingleQuoted = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"single quoted string" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    startPos <- getPosition
    singleQuote
    s <- many readSingleQuotedPart
    let string = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String]
s
    endPos <- getPosition
    singleQuote <|> fail "Expected end of single quoted string"

    optional $ do
        c <- try . lookAhead $ suspectCharAfterQuotes <|> oneOf "'"
        if not (null string) && isAlpha c && isAlpha (last string)
          then
            parseProblemAt endPos WarningC 1011
                "This apostrophe terminated the single quoted string!"
          else
            when ('\n' `elem` string && not ("\n" `isPrefixOf` string)) $
                suggestForgotClosingQuote startPos endPos "single quoted string"

    id <- endSpan start
    return (T_SingleQuoted id string)

readSingleQuotedLiteral :: ParsecT String UserState (SCBase m) String
readSingleQuotedLiteral = do
    ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
singleQuote
    strs <- ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) [String]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
readSingleQuotedPart
    singleQuote
    return $ concat strs

readSingleQuotedPart :: ParsecT String UserState (SCBase m) String
readSingleQuotedPart =
    ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
readSingleEscaped
    ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf (String -> ParsecT String UserState (SCBase m) Char)
-> String -> ParsecT String UserState (SCBase m) Char
forall a b. (a -> b) -> a -> b
$ String
"'\\" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
unicodeSingleQuotes)
    ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m String
readUnicodeQuote
   where
    readUnicodeQuote :: ParsecT s u m String
readUnicodeQuote = do
        pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        x <- oneOf unicodeSingleQuotes
        parseProblemAt pos WarningC 1112
            "This is a unicode quote. Delete and retype it (or ignore/doublequote for literal)."
        return [x]


prop_readBackTicked :: Bool
prop_readBackTicked = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk (Bool -> ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) Token
readBackTicked Bool
False) String
"`ls *.mp3`"
prop_readBackTicked2 :: Bool
prop_readBackTicked2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk (Bool -> ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) Token
readBackTicked Bool
False) String
"`grep \"\\\"\"`"
prop_readBackTicked3 :: Bool
prop_readBackTicked3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning (Bool -> ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) Token
readBackTicked Bool
False) String
"´grep \"\\\"\"´"
prop_readBackTicked4 :: Bool
prop_readBackTicked4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"`echo foo\necho bar`"
prop_readBackTicked5 :: Bool
prop_readBackTicked5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"echo `foo`bar"
prop_readBackTicked6 :: Bool
prop_readBackTicked6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"echo `foo\necho `bar"
prop_readBackTicked7 :: Bool
prop_readBackTicked7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"`#inline comment`"
prop_readBackTicked8 :: Bool
prop_readBackTicked8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"echo `#comment` \\\nbar baz"
readQuotedBackTicked :: ParsecT String UserState (SCBase m) Token
readQuotedBackTicked = Bool -> ParsecT String UserState (SCBase m) Token
readBackTicked Bool
True
readUnquotedBackTicked :: ParsecT String UserState (SCBase m) Token
readUnquotedBackTicked = Bool -> ParsecT String UserState (SCBase m) Token
readBackTicked Bool
False
readBackTicked :: Bool -> ParsecT String UserState (SCBase m) Token
readBackTicked Bool
quoted = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"backtick expansion" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    startPos <- getPosition
    backtick
    subStart <- getPosition
    subString <- readGenericLiteral "`´"
    endPos <- getPosition
    backtick
    id <- endSpan start

    optional $ do
        c <- try . lookAhead $ suspectCharAfterQuotes
        when ('\n' `elem` subString && not ("\n" `isPrefixOf` subString)) $
            suggestForgotClosingQuote startPos endPos "backtick expansion"

    -- Result positions may be off due to escapes
    result <- subParse subStart (tryWithErrors subParser <|> return []) (unEscape subString)
    return $ T_Backticked id result
  where
    unEscape :: String -> String
unEscape [] = []
    unEscape (Char
'\\':Char
'"':String
rest) | Bool
quoted = Char
'"' Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
unEscape String
rest
    unEscape (Char
'\\':Char
x:String
rest) | Char
x Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
"$`\\" = Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
unEscape String
rest
    unEscape (Char
'\\':Char
'\n':String
rest) = String -> String
unEscape String
rest
    unEscape (Char
c:String
rest) = Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
unEscape String
rest
    subParser :: ParsecT String UserState (SCBase m) [Token]
subParser = do
        cmds <- ParsecT String UserState (SCBase m) [Token]
readCompoundListOrEmpty
        verifyEof
        return cmds
    backtick :: ParsecT s u m ()
backtick =
      ParsecT s u m Char -> ParsecT s u m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'`') ParsecT s u m () -> ParsecT s u m () -> ParsecT s u m ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> do
         pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
         char '´'
         parseProblemAt pos ErrorC 1077
            "For command expansion, the tick should slant left (` vs ´). Use $(..) instead."

-- Run a parser on a new input, such as for `..` or here documents.
subParse :: SourcePos -> ParsecT s u m b -> s -> ParsecT s u m b
subParse SourcePos
pos ParsecT s u m b
parser s
input = do
    lastPosition <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    lastInput <- getInput
    setPosition pos
    setInput input
    result <- parser
    setInput lastInput
    setPosition lastPosition
    return result

-- Parse something, but forget all parseProblems
inSeparateContext :: ParsecT s u m b -> ParsecT s u m b
inSeparateContext = Bool -> ParsecT s u m b -> ParsecT s u m b
forall {s} {m :: * -> *} {s} {u} {b}.
MonadState s m =>
Bool -> ParsecT s u m b -> ParsecT s u m b
parseForgettingContext Bool
True
-- Parse something, but forget all parseProblems on failure
forgetOnFailure :: ParsecT s u m b -> ParsecT s u m b
forgetOnFailure = Bool -> ParsecT s u m b -> ParsecT s u m b
forall {s} {m :: * -> *} {s} {u} {b}.
MonadState s m =>
Bool -> ParsecT s u m b -> ParsecT s u m b
parseForgettingContext Bool
False

parseForgettingContext :: Bool -> ParsecT s u m b -> ParsecT s u m b
parseForgettingContext Bool
alsoOnSuccess ParsecT s u m b
parser = do
    context <- ParsecT s u m s
forall s (m :: * -> *). MonadState s m => m s
Ms.get
    success context <|> failure context
  where
    success :: s -> ParsecT s u m b
success s
c = do
        res <- ParsecT s u m b -> ParsecT s u m b
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT s u m b
parser
        when alsoOnSuccess $ Ms.put c
        return res
    failure :: s -> m b
failure s
c = do
        s -> m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
Ms.put s
c
        String -> m b
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
""

prop_readDoubleQuoted :: Bool
prop_readDoubleQuoted = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDoubleQuoted String
"\"Hello $FOO\""
prop_readDoubleQuoted2 :: Bool
prop_readDoubleQuoted2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDoubleQuoted String
"\"$'\""
prop_readDoubleQuoted3 :: Bool
prop_readDoubleQuoted3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDoubleQuoted String
"\"\x2018hello\x2019\""
prop_readDoubleQuoted4 :: Bool
prop_readDoubleQuoted4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"\"foo\nbar\"foo"
prop_readDoubleQuoted5 :: Bool
prop_readDoubleQuoted5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"lol \"foo\nbar\" etc"
prop_readDoubleQuoted6 :: Bool
prop_readDoubleQuoted6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"echo \"${ ls; }\""
prop_readDoubleQuoted7 :: Bool
prop_readDoubleQuoted7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"echo \"${ ls;}bar\""
prop_readDoubleQuoted8 :: Bool
prop_readDoubleQuoted8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDoubleQuoted String
"\"\x201Chello\x201D\""
prop_readDoubleQuoted10 :: Bool
prop_readDoubleQuoted10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDoubleQuoted String
"\"foo\\\\n\""
readDoubleQuoted :: ParsecT String UserState (SCBase m) Token
readDoubleQuoted = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"double quoted string" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    startPos <- getPosition
    doubleQuote
    x <- many doubleQuotedPart
    endPos <- getPosition
    doubleQuote <|> fail "Expected end of double quoted string"
    id <- endSpan start
    optional $ do
        try . lookAhead $ suspectCharAfterQuotes <|> oneOf "$\""
        when (any hasLineFeed x && not (startsWithLineFeed x)) $
            suggestForgotClosingQuote startPos endPos "double quoted string"
    return $ T_DoubleQuoted id x
  where
    startsWithLineFeed :: [Token] -> Bool
startsWithLineFeed (T_Literal Id
_ (Char
'\n':String
_):[Token]
_) = Bool
True
    startsWithLineFeed [Token]
_ = Bool
False
    hasLineFeed :: Token -> Bool
hasLineFeed (T_Literal Id
_ String
str) | Char
'\n' Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
str = Bool
True
    hasLineFeed Token
_ = Bool
False

suggestForgotClosingQuote :: SourcePos -> SourcePos -> String -> m ()
suggestForgotClosingQuote SourcePos
startPos SourcePos
endPos String
name = do
    SourcePos -> Severity -> Integer -> String -> m ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
startPos Severity
WarningC Integer
1078 (String -> m ()) -> String -> m ()
forall a b. (a -> b) -> a -> b
$
        String
"Did you forget to close this " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"?"
    SourcePos -> Severity -> Integer -> String -> m ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
endPos Severity
InfoC Integer
1079
        String
"This is actually an end quote, but due to next char it looks suspect."

doubleQuotedPart :: ParsecT String UserState (SCBase m) Token
doubleQuotedPart = ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDoubleLiteral ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readDoubleQuotedDollar ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readQuotedBackTicked ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
readUnicodeQuote
  where
    readUnicodeQuote :: ParsecT s UserState m Token
readUnicodeQuote = do
        pos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        start <- startSpan
        c <- oneOf unicodeDoubleQuotes
        id <- endSpan start
        parseProblemAt pos WarningC 1111
            "This is a unicode quote. Delete and retype it (or ignore/singlequote for literal)."
        return $ T_Literal id [c]

readDoubleLiteral :: ParsecT String UserState (SCBase m) Token
readDoubleLiteral = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    s <- many1 readDoubleLiteralPart
    id <- endSpan start
    return $ T_Literal id (concat s)

readDoubleLiteralPart :: ParsecT String UserState (SCBase m) String
readDoubleLiteralPart = do
    x <- ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) [String]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
readDoubleEscaped ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf (String
doubleQuotableChars String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
unicodeDoubleQuotes)))
    return $ concat x

readNormalLiteral :: String -> ParsecT String UserState (SCBase m) Token
readNormalLiteral String
end = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    s <- many1 (readNormalLiteralPart end)
    id <- endSpan start
    return $ T_Literal id (concat s)

prop_readGlob1 :: Bool
prop_readGlob1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"*"
prop_readGlob2 :: Bool
prop_readGlob2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[^0-9]"
prop_readGlob3 :: Bool
prop_readGlob3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[a[:alpha:]]"
prop_readGlob4 :: Bool
prop_readGlob4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[[:alnum:]]"
prop_readGlob5 :: Bool
prop_readGlob5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[^[:alpha:]1-9]"
prop_readGlob6 :: Bool
prop_readGlob6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[\\|]"
prop_readGlob7 :: Bool
prop_readGlob7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[^[]"
prop_readGlob8 :: Bool
prop_readGlob8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[*?]"
prop_readGlob9 :: Bool
prop_readGlob9 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[!]^]"
prop_readGlob10 :: Bool
prop_readGlob10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readGlob String
"[]]"
readGlob :: ParsecT String UserState (SCBase m) Token
readGlob = ParsecT String UserState (SCBase m) Token
readExtglob ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s}.
Stream s m Char =>
ParsecT s UserState m Token
readSimple ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readClass ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s}.
Stream s m Char =>
ParsecT s UserState m Token
readGlobbyLiteral
    where
        readSimple :: ParsecT s UserState m Token
readSimple = do
            start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
            c <- oneOf "*?"
            id <- endSpan start
            return $ T_Glob id [c]
        readClass :: ParsecT String UserState (SCBase m) Token
readClass = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
            start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
            char '['
            negation <- charToString (oneOf "!^") <|> return ""
            leadingBracket <- charToString (oneOf "]") <|> return ""
            s <- many (predefined <|> readNormalLiteralPart "]" <|> globchars)
            guard $ not (null leadingBracket) || not (null s)
            char ']'
            id <- endSpan start
            return $ T_Glob id $ "[" ++ concat (negation:leadingBracket:s) ++ "]"
          where
           globchars :: ParsecT s u m (m Char)
globchars = ParsecT s u m Char -> ParsecT s u m (m Char)
forall {m :: * -> *} {f :: * -> *} {a}.
(Monad m, Functor f) =>
f a -> f (m a)
charToString (ParsecT s u m Char -> ParsecT s u m (m Char))
-> ParsecT s u m Char -> ParsecT s u m (m Char)
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf (String -> ParsecT s u m Char) -> String -> ParsecT s u m Char
forall a b. (a -> b) -> a -> b
$ String
"![" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
extglobStartChars
           predefined :: ParsecT s u m String
predefined = do
              ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"[:"
              s <- ParsecT s u m Char -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter
              string ":]"
              return $ "[:" ++ s ++ ":]"

        charToString :: f a -> f (m a)
charToString = (a -> m a) -> f a -> f (m a)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return
        readGlobbyLiteral :: ParsecT s UserState m Token
readGlobbyLiteral = do
            start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
            c <- extglobStart <|> char '['
            id <- endSpan start
            return $ T_Literal id [c]

readNormalLiteralPart :: String -> ParsecT String UserState (SCBase m) String
readNormalLiteralPart String
customEnd =
    ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
readNormalEscaped ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
        ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf (String
customEnd String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
standardEnd))
  where
    standardEnd :: String
standardEnd = String
"[{}"
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
quotableChars
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
extglobStartChars
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
unicodeDoubleQuotes
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
unicodeSingleQuotes

readNormalEscaped :: ParsecT String UserState (SCBase m) String
readNormalEscaped = String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"escaped char" (ParsecT String UserState (SCBase m) String
 -> ParsecT String UserState (SCBase m) String)
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall a b. (a -> b) -> a -> b
$ do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    backslash
    do
        next <- quotable <|> oneOf "?*@!+[]{}.,~#"
        when (next == ' ') $ checkTrailingSpaces pos <|> return ()
        -- Check if this line is followed by a commented line with a trailing backslash
        when (next == '\n') $ try . lookAhead $ void spacing
        return $ if next == '\n' then "" else [next]
      <|>
        do
            next <- anyChar
            case escapedChar next of
                Just String
name -> SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
pos Severity
WarningC Integer
1012 (String -> ParsecT String UserState (SCBase m) ())
-> String -> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ String
"\\" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
next] String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is just literal '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
next] String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' here. For " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", use " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Char -> String
alternative Char
next String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" instead."
                Maybe String
Nothing -> SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
pos Severity
InfoC Integer
1001 (String -> ParsecT String UserState (SCBase m) ())
-> String -> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ String
"This \\" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
next] String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" will be a regular '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
next] String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' in this context."
            return [next]
  where
    alternative :: Char -> String
alternative Char
'n' = String
"a quoted, literal line feed"
    alternative Char
t = String
"\"$(printf '\\" String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
t] String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"')\""
    escapedChar :: Char -> Maybe String
escapedChar Char
'n' = String -> Maybe String
forall a. a -> Maybe a
Just String
"line feed"
    escapedChar Char
't' = String -> Maybe String
forall a. a -> Maybe a
Just String
"tab"
    escapedChar Char
'r' = String -> Maybe String
forall a. a -> Maybe a
Just String
"carriage return"
    escapedChar Char
_ = Maybe String
forall a. Maybe a
Nothing

    checkTrailingSpaces :: SourcePos -> ParsecT String UserState (SCBase m) ()
checkTrailingSpaces SourcePos
pos = ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> (ParsecT String UserState (SCBase m) ()
    -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ do
        ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT String UserState (SCBase m) Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
linewhitespace
        ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
linefeed ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof
        SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
pos Severity
ErrorC Integer
1101 String
"Delete trailing spaces after \\ to break line (or use quotes for literal space)."


prop_readExtglob1 :: Bool
prop_readExtglob1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readExtglob String
"!(*.mp3)"
prop_readExtglob2 :: Bool
prop_readExtglob2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readExtglob String
"!(*.mp3|*.wmv)"
prop_readExtglob4 :: Bool
prop_readExtglob4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readExtglob String
"+(foo \\) bar)"
prop_readExtglob5 :: Bool
prop_readExtglob5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readExtglob String
"+(!(foo *(bar)))"
prop_readExtglob6 :: Bool
prop_readExtglob6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readExtglob String
"*(((||))|())"
prop_readExtglob7 :: Bool
prop_readExtglob7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readExtglob String
"*(<>)"
prop_readExtglob8 :: Bool
prop_readExtglob8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readExtglob String
"@(|*())"
readExtglob :: ParsecT String UserState (SCBase m) Token
readExtglob = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"extglob" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    c <- try $ do
            f <- extglobStart
            char '('
            return f
    contents <- readExtglobPart `sepBy` char '|'
    char ')'
    id <- endSpan start
    return $ T_Extglob id [c] contents

readExtglobPart :: ParsecT String UserState (SCBase m) Token
readExtglobPart = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    x <- many (readExtglobGroup <|> readNormalWordPart "" <|> readSpacePart <|> readExtglobLiteral)
    id <- endSpan start
    return $ T_NormalWord id x
  where
    readExtglobGroup :: ParsecT String UserState (SCBase m) Token
readExtglobGroup = do
        Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'('
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        contents <- readExtglobPart `sepBy` char '|'
        id <- endSpan start
        char ')'
        return $ T_Extglob id "" contents
    readExtglobLiteral :: ParsecT s UserState m Token
readExtglobLiteral = do
        start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        str <- many1 (oneOf "<>#;&")
        id <- endSpan start
        return $ T_Literal id str


readSingleEscaped :: ParsecT String UserState (SCBase m) String
readSingleEscaped = do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    s <- backslash
    x <- lookAhead anyChar

    case x of
        Char
'\'' -> SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
pos Severity
InfoC Integer
1003 String
"Want to escape a single quote? echo 'This is how it'\\''s done'.";
        Char
_ -> () -> ParsecT String UserState (SCBase m) ()
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

    return [s]

readDoubleEscaped :: ParsecT String UserState (SCBase m) String
readDoubleEscaped = do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    bs <- backslash
    (linefeed >> return "")
        <|> fmap return doubleQuotable
        <|> do
            c <- anyChar
            -- This is an invalid escape sequence where the \ is literal.
            -- Previously this caused a SC1117, which may be re-enabled as
            -- as a pedantic warning.
            return [bs, c]

readBraceEscaped :: ParsecT String UserState (SCBase m) String
readBraceEscaped = do
    bs <- SCParser m Char
forall (m :: * -> *). Monad m => SCParser m Char
backslash
    (linefeed >> return "")
        <|> fmap return bracedQuotable
        <|> fmap (\ Char
x -> [Char
bs, Char
x]) anyChar


readGenericLiteral :: String -> ParsecT String UserState (SCBase m) String
readGenericLiteral String
endChars = do
    strings <- ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) [String]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
readGenericEscaped ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf (Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:String
endChars)))
    return $ concat strings

readGenericLiteral1 :: ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) String
readGenericLiteral1 ParsecT String UserState (SCBase m) a
endExp = do
    strings <- (ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
readGenericEscaped ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ((\Char
x -> [Char
x]) (Char -> String)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar)) ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) [String]
forall {s} {m :: * -> *} {t} {u} {a} {a}.
(Stream s m t, Show t) =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m [a]
`reluctantlyTill1` ParsecT String UserState (SCBase m) a
endExp
    return $ concat strings

readGenericEscaped :: ParsecT String UserState (SCBase m) String
readGenericEscaped = do
    SCParser m Char
forall (m :: * -> *). Monad m => SCParser m Char
backslash
    x <- SCParser m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar
    return $ if x == '\n' then [] else ['\\', x]

prop_readBraced :: Bool
prop_readBraced = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraced String
"{1..4}"
prop_readBraced2 :: Bool
prop_readBraced2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraced String
"{foo,bar,\"baz lol\"}"
prop_readBraced3 :: Bool
prop_readBraced3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraced String
"{1,\\},2}"
prop_readBraced4 :: Bool
prop_readBraced4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraced String
"{1,{2,3}}"
prop_readBraced5 :: Bool
prop_readBraced5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraced String
"{JP{,E}G,jp{,e}g}"
prop_readBraced6 :: Bool
prop_readBraced6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraced String
"{foo,bar,$((${var}))}"
prop_readBraced7 :: Bool
prop_readBraced7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraced String
"{}"
prop_readBraced8 :: Bool
prop_readBraced8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraced String
"{foo}"
readBraced :: ParsecT String UserState (SCBase m) Token
readBraced = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT String UserState (SCBase m) Token
braceExpansion
  where
    braceExpansion :: ParsecT String UserState (SCBase m) Token
braceExpansion =
        Id -> [Token] -> Token
T_BraceExpansion (Id -> [Token] -> Token)
-> ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {t} {b} {s}.
Monad m =>
(Id -> t -> b)
-> ParsecT s UserState m t -> ParsecT s UserState m b
`withParser` do
            Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'{'
            elements <- ParsecT String UserState (SCBase m) Token
bracedElement ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) [Token]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
`sepBy1` Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
','
            guard $
                case elements of
                    (Token
_:Token
_:[Token]
_) -> Bool
True
                    [Token
t] -> String
".." String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` Token -> String
onlyLiteralString Token
t
                    [] -> Bool
False
            char '}'
            return elements
    bracedElement :: ParsecT String UserState (SCBase m) Token
bracedElement =
        Id -> [Token] -> Token
T_NormalWord (Id -> [Token] -> Token)
-> ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {t} {b} {s}.
Monad m =>
(Id -> t -> b)
-> ParsecT s UserState m t -> ParsecT s UserState m b
`withParser` do
            ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) [Token])
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall a b. (a -> b) -> a -> b
$ [ParsecT String UserState (SCBase m) Token]
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
                ParsecT String UserState (SCBase m) Token
braceExpansion,
                ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpression,
                ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSingleQuoted,
                ParsecT String UserState (SCBase m) Token
readDoubleQuoted,
                ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
braceLiteral
                ]
    braceLiteral :: ParsecT String UserState (SCBase m) Token
braceLiteral =
        Id -> String -> Token
T_Literal (Id -> String -> Token)
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {t} {b} {s}.
Monad m =>
(Id -> t -> b)
-> ParsecT s UserState m t -> ParsecT s UserState m b
`withParser` ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {a}.
Monad m =>
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) String
readGenericLiteral1 (String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
"{}\"$'," ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
whitespace)

ensureDollar :: ParsecT s u m Char
ensureDollar =
    -- The grammar should have been designed along the lines of readDollarExpr = char '$' >> stuff, but
    -- instead, each subunit parses its own $. This results in ~7 1-3 char lookaheads instead of one 1-char.
    -- Instead of optimizing the grammar, here's a green cut that decreases shellcheck runtime by 10%:
    ParsecT s u m Char -> ParsecT s u m Char
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s u m Char -> ParsecT s u m Char)
-> ParsecT s u m Char -> ParsecT s u m Char
forall a b. (a -> b) -> a -> b
$ Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'$'

readNormalDollar :: ParsecT String UserState (SCBase m) Token
readNormalDollar = do
    ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
ensureDollar
    ParsecT String UserState (SCBase m) Token
readDollarExp ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readDollarDoubleQuote ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarSingleQuote ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Bool -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) Token
readDollarLonely Bool
False
readDoubleQuotedDollar :: ParsecT String UserState (SCBase m) Token
readDoubleQuotedDollar = do
    ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
ensureDollar
    ParsecT String UserState (SCBase m) Token
readDollarExp ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Bool -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) Token
readDollarLonely Bool
True


prop_readDollarExpression1 :: Bool
prop_readDollarExpression1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpression String
"$(((1) && 3))"
prop_readDollarExpression2 :: Bool
prop_readDollarExpression2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpression String
"$(((1)) && 3)"
prop_readDollarExpression3 :: Bool
prop_readDollarExpression3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpression String
"$((\"$@\" &); foo;)"
readDollarExpression :: Monad m => SCParser m Token
readDollarExpression :: forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpression = do
    ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
ensureDollar
    ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExp

readDollarExp :: ParsecT String UserState (SCBase m) Token
readDollarExp = ParsecT String UserState (SCBase m) Token
arithmetic ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readDollarExpansion ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarBracket ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readDollarBraceCommandExpansion ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readDollarBraced ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarVariable
  where
    arithmetic :: ParsecT String UserState (SCBase m) Token
arithmetic = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> (SourcePos -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) Token
forall (m :: * -> *) p.
Monad m =>
String
-> SCParser m p
-> SCParser m p
-> (SourcePos -> SCParser m ())
-> SCParser m p
readAmbiguous String
"$((" ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarArithmetic ParsecT String UserState (SCBase m) Token
readDollarExpansion (\SourcePos
pos ->
        SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
pos Severity
ErrorC Integer
1102 String
"Shells disambiguate $(( differently or not at all. For $(command substitution), add space after $( . For $((arithmetics)), fix parsing errors.")

prop_readDollarSingleQuote :: Bool
prop_readDollarSingleQuote = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarSingleQuote String
"$'foo\\\'lol'"
readDollarSingleQuote :: ParsecT String UserState (SCBase m) Token
readDollarSingleQuote = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"$'..' expression" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try $ string "$'"
    str <- readGenericLiteral "'"
    char '\''
    id <- endSpan start
    return $ T_DollarSingleQuoted id str

prop_readDollarDoubleQuote :: Bool
prop_readDollarDoubleQuote = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarDoubleQuote String
"$\"hello\""
readDollarDoubleQuote :: ParsecT String UserState (SCBase m) Token
readDollarDoubleQuote = do
    ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) String
 -> ParsecT String UserState (SCBase m) String)
-> (ParsecT String UserState (SCBase m) String
    -> ParsecT String UserState (SCBase m) String)
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) String
 -> ParsecT String UserState (SCBase m) String)
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT String UserState (SCBase m) String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"$\""
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char '$'
    doubleQuote
    x <- many doubleQuotedPart
    doubleQuote <|> fail "Expected end of translated double quoted string"
    id <- endSpan start
    return $ T_DollarDoubleQuoted id x

prop_readDollarArithmetic :: Bool
prop_readDollarArithmetic = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarArithmetic String
"$(( 3 * 4 +5))"
prop_readDollarArithmetic2 :: Bool
prop_readDollarArithmetic2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarArithmetic String
"$(((3*4)+(1*2+(3-1))))"
readDollarArithmetic :: ParsecT String UserState (SCBase m) Token
readDollarArithmetic = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"$((..)) expression" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try (string "$((")
    c <- readArithmeticContents
    pos <- getPosition
    char ')'
    char ')' <|> fail "Expected a double )) to end the $((..))"
    id <- endSpan start
    return (T_DollarArithmetic id c)

readDollarBracket :: ParsecT String UserState (SCBase m) Token
readDollarBracket = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"$[..] expression" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try (string "$[")
    c <- readArithmeticContents
    string "]"
    id <- endSpan start
    return (T_DollarBracket id c)

prop_readArithmeticExpression :: Bool
prop_readArithmeticExpression = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticExpression String
"((a?b:c))"
readArithmeticExpression :: ParsecT String UserState (SCBase m) Token
readArithmeticExpression = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"((..)) command" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try (string "((")
    c <- readArithmeticContents
    string "))"
    id <- endSpan start
    spacing
    return (T_Arithmetic id c)

-- If the next characters match prefix, try two different parsers and warn if the alternate parser had to be used
readAmbiguous :: Monad m => String -> SCParser m p -> SCParser m p -> (SourcePos -> SCParser m ()) -> SCParser m p
readAmbiguous :: forall (m :: * -> *) p.
Monad m =>
String
-> SCParser m p
-> SCParser m p
-> (SourcePos -> SCParser m ())
-> SCParser m p
readAmbiguous String
prefix SCParser m p
expected SCParser m p
alternative SourcePos -> SCParser m ()
warner = do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    try . lookAhead $ string prefix
    -- If the expected parser fails, try the alt.
    -- If the alt fails, run the expected one again for the errors.
    try expected <|> try (withAlt pos) <|> expected
  where
    withAlt :: SourcePos -> SCParser m p
withAlt SourcePos
pos = do
        t <- SCParser m p -> SCParser m p
forall {s} {m :: * -> *} {s} {u} {b}.
MonadState s m =>
ParsecT s u m b -> ParsecT s u m b
forgetOnFailure SCParser m p
alternative
        warner pos
        return t

prop_readDollarBraceCommandExpansion1 :: Bool
prop_readDollarBraceCommandExpansion1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarBraceCommandExpansion String
"${ ls; }"
prop_readDollarBraceCommandExpansion2 :: Bool
prop_readDollarBraceCommandExpansion2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarBraceCommandExpansion String
"${\nls\n}"
readDollarBraceCommandExpansion :: ParsecT String UserState (SCBase m) Token
readDollarBraceCommandExpansion = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"ksh ${ ..; } command expansion" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try $ do
        string "${"
        whitespace
    allspacing
    term <- readTerm
    char '}' <|> fail "Expected } to end the ksh ${ ..; } command expansion"
    id <- endSpan start
    return $ T_DollarBraceCommandExpansion id term

prop_readDollarBraced1 :: Bool
prop_readDollarBraced1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarBraced String
"${foo//bar/baz}"
prop_readDollarBraced2 :: Bool
prop_readDollarBraced2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarBraced String
"${foo/'{cow}'}"
prop_readDollarBraced3 :: Bool
prop_readDollarBraced3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarBraced String
"${foo%%$(echo cow\\})}"
prop_readDollarBraced4 :: Bool
prop_readDollarBraced4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarBraced String
"${foo#\\}}"
readDollarBraced :: ParsecT String UserState (SCBase m) Token
readDollarBraced = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"parameter expansion" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try (string "${")
    word <- readDollarBracedWord
    char '}'
    id <- endSpan start
    return $ T_DollarBraced id True word

prop_readDollarExpansion1 :: Bool
prop_readDollarExpansion1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpansion String
"$(echo foo; ls\n)"
prop_readDollarExpansion2 :: Bool
prop_readDollarExpansion2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpansion String
"$(  )"
prop_readDollarExpansion3 :: Bool
prop_readDollarExpansion3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarExpansion String
"$( command \n#comment \n)"
readDollarExpansion :: ParsecT String UserState (SCBase m) Token
readDollarExpansion = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"command expansion" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try (string "$(")
    cmds <- readCompoundListOrEmpty
    char ')' <|> fail "Expected end of $(..) expression"
    id <- endSpan start
    return $ T_DollarExpansion id cmds

prop_readDollarVariable :: Bool
prop_readDollarVariable = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarVariable String
"$@"
prop_readDollarVariable2 :: Bool
prop_readDollarVariable2 = ParsecT String UserState (SCBase Identity) Char -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk (ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarVariable ParsecT String UserState (SCBase Identity) Token
-> ParsecT String UserState (SCBase Identity) Char
-> ParsecT String UserState (SCBase Identity) Char
forall a b.
ParsecT String UserState (SCBase Identity) a
-> ParsecT String UserState (SCBase Identity) b
-> ParsecT String UserState (SCBase Identity) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT String UserState (SCBase Identity) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar) String
"$?!"
prop_readDollarVariable3 :: Bool
prop_readDollarVariable3 = ParsecT String UserState (SCBase Identity) Char -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning (ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarVariable ParsecT String UserState (SCBase Identity) Token
-> ParsecT String UserState (SCBase Identity) Char
-> ParsecT String UserState (SCBase Identity) Char
forall a b.
ParsecT String UserState (SCBase Identity) a
-> ParsecT String UserState (SCBase Identity) b
-> ParsecT String UserState (SCBase Identity) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT String UserState (SCBase Identity) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar) String
"$10"
prop_readDollarVariable4 :: Bool
prop_readDollarVariable4 = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning (ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarVariable ParsecT String UserState (SCBase Identity) Token
-> ParsecT String UserState (SCBase Identity) String
-> ParsecT String UserState (SCBase Identity) String
forall a b.
ParsecT String UserState (SCBase Identity) a
-> ParsecT String UserState (SCBase Identity) b
-> ParsecT String UserState (SCBase Identity) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> ParsecT String UserState (SCBase Identity) String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"[@]") String
"$arr[@]"
prop_readDollarVariable5 :: Bool
prop_readDollarVariable5 = ParsecT String UserState (SCBase Identity) String -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning (ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarVariable ParsecT String UserState (SCBase Identity) Token
-> ParsecT String UserState (SCBase Identity) String
-> ParsecT String UserState (SCBase Identity) String
forall a b.
ParsecT String UserState (SCBase Identity) a
-> ParsecT String UserState (SCBase Identity) b
-> ParsecT String UserState (SCBase Identity) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> ParsecT String UserState (SCBase Identity) String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"[f") String
"$arr[f"

readDollarVariable :: Monad m => SCParser m Token
readDollarVariable :: forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readDollarVariable = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    pos <- getPosition

    let singleCharred ParsecT s UserState m Char
p = do
        value <- ParsecT s UserState m String -> ParsecT s UserState m Token
forall {m :: * -> *} {s}.
Monad m =>
ParsecT s UserState m String -> ParsecT s UserState m Token
wrapString ((Char -> String -> String
forall a. a -> [a] -> [a]
:[]) (Char -> String)
-> ParsecT s UserState m Char -> ParsecT s UserState m String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s UserState m Char
p)
        id <- endSpan start
        return $ (T_DollarBraced id False value)

    let positional = do
        value <- ParsecT s UserState m Char -> ParsecT s UserState m Token
forall {m :: * -> *} {s}.
Monad m =>
ParsecT s UserState m Char -> ParsecT s UserState m Token
singleCharred ParsecT s UserState m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit
        return value `attempting` do
            lookAhead digit
            parseNoteAt pos ErrorC 1037 "Braces are required for positionals over 9, e.g. ${10}."

    let special = ParsecT s UserState m Char -> ParsecT s UserState m Token
forall {m :: * -> *} {s}.
Monad m =>
ParsecT s UserState m Char -> ParsecT s UserState m Token
singleCharred ParsecT s UserState m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
specialVariable

    let regular = do
        value <- ParsecT s UserState m String -> ParsecT s UserState m Token
forall {m :: * -> *} {s}.
Monad m =>
ParsecT s UserState m String -> ParsecT s UserState m Token
wrapString ParsecT s UserState m String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readVariableName
        id <- endSpan start
        return (T_DollarBraced id False value) `attempting` do
            lookAhead $ char '['
            parseNoteAt pos ErrorC 1087 "Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet)."

    try $ char '$' >> (positional <|> special <|> regular)

  where
    wrapString :: ParsecT s UserState m String -> ParsecT s UserState m Token
wrapString ParsecT s UserState m String
p = do
        start <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        s <- p
        end <- getPosition
        id1 <- getNextIdBetween start end
        id2 <- getNextIdBetween start end
        return $ T_NormalWord id1 [T_Literal id2 s]

readVariableName :: ParsecT s u m String
readVariableName = do
    f <- ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
variableStart
    rest <- many variableChars
    return (f:rest)


prop_readDollarLonely1 :: Bool
prop_readDollarLonely1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"\"$\"var"
prop_readDollarLonely2 :: Bool
prop_readDollarLonely2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"\"$\"\"var\""
prop_readDollarLonely3 :: Bool
prop_readDollarLonely3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"\"$\"$var"
prop_readDollarLonely4 :: Bool
prop_readDollarLonely4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"\"$\"*"
prop_readDollarLonely5 :: Bool
prop_readDollarLonely5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord String
"$\"str\""
readDollarLonely :: Bool -> ParsecT String UserState (SCBase m) Token
readDollarLonely Bool
quoted = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char '$'
    id <- endSpan start
    when quoted $ do
        isHack <- quoteForEscape
        when isHack $
            parseProblemAtId id StyleC 1135
                "Prefer escape over ending quote to make $ literal. Instead of \"It costs $\"5, use \"It costs \\$5\"."
    return $ T_Literal id "$"
  where
    quoteForEscape :: ParsecT s u m Bool
quoteForEscape = Bool -> ParsecT s u m Bool -> ParsecT s u m Bool
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option Bool
False (ParsecT s u m Bool -> ParsecT s u m Bool)
-> ParsecT s u m Bool -> ParsecT s u m Bool
forall a b. (a -> b) -> a -> b
$ ParsecT s u m Bool -> ParsecT s u m Bool
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m Bool -> ParsecT s u m Bool)
-> (ParsecT s u m Bool -> ParsecT s u m Bool)
-> ParsecT s u m Bool
-> ParsecT s u m Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT s u m Bool -> ParsecT s u m Bool
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s u m Bool -> ParsecT s u m Bool)
-> ParsecT s u m Bool -> ParsecT s u m Bool
forall a b. (a -> b) -> a -> b
$ do
        Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'"'
        -- Check for "foo $""bar"
        ParsecT s u m Char -> ParsecT s u m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT s u m Char -> ParsecT s u m ())
-> ParsecT s u m Char -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'"'
        c <- ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyVar
        -- Don't trigger on [[ x == "$"* ]] or "$"$pattern
        return $ c `notElem` "*$"
    anyVar :: ParsecT s u m Char
anyVar = ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
variableStart ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
specialVariable


prop_readHereDoc :: Bool
prop_readHereDoc = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo\nlol\ncow\nfoo"
prop_readHereDoc2 :: Bool
prop_readHereDoc2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat <<- EOF\n  cow\n  EOF"
prop_readHereDoc3 :: Bool
prop_readHereDoc3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo\n$\"\nfoo"
prop_readHereDoc4 :: Bool
prop_readHereDoc4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo\n`\nfoo"
prop_readHereDoc5 :: Bool
prop_readHereDoc5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat <<- !foo\nbar\n!foo"
prop_readHereDoc6 :: Bool
prop_readHereDoc6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo\\ bar\ncow\nfoo bar"
prop_readHereDoc7 :: Bool
prop_readHereDoc7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo\n\\$(f ())\nfoo"
prop_readHereDoc8 :: Bool
prop_readHereDoc8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat <<foo>>bar\netc\nfoo"
prop_readHereDoc9 :: Bool
prop_readHereDoc9 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"if true; then cat << foo; fi\nbar\nfoo\n"
prop_readHereDoc10 :: Bool
prop_readHereDoc10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"if true; then cat << foo << bar; fi\nfoo\nbar\n"
prop_readHereDoc11 :: Bool
prop_readHereDoc11 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo $(\nfoo\n)lol\nfoo\n"
prop_readHereDoc12 :: Bool
prop_readHereDoc12 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo|cat\nbar\nfoo"
prop_readHereDoc13 :: Bool
prop_readHereDoc13 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat <<'#!'\nHello World\n#!\necho Done"
prop_readHereDoc14 :: Bool
prop_readHereDoc14 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo\nbar\nfoo \n"
prop_readHereDoc15 :: Bool
prop_readHereDoc15 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat <<foo\nbar\nfoo bar\nfoo"
prop_readHereDoc16 :: Bool
prop_readHereDoc16 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat <<- ' foo'\nbar\n foo\n"
prop_readHereDoc17 :: Bool
prop_readHereDoc17 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat <<- ' foo'\nbar\n  foo\n foo\n"
prop_readHereDoc18 :: Bool
prop_readHereDoc18 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat <<'\"foo'\nbar\n\"foo\n"
prop_readHereDoc20 :: Bool
prop_readHereDoc20 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo\n  foo\n()\nfoo\n"
prop_readHereDoc21 :: Bool
prop_readHereDoc21 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"# shellcheck disable=SC1039\ncat << foo\n  foo\n()\nfoo\n"
prop_readHereDoc22 :: Bool
prop_readHereDoc22 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo\r\ncow\r\nfoo\r\n"
prop_readHereDoc23 :: Bool
prop_readHereDoc23 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"cat << foo \r\ncow\r\nfoo\r\n"
readHereDoc :: ParsecT String UserState (SCBase m) Token
readHereDoc = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"here document" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    try $ string "<<"
    dashed <- (char '-' >> return Dashed) <|> return Undashed
    sp <- spacing
    optional $ do
        try . lookAhead $ char '('
        let message = String
"Shells are space sensitive. Use '< <(cmd)', not '<<" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
sp String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"(cmd)'."
        parseProblemAt pos ErrorC 1038 message
    start <- startSpan
    (quoted, endToken) <- readToken
    hid <- endSpan start

    -- add empty tokens for now, read the rest in readPendingHereDocs
    let doc = Id -> Dashed -> Quoted -> String -> [Token] -> Token
T_HereDoc Id
hid Dashed
dashed Quoted
quoted String
endToken []
    addPendingHereDoc hid dashed quoted endToken
    return doc
  where
    unquote :: String -> (Quoted, String)
    unquote :: String -> (Quoted, String)
unquote String
"" = (Quoted
Unquoted, String
"")
    unquote [Char
c] = (Quoted
Unquoted, [Char
c])
    unquote s :: String
s@(Char
cl:String
tl) =
      case String -> String
forall a. [a] -> [a]
reverse String
tl of
        (Char
cr:String
tr) | Char
cr Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
cl Bool -> Bool -> Bool
&& Char
cl Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
"\"'" -> (Quoted
Quoted, String -> String
forall a. [a] -> [a]
reverse String
tr)
        String
_ -> (if Char
'\\' Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s then (Quoted
Quoted, (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
(/=) Char
'\\') String
s) else (Quoted
Unquoted, String
s))
    -- Fun fact: bash considers << foo"" quoted, but not << <("foo").
    readToken :: ParsecT String UserState (SCBase m) (Quoted, String)
readToken = do
        str <- ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {s} {u} {a}.
(MonadState s m, Stream s m Char) =>
ParsecT s u m a -> ParsecT s u m String
readStringForParser ParsecT String UserState (SCBase m) Token
readNormalWord
        -- A here doc actually works with \r\n because the \r becomes part of the token
        crstr <- (carriageReturn >> (return $ str ++ "\r")) <|> return str
        return $ unquote crstr

readPendingHereDocs :: ParsecT String UserState (SCBase m) ()
readPendingHereDocs = do
    docs <- ParsecT String UserState (SCBase m) [HereDocContext]
forall {m :: * -> *} {s}.
Monad m =>
ParsecT s UserState m [HereDocContext]
popPendingHereDocs
    mapM_ readDoc docs
  where
    readDoc :: HereDocContext -> ParsecT String UserState (SCBase m) ()
readDoc (HereDocPending Id
id Dashed
dashed Quoted
quoted String
endToken [Context]
ctx) =
      [Context]
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall {s} {m :: * -> *} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
[Context] -> ParsecT s u m b -> ParsecT s u m b
swapContext [Context]
ctx (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$
      do
        docStartPos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        (terminated, wasWarned, lines) <- readDocLines dashed endToken
        docEndPos <- getPosition
        let hereData = [String] -> String
unlines [String]
lines
        unless terminated $ do
            unless wasWarned $
                debugHereDoc id endToken hereData
            fail "Here document was not correctly terminated"
        list <- parseHereData quoted (docStartPos, docEndPos) hereData
        addToHereDocMap id list

    -- Read the lines making up the here doc. Returns (IsTerminated, Lines)
    readDocLines :: Monad m => Dashed -> String -> SCParser m (Bool, Bool, [String])
    readDocLines :: forall (m :: * -> *).
Monad m =>
Dashed -> String -> SCParser m (Bool, Bool, [String])
readDocLines Dashed
dashed String
endToken = do
        pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        str <- rawLine
        isEof <- option False (eof >> return True)
        (isEnd, wasWarned) <- subParse pos checkEnd str
        if
            | isEnd -> return (True, wasWarned, [])
            | isEof -> return (False, wasWarned, [str])
            | True -> do
                (ok, previousWarning, rest) <- readDocLines dashed endToken
                return (ok, wasWarned || previousWarning, str:rest)
      where
        -- Check if this is the actual end, or a plausible false end
        checkEnd :: ParsecT s UserState m (Bool, Bool)
checkEnd = (Bool, Bool)
-> ParsecT s UserState m (Bool, Bool)
-> ParsecT s UserState m (Bool, Bool)
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option (Bool
False, Bool
False) (ParsecT s UserState m (Bool, Bool)
 -> ParsecT s UserState m (Bool, Bool))
-> ParsecT s UserState m (Bool, Bool)
-> ParsecT s UserState m (Bool, Bool)
forall a b. (a -> b) -> a -> b
$ ParsecT s UserState m (Bool, Bool)
-> ParsecT s UserState m (Bool, Bool)
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s UserState m (Bool, Bool)
 -> ParsecT s UserState m (Bool, Bool))
-> ParsecT s UserState m (Bool, Bool)
-> ParsecT s UserState m (Bool, Bool)
forall a b. (a -> b) -> a -> b
$ do
            -- Match what's basically '^( *)token( *)(.*)$'
            leadingSpacePos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
            leadingSpace <- linewhitespace `reluctantlyTill` string endToken
            string endToken
            trailingSpacePos <- getPosition
            trailingSpace <- many linewhitespace
            trailerPos <- getPosition
            trailer <- many anyChar

            let leadingSpacesAreTabs = (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\t') String
leadingSpace
            let thereIsNoTrailer = String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
trailingSpace Bool -> Bool -> Bool
&& String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
trailer
            let leaderIsOk = String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
leadingSpace
                    Bool -> Bool -> Bool
|| Dashed
dashed Dashed -> Dashed -> Bool
forall a. Eq a => a -> a -> Bool
== Dashed
Dashed Bool -> Bool -> Bool
&& Bool
leadingSpacesAreTabs
            let trailerStart = case String
trailer of [] -> Char
'\0'; (Char
h:String
_) -> Char
h
            let hasTrailingSpace = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
trailingSpace
            let hasTrailer = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
trailer
            let ppt = SourcePos -> Severity -> Integer -> String -> m ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
trailerPos Severity
ErrorC

            if leaderIsOk && thereIsNoTrailer
              then return (True, False)
              else do
                let foundCause = (Bool, Bool) -> m (Bool, Bool)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
False, Bool
True)
                let skipLine = (Bool, Bool) -> m (Bool, Bool)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
False, Bool
False)
                -- This may be intended as an end token. Debug why it isn't.
                if
                    | trailerStart == ')' -> do
                        ppt 1119 $ "Add a linefeed between end token and terminating ')'."
                        foundCause
                    | trailerStart == '#' -> do
                        ppt 1120 "No comments allowed after here-doc token. Comment the next line instead."
                        foundCause
                    | trailerStart `elem` ";>|&" -> do
                        ppt 1121 "Add ;/& terminators (and other syntax) on the line with the <<, not here."
                        foundCause
                    | hasTrailingSpace && hasTrailer -> do
                        ppt 1122 "Nothing allowed after end token. To continue a command, put it on the line with the <<."
                        foundCause
                    | leaderIsOk && hasTrailingSpace && not hasTrailer -> do
                        parseProblemAt trailingSpacePos ErrorC 1118 "Delete whitespace after the here-doc end token."
                        -- Parse as if it's the actual end token. Will koala_man regret this once again?
                        return (True, True)
                    | not hasTrailingSpace && hasTrailer ->
                        -- The end token is just a prefix
                        skipLine
                    | hasTrailer ->
                        error $ pleaseReport "unexpected heredoc trailer"

                    -- The following cases assume no trailing text:
                    | dashed == Undashed && (not $ null leadingSpace) -> do
                        parseProblemAt leadingSpacePos ErrorC 1039 "Remove indentation before end token (or use <<- and indent with tabs)."
                        foundCause
                    | dashed == Dashed && not leadingSpacesAreTabs -> do
                        parseProblemAt leadingSpacePos ErrorC 1040 "When using <<-, you can only indent with tabs."
                        foundCause
                    | True -> skipLine

    rawLine :: ParsecT s u m String
rawLine = do
        c <- ParsecT s u m Char -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT s u m Char -> ParsecT s u m String)
-> ParsecT s u m Char -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"\n"
        void (char '\n') <|> eof
        return c

    parseHereData :: Quoted
-> (SourcePos, SourcePos)
-> String
-> ParsecT String UserState (SCBase m) [Token]
parseHereData Quoted
Quoted (SourcePos
start,SourcePos
end) String
hereData = do
        id <- SourcePos -> SourcePos -> ParsecT String UserState (SCBase m) Id
forall {m :: * -> *} {s}.
Monad m =>
SourcePos -> SourcePos -> ParsecT s UserState m Id
getNextIdBetween SourcePos
start SourcePos
end
        return [T_Literal id hereData]

    parseHereData Quoted
Unquoted (SourcePos
startPos, SourcePos
_) String
hereData =
        SourcePos
-> ParsecT String UserState (SCBase m) [Token]
-> String
-> ParsecT String UserState (SCBase m) [Token]
forall {m :: * -> *} {s} {u} {b}.
Monad m =>
SourcePos -> ParsecT s u m b -> s -> ParsecT s u m b
subParse SourcePos
startPos ParsecT String UserState (SCBase m) [Token]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Token]
readHereData String
hereData

    readHereData :: ParsecT String UserState (SCBase m) [Token]
readHereData = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) [Token])
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
doubleQuotedPart ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s}.
Stream s m Char =>
ParsecT s UserState m Token
readHereLiteral

    readHereLiteral :: ParsecT s UserState m Token
readHereLiteral = do
        start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        chars <- many1 $ noneOf "`$\\"
        id <- endSpan start
        return $ T_Literal id chars

    debugHereDoc :: Id -> String -> String -> ParsecT String UserState (SCBase m) ()
debugHereDoc Id
tokenId String
endToken String
doc
        | String
endToken String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` String
doc =
            let lookAt :: String -> ParsecT String UserState (SCBase m) ()
lookAt String
line = Bool
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (String
endToken String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` String
line) (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$
                      Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId Id
tokenId Severity
ErrorC Integer
1042 (String
"Close matches include '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String -> String
e4m String
line) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' (!= '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String -> String
e4m String
endToken) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"').")
            in do
                  Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId Id
tokenId Severity
ErrorC Integer
1041 (String
"Found '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String -> String
e4m String
endToken) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' further down, but not on a separate line.")
                  (String -> ParsecT String UserState (SCBase m) ())
-> [String] -> ParsecT String UserState (SCBase m) ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ String -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *}.
Monad m =>
String -> ParsecT String UserState (SCBase m) ()
lookAt (String -> [String]
lines String
doc)
        | (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
endToken String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
doc =
            Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId Id
tokenId Severity
ErrorC Integer
1043 (String
"Found " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String -> String
e4m String
endToken) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" further down, but with wrong casing.")
        | Bool
otherwise =
            Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId Id
tokenId Severity
ErrorC Integer
1044 (String
"Couldn't find end token `" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String -> String
e4m String
endToken) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' in the here document.")


readFilename :: ParsecT String UserState (SCBase m) Token
readFilename = ParsecT String UserState (SCBase m) Token
readNormalWord
readIoFileOp :: ParsecT s UserState m Token
readIoFileOp = [ParsecT s UserState m Token] -> ParsecT s UserState m Token
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_DGREAT, ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_LESSGREAT, ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_GREATAND, ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_LESSAND, ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_CLOBBER, Char -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {a}.
Stream s m Char =>
Char -> (Id -> a) -> ParsecT s UserState m a
redirToken Char
'<' Id -> Token
T_Less, Char -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {a}.
Stream s m Char =>
Char -> (Id -> a) -> ParsecT s UserState m a
redirToken Char
'>' Id -> Token
T_Greater ]

readIoDuplicate :: ParsecT s UserState m Token
readIoDuplicate = ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s UserState m Token -> ParsecT s UserState m Token)
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    op <- g_GREATAND <|> g_LESSAND
    target <- readIoVariable <|> digitsAndOrDash
    id <- endSpan start
    return $ T_IoDuplicate id op target
  where
    -- either digits with optional dash, or a required dash
    digitsAndOrDash :: ParsecT s u m String
digitsAndOrDash = do
        str <- ParsecT s u m Char -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit
        dash <- (if null str then id else option "") $ string "-"
        return $ str ++ dash


prop_readIoFile :: Bool
prop_readIoFile = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoFile String
">> \"$(date +%YYmmDD)\""
readIoFile :: ParsecT String UserState (SCBase m) Token
readIoFile = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"redirection" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    op <- readIoFileOp
    spacing
    file <- readFilename
    id <- endSpan start
    return $ T_IoFile id op file

readIoVariable :: ParsecT s u m String
readIoVariable = ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ do
    Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'{'
    x <- ParsecT s u m String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readVariableName
    char '}'
    return $ "{" ++ x ++ "}"

readIoSource :: ParsecT s UserState m String
readIoSource = ParsecT s UserState m String -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s UserState m String -> ParsecT s UserState m String)
-> ParsecT s UserState m String -> ParsecT s UserState m String
forall a b. (a -> b) -> a -> b
$ do
    x <- String -> ParsecT s UserState m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"&" ParsecT s UserState m String
-> ParsecT s UserState m String -> ParsecT s UserState m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readIoVariable ParsecT s UserState m String
-> ParsecT s UserState m String -> ParsecT s UserState m String
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Char -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT s UserState m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit
    lookAhead $ void readIoFileOp <|> void (string "<<")
    return x

prop_readIoRedirect :: Bool
prop_readIoRedirect = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoRedirect String
"3>&2"
prop_readIoRedirect2 :: Bool
prop_readIoRedirect2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoRedirect String
"2> lol"
prop_readIoRedirect3 :: Bool
prop_readIoRedirect3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoRedirect String
"4>&-"
prop_readIoRedirect4 :: Bool
prop_readIoRedirect4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoRedirect String
"&> lol"
prop_readIoRedirect5 :: Bool
prop_readIoRedirect5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoRedirect String
"{foo}>&2"
prop_readIoRedirect6 :: Bool
prop_readIoRedirect6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoRedirect String
"{foo}<&-"
prop_readIoRedirect7 :: Bool
prop_readIoRedirect7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoRedirect String
"{foo}>&1-"
readIoRedirect :: ParsecT String UserState (SCBase m) Token
readIoRedirect = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    n <- readIoSource
    redir <- readHereString <|> readHereDoc <|> readIoDuplicate <|> readIoFile
    id <- endSpan start
    skipAnnotationAndWarn
    spacing
    return $ T_FdRedirect id n redir

prop_readHereString :: Bool
prop_readHereString = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readHereString String
"<<< \"Hello $world\""
readHereString :: ParsecT String UserState (SCBase m) Token
readHereString = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"here string" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try $ string "<<<"
    id <- endSpan start
    spacing
    word <- readNormalWord
    return $ T_HereString id word

prop_readNewlineList1 :: Bool
prop_readNewlineList1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"&> /dev/null echo foo"
readNewlineList :: ParsecT String UserState (SCBase m) String
readNewlineList =
    ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ((ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
linefeed ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
forall {m :: * -> *} {s} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m Char
carriageReturn) ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) Char
forall {s} {m :: * -> *} {t} {u} {a} {a}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`thenSkip` ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing) ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) String
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {s} {m :: * -> *} {u}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m ()
checkBadBreak
  where
    checkBadBreak :: ParsecT s u m ()
checkBadBreak = ParsecT s u m () -> ParsecT s u m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT s u m () -> ParsecT s u m ())
-> ParsecT s u m () -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ do
                pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
                try $ lookAhead (oneOf "|&") --  See if the next thing could be |, || or &&
                notFollowedBy2 (string "&>") --  Except &> or &>> which is valid
                parseProblemAt pos ErrorC 1133
                    "Unexpected start of line. If breaking lines, |/||/&& should be at the end of the previous one."
readLineBreak :: ParsecT String UserState (SCBase m) ()
readLineBreak = ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
readNewlineList

prop_readSeparator1 :: Bool
prop_readSeparator1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"a &; b"
prop_readSeparator2 :: Bool
prop_readSeparator2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"a & b"
prop_readSeparator3 :: Bool
prop_readSeparator3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"a &amp; b"
prop_readSeparator4 :: Bool
prop_readSeparator4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"a &gt; file; b"
prop_readSeparator5 :: Bool
prop_readSeparator5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"curl https://example.com/?foo=moo&bar=cow"
readSeparatorOp :: ParsecT String UserState (SCBase m) (Char, (SourcePos, SourcePos))
readSeparatorOp = do
    ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 (ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_AND_IF ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) CaseType
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) CaseType
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) CaseType
readCaseSeparator)
    ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 (String -> ParsecT String UserState (SCBase m) String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"&>")
    start <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    f <- try (do
                    pos <- getPosition
                    char '&'
                    optional $ choice [
                        do
                            s <- lookAhead . choice . map (try . string) $
                                ["amp;", "gt;", "lt;"]
                            parseProblemAt pos ErrorC 1109 "This is an unquoted HTML entity. Replace with corresponding character.",

                        do
                            try . lookAhead $ variableStart
                            parseProblemAt pos WarningC 1132 "This & terminates the command. Escape it or add space after & to silence."
                      ]

                    spacing
                    pos <- getPosition
                    char ';'
                    -- In case statements we might have foo & ;;
                    notFollowedBy2 $ char ';'
                    parseProblemAt pos ErrorC 1045 "It's not 'foo &; bar', just 'foo & bar'."
                    return '&'
            ) <|> char ';' <|> char '&'
    end <- getPosition
    spacing
    return (f, (start, end))

readSequentialSep :: ParsecT String UserState (SCBase m) ()
readSequentialSep = ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_Semi ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) ()
readLineBreak) ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
readNewlineList
readSeparator :: ParsecT String UserState (SCBase m) (Char, (SourcePos, SourcePos))
readSeparator =
    do
        separator <- ParsecT String UserState (SCBase m) (Char, (SourcePos, SourcePos))
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) (Char, (SourcePos, SourcePos))
readSeparatorOp
        readLineBreak
        return separator
     ParsecT String UserState (SCBase m) (Char, (SourcePos, SourcePos))
-> ParsecT
     String UserState (SCBase m) (Char, (SourcePos, SourcePos))
-> ParsecT
     String UserState (SCBase m) (Char, (SourcePos, SourcePos))
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
        do
            start <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
            readNewlineList
            end <- getPosition
            return ('\n', (start, end))

prop_readSimpleCommand :: Bool
prop_readSimpleCommand = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"echo test > file"
prop_readSimpleCommand2 :: Bool
prop_readSimpleCommand2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"cmd &> file"
prop_readSimpleCommand3 :: Bool
prop_readSimpleCommand3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"export foo=(bar baz)"
prop_readSimpleCommand4 :: Bool
prop_readSimpleCommand4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"typeset -a foo=(lol)"
prop_readSimpleCommand5 :: Bool
prop_readSimpleCommand5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"time if true; then echo foo; fi"
prop_readSimpleCommand6 :: Bool
prop_readSimpleCommand6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"time -p ( ls -l; )"
prop_readSimpleCommand7 :: Bool
prop_readSimpleCommand7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"\\ls"
prop_readSimpleCommand7b :: Bool
prop_readSimpleCommand7b = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"\\:"
prop_readSimpleCommand8 :: Bool
prop_readSimpleCommand8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"// Lol"
prop_readSimpleCommand9 :: Bool
prop_readSimpleCommand9 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"/* Lolbert */"
prop_readSimpleCommand10 :: Bool
prop_readSimpleCommand10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"/**** Lolbert */"
prop_readSimpleCommand11 :: Bool
prop_readSimpleCommand11 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"/\\* foo"
prop_readSimpleCommand12 :: Bool
prop_readSimpleCommand12 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"elsif foo"
prop_readSimpleCommand13 :: Bool
prop_readSimpleCommand13 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"ElseIf foo"
prop_readSimpleCommand14 :: Bool
prop_readSimpleCommand14 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"elseif[$i==2]"
prop_readSimpleCommand15 :: Bool
prop_readSimpleCommand15 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSimpleCommand String
"trap 'foo\"bar' INT"
readSimpleCommand :: ParsecT String UserState (SCBase m) Token
readSimpleCommand = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"simple command" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    prefix <- [Token]
-> ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option [] ParsecT String UserState (SCBase m) [Token]
readCmdPrefix
    skipAnnotationAndWarn
    cmd <- option Nothing $ Just <$> readCmdName
    when (null prefix && isNothing cmd) $ fail "Expected a command"

    case cmd of
      Maybe Token
Nothing -> do
        id1 <- [Token] -> ParsecT String UserState (SCBase m) Id
forall {m :: * -> *}.
Monad m =>
[Token] -> ParsecT String UserState (SCBase m) Id
getNextIdSpanningTokenList [Token]
prefix
        id2 <- getNewIdFor id1
        return $ makeSimpleCommand id1 id2 prefix [] []

      Just Token
cmd -> do
            Token -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *}.
Monad m =>
Token -> ParsecT String UserState (SCBase m) ()
validateCommand Token
cmd
            -- We have to ignore possible parsing problems from the lookAhead parser
            firstArgument <- ParsecT String UserState (SCBase m) (Maybe Token)
-> ParsecT String UserState (SCBase m) (Maybe Token)
forall {t :: (* -> *) -> * -> *} {t :: (* -> *) -> * -> *}
       {m :: * -> *} {a} {b}.
(MonadTrans t, MonadTrans t, Monad (t (t m)), Monad (t m),
 MonadState a m) =>
t (t m) b -> t (t m) b
ignoreProblemsOf (ParsecT String UserState (SCBase m) (Maybe Token)
 -> ParsecT String UserState (SCBase m) (Maybe Token))
-> (ParsecT String UserState (SCBase m) Token
    -> ParsecT String UserState (SCBase m) (Maybe Token))
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Maybe Token)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Maybe Token)
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (Maybe a)
optionMaybe (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) (Maybe Token))
-> (ParsecT String UserState (SCBase m) Token
    -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Maybe Token)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> (ParsecT String UserState (SCBase m) Token
    -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) (Maybe Token))
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) (Maybe Token)
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Token
readCmdWord
            suffix <- option [] $ getParser readCmdSuffix
                    -- If `export` or other modifier commands are called with `builtin` we have to look at the first argument
                    (if isCommand ["builtin"] cmd then fromMaybe cmd firstArgument else cmd) [
                        (["declare", "export", "local", "readonly", "typeset"], readModifierSuffix),
                        (["time"], readTimeSuffix),
                        (["let"], readLetSuffix),
                        (["eval"], readEvalSuffix)
                    ]

            id1 <- getNextIdSpanningTokenList (prefix ++ (cmd:suffix))
            id2 <- getNewIdFor id1

            let result = Id -> Id -> [Token] -> [Token] -> [Token] -> Token
makeSimpleCommand Id
id1 Id
id2 [Token]
prefix [Token
cmd] [Token]
suffix
            case () of
                ()
_ | [String] -> Token -> Bool
forall {t :: * -> *}. Foldable t => t String -> Token -> Bool
isCommand [String
"source", String
"."] Token
cmd -> Token -> ParsecT String UserState (SCBase m) Token
forall (m :: * -> *). Monad m => Token -> SCParser m Token
readSource Token
result
                ()
_ | [String] -> Token -> Bool
forall {t :: * -> *}. Foldable t => t String -> Token -> Bool
isCommand [String
"trap"] Token
cmd -> do
                        Token -> ParsecT String UserState (SCBase m) ()
syntaxCheckTrap Token
result
                        Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
result
                ()
_ -> Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
result
  where
    isCommand :: t String -> Token -> Bool
isCommand t String
strings (T_NormalWord Id
_ [T_Literal Id
_ String
s]) = String
s String -> t String -> Bool
forall a. Eq a => a -> t a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` t String
strings
    isCommand t String
_ Token
_ = Bool
False
    getParser :: t -> Token -> [(t String, t)] -> t
getParser t
def Token
cmd [] = t
def
    getParser t
def Token
cmd ((t String
list, t
action):[(t String, t)]
rest) =
        if t String -> Token -> Bool
forall {t :: * -> *}. Foldable t => t String -> Token -> Bool
isCommand t String
list Token
cmd
        then t
action
        else t -> Token -> [(t String, t)] -> t
getParser t
def Token
cmd [(t String, t)]
rest

    validateCommand :: Token -> SCParser m ()
validateCommand Token
cmd =
        case Token
cmd of
            (T_NormalWord Id
_ [T_Literal Id
_ String
"//"]) -> Id -> SCParser m ()
forall {m :: * -> *}. Monad m => Id -> SCParser m ()
commentWarning (Token -> Id
getId Token
cmd)
            (T_NormalWord Id
_ (T_Literal Id
_ String
"/" : T_Glob Id
_ String
"*" :[Token]
_)) -> Id -> SCParser m ()
forall {m :: * -> *}. Monad m => Id -> SCParser m ()
commentWarning (Token -> Id
getId Token
cmd)
            (T_NormalWord Id
_ (T_Literal Id
_ String
str:[Token]
_)) -> do
                let cmdString :: String
cmdString = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile Char -> Bool
isAlpha String
str
                Bool -> SCParser m () -> SCParser m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (String
cmdString String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String
"elsif", String
"elseif"]) (SCParser m () -> SCParser m ()) -> SCParser m () -> SCParser m ()
forall a b. (a -> b) -> a -> b
$
                    Id -> Severity -> Integer -> String -> SCParser m ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId (Token -> Id
getId Token
cmd) Severity
ErrorC Integer
1131 String
"Use 'elif' to start another branch."
            Token
_ -> () -> SCParser m ()
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

    syntaxCheckTrap :: Token -> ParsecT String UserState (SCBase m) ()
syntaxCheckTrap Token
cmd =
        case Token
cmd of
            (T_Redirecting Id
_ [Token]
_ (T_SimpleCommand Id
_ [Token]
_ (Token
cmd:Token
arg:[Token]
_))) -> Token -> Maybe String -> ParsecT String UserState (SCBase m) ()
checkArg Token
arg (Token -> Maybe String
getLiteralString Token
arg)
            Token
_ -> () -> ParsecT String UserState (SCBase m) ()
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      where
        checkArg :: Token -> Maybe String -> ParsecT String UserState (SCBase m) ()
checkArg Token
_ Maybe String
Nothing = () -> ParsecT String UserState (SCBase m) ()
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        checkArg Token
arg (Just (Char
'-':String
_)) = () -> ParsecT String UserState (SCBase m) ()
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        checkArg Token
arg (Just String
str) = do
            (start,end) <- Id -> SCParser m (SourcePos, SourcePos)
forall (m :: * -> *).
Monad m =>
Id -> SCParser m (SourcePos, SourcePos)
getSpanForId (Token -> Id
getId Token
arg)
            subParse start (tryWithErrors (readCompoundListOrEmpty >> verifyEof) <|> return ()) str

    commentWarning :: Id -> SCParser m ()
commentWarning Id
id =
        Id -> Severity -> Integer -> String -> SCParser m ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId Id
id Severity
ErrorC Integer
1127 String
"Was this intended as a comment? Use # in sh."

    makeSimpleCommand :: Id -> Id -> [Token] -> [Token] -> [Token] -> Token
makeSimpleCommand Id
id1 Id
id2 [Token]
prefix [Token]
cmd [Token]
suffix =
        let
            ([Token]
preAssigned, [Token]
preRest) = (Token -> Bool) -> [Token] -> ([Token], [Token])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition Token -> Bool
assignment [Token]
prefix
            ([Token]
preRedirected, [Token]
preRest2) = (Token -> Bool) -> [Token] -> ([Token], [Token])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition Token -> Bool
redirection [Token]
preRest
            ([Token]
postRedirected, [Token]
postRest) = (Token -> Bool) -> [Token] -> ([Token], [Token])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition Token -> Bool
redirection [Token]
suffix

            redirs :: [Token]
redirs = [Token]
preRedirected [Token] -> [Token] -> [Token]
forall a. [a] -> [a] -> [a]
++ [Token]
postRedirected
            assigns :: [Token]
assigns = [Token]
preAssigned
            args :: [Token]
args = [Token]
cmd [Token] -> [Token] -> [Token]
forall a. [a] -> [a] -> [a]
++ [Token]
preRest2 [Token] -> [Token] -> [Token]
forall a. [a] -> [a] -> [a]
++ [Token]
postRest
        in
            Id -> [Token] -> Token -> Token
T_Redirecting Id
id1 [Token]
redirs (Token -> Token) -> Token -> Token
forall a b. (a -> b) -> a -> b
$ Id -> [Token] -> [Token] -> Token
T_SimpleCommand Id
id2 [Token]
assigns [Token]
args
      where
        assignment :: Token -> Bool
assignment (T_Assignment {}) = Bool
True
        assignment Token
_ = Bool
False
        redirection :: Token -> Bool
redirection (T_FdRedirect {}) = Bool
True
        redirection Token
_ = Bool
False


readSource :: Monad m => Token -> SCParser m Token
readSource :: forall (m :: * -> *). Monad m => Token -> SCParser m Token
readSource t :: Token
t@(T_Redirecting Id
_ [Token]
_ (T_SimpleCommand Id
cmdId [Token]
_ (Token
cmd:Token
file':[Token]
rest'))) = do
    let file :: Token
file = Token -> [Token] -> Token
getFile Token
file' [Token]
rest'
    override <- ParsecT String UserState (SCBase m) (Maybe String)
forall {m :: * -> *}. MonadState SystemState m => m (Maybe String)
getSourceOverride
    let literalFile = do
        name <- Maybe String
override Maybe String -> Maybe String -> Maybe String
forall a. Maybe a -> Maybe a -> Maybe a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` Token -> Maybe String
getLiteralString Token
file Maybe String -> Maybe String -> Maybe String
forall a. Maybe a -> Maybe a -> Maybe a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` Token -> Maybe String
stripDynamicPrefix Token
file
        -- Hack to avoid 'source ~/foo' trying to read from literal tilde
        guard . not $ "~/" `isPrefixOf` name
        return name
    case literalFile of
        Maybe String
Nothing -> do
            Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseNoteAtId (Token -> Id
getId Token
file) Severity
WarningC Integer
1090
                String
"ShellCheck can't follow non-constant source. Use a directive to specify location."
            Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
t
        Just String
filename -> do
            proceed <- String -> ParsecT String UserState (SCBase m) Bool
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
String -> ParsecT s u m Bool
shouldFollow String
filename
            if not proceed
              then do
                -- FIXME: This actually gets squashed without -a
                parseNoteAtId (getId file) InfoC 1093
                    "This file appears to be recursively sourced. Ignoring."
                return t
              else do
                sys <- Mr.asks systemInterface
                (input, resolvedFile) <-
                    if filename == "/dev/null" -- always allow /dev/null
                    then return (Right "", filename)
                    else do
                        allAnnotations <- getCurrentAnnotations True
                        currentScript <- Mr.asks currentFilename
                        let paths = (Annotation -> Maybe String) -> [Annotation] -> [String]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Annotation -> Maybe String
getSourcePath [Annotation]
allAnnotations
                        let externalSources = [Bool] -> Maybe Bool
forall a. [a] -> Maybe a
listToMaybe ([Bool] -> Maybe Bool) -> [Bool] -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ (Annotation -> Maybe Bool) -> [Annotation] -> [Bool]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Annotation -> Maybe Bool
getExternalSources [Annotation]
allAnnotations
                        resolved <- system $ siFindSource sys currentScript externalSources paths filename
                        contents <- system $ siReadFile sys externalSources resolved
                        return (contents, resolved)
                case input of
                    Left String
err -> do
                        Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseNoteAtId (Token -> Id
getId Token
file) Severity
InfoC Integer
1091 (String -> ParsecT String UserState (SCBase m) ())
-> String -> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$
                            String
"Not following: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
err
                        Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
t
                    Right String
script -> do
                        id1 <- Id -> SCParser m Id
forall (m :: * -> *). Monad m => Id -> SCParser m Id
getNewIdFor Id
cmdId
                        id2 <- getNewIdFor cmdId

                        let included = do
                            src <- String -> String -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
String -> String -> ParsecT String UserState (SCBase m) Token
subRead String
resolvedFile String
script
                            return $ T_SourceCommand id1 t (T_Include id2 src)

                        let failed = do
                            Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseNoteAtId (Token -> Id
getId Token
file) Severity
WarningC Integer
1094
                                String
"Parsing of sourced file failed. Ignoring it."
                            Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
t

                        included <|> failed
  where
    getFile :: Token -> [Token] -> Token
    getFile :: Token -> [Token] -> Token
getFile Token
file (Token
next:[Token]
rest) =
        case Token -> Maybe String
getLiteralString Token
file of
            Just String
"--" -> Token
next
            Maybe String
x -> Token
file
    getFile Token
file [Token]
_ = Token
file

    getSourcePath :: Annotation -> Maybe String
getSourcePath Annotation
t =
        case Annotation
t of
            SourcePath String
x -> String -> Maybe String
forall a. a -> Maybe a
Just String
x
            Annotation
_ -> Maybe String
forall a. Maybe a
Nothing

    getExternalSources :: Annotation -> Maybe Bool
getExternalSources Annotation
t =
        case Annotation
t of
            ExternalSources Bool
b -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
b
            Annotation
_ -> Maybe Bool
forall a. Maybe a
Nothing

    -- If the word has a single expansion as the directory, try stripping it
    -- This affects `$foo/bar` but not `${foo}-dir/bar` or `/foo/$file`
    stripDynamicPrefix :: Token -> Maybe String
stripDynamicPrefix Token
word =
        case Token -> [Token]
getWordParts Token
word of
            Token
exp : [Token]
rest | Token -> Bool
isStringExpansion Token
exp -> do
                str <- Token -> Maybe String
getLiteralString (Id -> [Token] -> Token
T_NormalWord (Line -> Id
Id Line
0) [Token]
rest)
                guard $ "/" `isPrefixOf` str
                return $ "." ++ str
            [Token]
_ -> Maybe String
forall a. Maybe a
Nothing

    subRead :: String -> String -> ParsecT String UserState (SCBase m) Token
subRead String
name String
script =
        Context
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
Context -> ParsecT s u m b -> ParsecT s u m b
withContext (String -> Context
ContextSource String
name) (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$
            ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {s} {u} {b}.
MonadState s m =>
ParsecT s u m b -> ParsecT s u m b
inSeparateContext (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
                oldState <- ParsecT String UserState (SCBase m) UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
                setState $ oldState { pendingHereDocs = [] }
                result <- subParse (initialPos name) (readScriptFile True) script
                newState <- getState
                setState $ newState { pendingHereDocs = pendingHereDocs oldState }
                return result
readSource Token
t = Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
t


prop_readPipeline :: Bool
prop_readPipeline = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readPipeline String
"! cat /etc/issue | grep -i ubuntu"
prop_readPipeline2 :: Bool
prop_readPipeline2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readPipeline String
"!cat /etc/issue | grep -i ubuntu"
prop_readPipeline3 :: Bool
prop_readPipeline3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readPipeline String
"for f; do :; done|cat"
prop_readPipeline4 :: Bool
prop_readPipeline4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readPipeline String
"! ! true"
prop_readPipeline5 :: Bool
prop_readPipeline5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readPipeline String
"true | ! true"
readPipeline :: ParsecT String UserState (SCBase m) Token
readPipeline = do
    String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
forall {s} {u} {m :: * -> *} {a}.
String -> ParsecT s u m a -> ParsecT s u m ()
unexpecting String
"keyword/token" ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readKeyword
    ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token -> ParsecT s UserState m Token
readBanged ParsecT String UserState (SCBase m) Token
readPipeSequence

readBanged :: ParsecT s UserState m Token -> ParsecT s UserState m Token
readBanged ParsecT s UserState m Token
parser = do
    pos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    (T_Bang id) <- g_Bang
    next <- readBanged parser
    return $ T_Banged id next
 ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
parser

prop_readAndOr :: Bool
prop_readAndOr = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAndOr String
"grep -i lol foo || exit 1"
prop_readAndOr1 :: Bool
prop_readAndOr1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAndOr String
"# shellcheck disable=1\nfoo"
prop_readAndOr2 :: Bool
prop_readAndOr2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAndOr String
"# shellcheck disable=1\n# lol\n# shellcheck disable=3\nfoo"
readAndOr :: ParsecT String UserState (SCBase m) Token
readAndOr = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    apos <- getPosition
    annotations <- readAnnotations
    aid <- endSpan start

    unless (null annotations) $ optional $ do
        try . lookAhead $ readKeyword
        parseProblemAt apos ErrorC 1123 "ShellCheck directives are only valid in front of complete compound commands, like 'if', not e.g. individual 'elif' branches."

    andOr <- withAnnotations annotations $
        chainl1 readPipeline $ do
            op <- g_AND_IF <|> g_OR_IF
            readLineBreak
            return $ case op of T_AND_IF Id
id -> Id -> Token -> Token -> Token
T_AndIf Id
id
                                T_OR_IF  Id
id -> Id -> Token -> Token -> Token
T_OrIf Id
id

    return $ if null annotations
                then andOr
                else T_Annotation aid annotations andOr

readTermOrNone :: ParsecT String UserState (SCBase m) [Token]
readTermOrNone = do
    ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing
    ParsecT String UserState (SCBase m) [Token]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Token]
readTerm ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> do
        ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof
        [Token] -> ParsecT String UserState (SCBase m) [Token]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return []

prop_readTerm :: Bool
prop_readTerm = ParsecT String UserState (SCBase Identity) [Token]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Token]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Token]
readTerm String
"time ( foo; bar; )"
readTerm :: ParsecT String UserState (SCBase m) [Token]
readTerm = do
    ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing
    m <- ParsecT String UserState (SCBase m) Token
readAndOr
    readTerm' m
  where
    readTerm' :: Token -> ParsecT String UserState (SCBase m) [Token]
readTerm' Token
current =
        do
            (sep, (start, end)) <- ParsecT String UserState (SCBase m) (Char, (SourcePos, SourcePos))
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) (Char, (SourcePos, SourcePos))
readSeparator
            id <- getNextIdBetween start end
            more <- option (T_EOF id) readAndOr
            case more of (T_EOF Id
_) -> [Token] -> ParsecT String UserState (SCBase m) [Token]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return [Id -> Char -> Token -> Token
transformWithSeparator Id
id Char
sep Token
current]
                         Token
_         -> do
                                    list <- Token -> ParsecT String UserState (SCBase m) [Token]
readTerm' Token
more
                                    return (transformWithSeparator id sep current : list)
          ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
            [Token] -> ParsecT String UserState (SCBase m) [Token]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return [Token
current]
      where
        transformWithSeparator :: Id -> Char -> Token -> Token
transformWithSeparator Id
i Char
'&' = Id -> Token -> Token
T_Backgrounded Id
i
        transformWithSeparator Id
i Char
_  = Token -> Token
forall a. a -> a
id


readPipeSequence :: ParsecT String UserState (SCBase m) Token
readPipeSequence = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    (cmds, pipes) <- sepBy1WithSeparators (readBanged readCommand)
                        (readPipe `thenSkip` (spacing >> readLineBreak))
    id <- endSpan start
    spacing
    return $ T_Pipeline id pipes cmds
  where
    sepBy1WithSeparators :: ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m ([a], [a])
sepBy1WithSeparators ParsecT s u m a
p ParsecT s u m a
s = do
        let elems :: ParsecT s u m ([a], [a])
elems = (\a
x -> ([a
x], [])) (a -> ([a], [a])) -> ParsecT s u m a -> ParsecT s u m ([a], [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParsecT s u m a
p
        let seps :: ParsecT s u m (([a], [a]) -> ([a], [a]) -> ([a], [a]))
seps = do
            separator <- ParsecT s u m a
s
            return $ \([a]
a,[a]
b) ([a]
c,[a]
d) -> ([a]
a[a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++[a]
c, [a]
b [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a]
d [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
separator])
        ParsecT s u m ([a], [a])
forall {a}. ParsecT s u m ([a], [a])
elems ParsecT s u m ([a], [a])
-> ParsecT s u m (([a], [a]) -> ([a], [a]) -> ([a], [a]))
-> ParsecT s u m ([a], [a])
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
`chainl1` ParsecT s u m (([a], [a]) -> ([a], [a]) -> ([a], [a]))
forall {a}. ParsecT s u m (([a], [a]) -> ([a], [a]) -> ([a], [a]))
seps

readPipe :: ParsecT s UserState m Token
readPipe = do
    ParsecT s UserState m Token -> ParsecT s UserState m ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_OR_IF
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char '|'
    qualifier <- string "&" <|> return ""
    id <- endSpan start
    spacing
    return $ T_Pipe id ('|':qualifier)

readCommand :: ParsecT String UserState (SCBase m) Token
readCommand = [ParsecT String UserState (SCBase m) Token]
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
    ParsecT String UserState (SCBase m) Token
readCompoundCommand,
    ParsecT String UserState (SCBase m) Token
readConditionCommand,
    ParsecT String UserState (SCBase m) Token
readCoProc,
    ParsecT String UserState (SCBase m) Token
readSimpleCommand
    ]

readCmdName :: ParsecT String UserState (SCBase m) Token
readCmdName = do
    -- If the command name is `!` then
    ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) ())
-> (ParsecT String UserState (SCBase m) Char
    -> ParsecT String UserState (SCBase m) Char)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) Char)
-> (ParsecT String UserState (SCBase m) Char
    -> ParsecT String UserState (SCBase m) Char)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ do
        Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'!'
        ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
whitespace
    -- Ignore alias suppression
    ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) ())
-> (ParsecT String UserState (SCBase m) Char
    -> ParsecT String UserState (SCBase m) Char)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ do
        Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'\\'
        ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) Char)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
variableChars ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
":."
    ParsecT String UserState (SCBase m) Token
readCmdWord

readCmdWord :: ParsecT String UserState (SCBase m) Token
readCmdWord = do
    ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m ()
skipAnnotationAndWarn
    ParsecT String UserState (SCBase m) Token
readNormalWord ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) Token
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing

-- Due to poor planning, annotations after commands isn't handled well.
-- At the time this function is used, it's usually too late to skip
-- comments, so you end up with a parse failure instead.
skipAnnotationAndWarn :: ParsecT s UserState m ()
skipAnnotationAndWarn = ParsecT s UserState m String -> ParsecT s UserState m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT s UserState m String -> ParsecT s UserState m ())
-> ParsecT s UserState m String -> ParsecT s UserState m ()
forall a b. (a -> b) -> a -> b
$ do
        ParsecT s UserState m String -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s UserState m String -> ParsecT s UserState m String)
-> (ParsecT s UserState m String -> ParsecT s UserState m String)
-> ParsecT s UserState m String
-> ParsecT s UserState m String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT s UserState m String -> ParsecT s UserState m String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s UserState m String -> ParsecT s UserState m String)
-> ParsecT s UserState m String -> ParsecT s UserState m String
forall a b. (a -> b) -> a -> b
$ ParsecT s UserState m String
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
readAnnotationPrefix
        Severity -> Integer -> String -> ParsecT s UserState m ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1126 String
"Place shellcheck directives before commands, not after."
        ParsecT s UserState m String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readAnyComment

prop_readIfClause :: Bool
prop_readIfClause = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIfClause String
"if false; then foo; elif true; then stuff; more stuff; else cows; fi"
prop_readIfClause2 :: Bool
prop_readIfClause2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIfClause String
"if false; then; echo oo; fi"
prop_readIfClause3 :: Bool
prop_readIfClause3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIfClause String
"if false; then true; else; echo lol; fi"
prop_readIfClause4 :: Bool
prop_readIfClause4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIfClause String
"if false; then true; else if true; then echo lol; fi; fi"
prop_readIfClause5 :: Bool
prop_readIfClause5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIfClause String
"if false; then true; else\nif true; then echo lol; fi; fi"
prop_readIfClause6 :: Bool
prop_readIfClause6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIfClause String
"if true\nthen\nDo the thing\nfi"
readIfClause :: ParsecT String UserState (SCBase m) Token
readIfClause = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"if expression" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    pos <- getPosition
    (condition, action) <- readIfPart
    elifs <- many readElifPart
    elses <- option [] readElsePart

    g_Fi `orFail` do
        parseProblemAt pos ErrorC 1046 "Couldn't find 'fi' for this 'if'."
        parseProblem ErrorC 1047 "Expected 'fi' matching previously mentioned 'if'."
        return "Expected 'fi'"
    id <- endSpan start

    return $ T_IfExpression id ((condition, action):elifs) elses


verifyNotEmptyIf :: String -> ParsecT String UserState (SCBase m) ()
verifyNotEmptyIf String
s =
    ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (do
                emptyPos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
                try . lookAhead $ (g_Fi <|> g_Elif <|> g_Else)
                parseProblemAt emptyPos ErrorC 1048 $ "Can't have empty " ++ s ++ " clauses (use 'true' as a no-op).")
readIfPart :: ParsecT String UserState (SCBase m) ([Token], [Token])
readIfPart = do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    g_If
    allspacing
    condition <- readTerm

    ifNextToken (g_Fi <|> g_Elif <|> g_Else) $
        parseProblemAt pos ErrorC 1049 "Did you forget the 'then' for this 'if'?"

    called "then clause" $ do
        g_Then `orFail` do
            parseProblem ErrorC 1050 "Expected 'then'."
            return "Expected 'then'"

        acceptButWarn g_Semi ErrorC 1051 "Semicolons directly after 'then' are not allowed. Just remove it."
        allspacing
        verifyNotEmptyIf "then"

        action <- readTerm
        return (condition, action)

readElifPart :: ParsecT String UserState (SCBase m) ([Token], [Token])
readElifPart = String
-> ParsecT String UserState (SCBase m) ([Token], [Token])
-> ParsecT String UserState (SCBase m) ([Token], [Token])
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"elif clause" (ParsecT String UserState (SCBase m) ([Token], [Token])
 -> ParsecT String UserState (SCBase m) ([Token], [Token]))
-> ParsecT String UserState (SCBase m) ([Token], [Token])
-> ParsecT String UserState (SCBase m) ([Token], [Token])
forall a b. (a -> b) -> a -> b
$ do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    g_Elif
    allspacing
    condition <- readTerm
    ifNextToken (g_Fi <|> g_Elif <|> g_Else) $
        parseProblemAt pos ErrorC 1049 "Did you forget the 'then' for this 'elif'?"

    g_Then
    acceptButWarn g_Semi ErrorC 1052 "Semicolons directly after 'then' are not allowed. Just remove it."
    allspacing
    verifyNotEmptyIf "then"
    action <- readTerm
    return (condition, action)

readElsePart :: ParsecT String UserState (SCBase m) [Token]
readElsePart = String
-> ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"else clause" (ParsecT String UserState (SCBase m) [Token]
 -> ParsecT String UserState (SCBase m) [Token])
-> ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
forall a b. (a -> b) -> a -> b
$ do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    g_Else
    optional $ do
        try . lookAhead $ g_If
        parseProblemAt pos ErrorC 1075 "Use 'elif' instead of 'else if' (or put 'if' on new line if nesting)."

    acceptButWarn g_Semi ErrorC 1053 "Semicolons directly after 'else' are not allowed. Just remove it."
    allspacing
    verifyNotEmptyIf "else"
    readTerm

ifNextToken :: ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m ()
ifNextToken ParsecT s u m a
parser ParsecT s u m a
action =
    ParsecT s u m a -> ParsecT s u m ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT s u m a -> ParsecT s u m ())
-> ParsecT s u m a -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ do
        ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m a -> ParsecT s u m a)
-> (ParsecT s u m a -> ParsecT s u m a)
-> ParsecT s u m a
-> ParsecT s u m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 (ParsecT s u m a -> ParsecT s u m a)
-> ParsecT s u m a -> ParsecT s u m a
forall a b. (a -> b) -> a -> b
$ ParsecT s u m a
parser
        ParsecT s u m a
action

prop_readSubshell :: Bool
prop_readSubshell = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSubshell String
"( cd /foo; tar cf stuff.tar * )"
readSubshell :: ParsecT String UserState (SCBase m) Token
readSubshell = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"explicit subshell" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char '('
    allspacing
    list <- readCompoundList
    allspacing
    char ')' <|> fail "Expected ) closing the subshell"
    id <- endSpan start
    spacing
    return $ T_Subshell id list

prop_readBraceGroup :: Bool
prop_readBraceGroup = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraceGroup String
"{ a; b | c | d; e; }"
prop_readBraceGroup2 :: Bool
prop_readBraceGroup2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraceGroup String
"{foo;}"
prop_readBraceGroup3 :: Bool
prop_readBraceGroup3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBraceGroup String
"{(foo)}"
readBraceGroup :: ParsecT String UserState (SCBase m) Token
readBraceGroup = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"brace group" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char '{'
    void allspacingOrFail <|> optional (do
        lookAhead $ noneOf "(" -- {( is legal
        parseProblem ErrorC 1054 "You need a space after the '{'.")
    optional $ do
        pos <- getPosition
        lookAhead $ char '}'
        parseProblemAt pos ErrorC 1055 "You need at least one command here. Use 'true;' as a no-op."
    list <- readTerm
    char '}' <|> do
        parseProblem ErrorC 1056 "Expected a '}'. If you have one, try a ; or \\n in front of it."
        fail "Missing '}'"
    id <- endSpan start
    spacing
    return $ T_BraceGroup id list

prop_readBatsTest1 :: Bool
prop_readBatsTest1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBatsTest String
"@test 'can parse' {\n  true\n}"
prop_readBatsTest2 :: Bool
prop_readBatsTest2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBatsTest String
"@test random text !(@*$Y&! {\n  true\n}"
prop_readBatsTest3 :: Bool
prop_readBatsTest3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBatsTest String
"@test foo { bar { baz {\n  true\n}"
prop_readBatsTest4 :: Bool
prop_readBatsTest4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readBatsTest String
"@test foo \n{\n true\n}"
readBatsTest :: ParsecT String UserState (SCBase m) Token
readBatsTest = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"bats @test" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try $ string "@test "
    spacing
    name <- readBatsName
    spacing
    test <- readBraceGroup
    id <- endSpan start
    return $ T_BatsTest id name test
  where
    readBatsName :: ParsecT s u m String
readBatsName = do
        line <- ParsecT s u m String -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s u m String -> ParsecT s u m String)
-> (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String
-> ParsecT s u m String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT s u m String -> ParsecT s u m String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ ParsecT s u m Char -> ParsecT s u m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT s u m Char -> ParsecT s u m String)
-> ParsecT s u m Char -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"\n"
        let name = String -> String
forall a. [a] -> [a]
reverse (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
f (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String -> String
forall a. [a] -> [a]
reverse String
line
        string name

    -- We want everything before the last " {" in a string, so we find everything after "{ " in its reverse
    f :: String -> String
f (Char
'{':Char
' ':String
rest) = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace String
rest
    f (Char
a:String
rest) = String -> String
f String
rest
    f [] = String
""

prop_readWhileClause :: Bool
prop_readWhileClause = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readWhileClause String
"while [[ -e foo ]]; do sleep 1; done"
readWhileClause :: ParsecT String UserState (SCBase m) Token
readWhileClause = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"while loop" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    kwId <- getId <$> g_While
    condition <- readTerm
    statements <- readDoGroup kwId
    id <- endSpan start
    return $ T_WhileExpression id condition statements

prop_readUntilClause :: Bool
prop_readUntilClause = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readUntilClause String
"until kill -0 $PID; do sleep 1; done"
readUntilClause :: ParsecT String UserState (SCBase m) Token
readUntilClause = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"until loop" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    kwId <- getId <$> g_Until
    condition <- readTerm
    statements <- readDoGroup kwId
    id <- endSpan start
    return $ T_UntilExpression id condition statements

readDoGroup :: Id -> ParsecT String UserState (SCBase m) [Token]
readDoGroup Id
kwId = do
    ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (do
                ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> (ParsecT String UserState (SCBase m) Token
    -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Done
                Id
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *).
Monad m =>
Id -> Severity -> Integer -> String -> SCParser m ()
parseProblemAtId Id
kwId Severity
ErrorC Integer
1057 String
"Did you forget the 'do' for this loop?")

    doKw <- ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Do ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) Token
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m String -> ParsecT s u m a
`orFail` do
        Severity
-> Integer -> String -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1058 String
"Expected 'do'."
        String -> ParsecT String UserState (SCBase m) String
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return String
"Expected 'do'"

    acceptButWarn g_Semi ErrorC 1059 "Semicolon is not allowed directly after 'do'. You can just delete it."
    allspacing

    optional (do
                try . lookAhead $ g_Done
                parseProblemAtId (getId doKw) ErrorC 1060 "Can't have empty do clauses (use 'true' as a no-op).")

    commands <- readCompoundList
    g_Done `orFail` do
            parseProblemAtId (getId doKw) ErrorC 1061 "Couldn't find 'done' for this 'do'."
            parseProblem ErrorC 1062 "Expected 'done' matching previously mentioned 'do'."
            return "Expected 'done'"

    optional . lookAhead $ do
        pos <- getPosition
        try $ string "<("
        parseProblemAt pos ErrorC 1142 "Use 'done < <(cmd)' to redirect from process substitution (currently missing one '<')."
    return commands


prop_readForClause :: Bool
prop_readForClause = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for f in *; do rm \"$f\"; done"
prop_readForClause1 :: Bool
prop_readForClause1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for f in *; { rm \"$f\"; }"
prop_readForClause3 :: Bool
prop_readForClause3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for f; do foo; done"
prop_readForClause4 :: Bool
prop_readForClause4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for((i=0; i<10; i++)); do echo $i; done"
prop_readForClause5 :: Bool
prop_readForClause5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for ((i=0;i<10 && n>x;i++,--n))\ndo \necho $i\ndone"
prop_readForClause6 :: Bool
prop_readForClause6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for ((;;))\ndo echo $i\ndone"
prop_readForClause7 :: Bool
prop_readForClause7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for ((;;)) do echo $i\ndone"
prop_readForClause8 :: Bool
prop_readForClause8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for ((;;)) ; do echo $i\ndone"
prop_readForClause9 :: Bool
prop_readForClause9 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for i do true; done"
prop_readForClause10 :: Bool
prop_readForClause10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for ((;;)) { true; }"
prop_readForClause12 :: Bool
prop_readForClause12 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for $a in *; do echo \"$a\"; done"
prop_readForClause13 :: Bool
prop_readForClause13 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readForClause String
"for foo\nin\\\n  bar\\\n  baz\ndo true; done"
readForClause :: ParsecT String UserState (SCBase m) Token
readForClause = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"for loop" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    (T_For id) <- g_For
    spacing
    readArithmetic id <|> readRegular id
  where
    readArithmetic :: Id -> ParsecT String UserState (SCBase m) Token
readArithmetic Id
id = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"arithmetic for condition" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
        Char -> String -> ParsecT String UserState (SCBase m) ()
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
Char -> String -> ParsecT s UserState m ()
readArithmeticDelimiter Char
'(' String
"Missing second '(' to start arithmetic for ((;;)) loop"
        x <- ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents
        char ';' >> spacing
        y <- readArithmeticContents
        char ';' >> spacing
        z <- readArithmeticContents
        spacing
        readArithmeticDelimiter ')' "Missing second ')' to terminate 'for ((;;))' loop condition"
        spacing
        optional $ readSequentialSep >> spacing
        group <- readBraced <|> readDoGroup id
        return $ T_ForArithmetic id x y z group

    -- For c='(' read "((" and be lenient about spaces
    readArithmeticDelimiter :: Char -> String -> ParsecT s UserState m ()
readArithmeticDelimiter Char
c String
msg = do
        Char -> ParsecT s UserState m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
c
        startPos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        sp <- spacing
        endPos <- getPosition
        char c <|> do
            parseProblemAt startPos ErrorC 1137 msg
            fail ""
        unless (null sp) $
            parseProblemAtWithEnd startPos endPos ErrorC 1138 $ "Remove spaces between " ++ [c,c] ++ " in arithmetic for loop."

    readBraced :: ParsecT String UserState (SCBase m) [Token]
readBraced = do
        (T_BraceGroup _ list) <- ParsecT String UserState (SCBase m) Token
readBraceGroup
        return list

    readRegular :: Id -> ParsecT String UserState (SCBase m) Token
readRegular Id
id = do
        ParsecT String UserState (SCBase m) Char
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {s} {m :: * -> *} {t} {m :: * -> *} {u} {a}.
(Stream s m t, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m a
-> Severity -> Integer -> String -> ParsecT s u m ()
acceptButWarn (Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'$') Severity
ErrorC Integer
1086
            String
"Don't use $ on the iterator name in for loops."
        name <- ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readVariableName ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {t} {u} {a} {a}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`thenSkip` ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing
        values <- readInClause <|> (optional readSequentialSep >> return [])
        group <- readBraced <|> readDoGroup id
        return $ T_ForIn id name values group

prop_readSelectClause1 :: Bool
prop_readSelectClause1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSelectClause String
"select foo in *; do echo $foo; done"
prop_readSelectClause2 :: Bool
prop_readSelectClause2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readSelectClause String
"select foo; do echo $foo; done"
readSelectClause :: ParsecT String UserState (SCBase m) Token
readSelectClause = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"select loop" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    (T_Select id) <- ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Select
    spacing
    typ <- readRegular
    group <- readDoGroup id
    typ id group
  where
    readRegular :: ParsecT String UserState (SCBase m) (Id -> [Token] -> m Token)
readRegular = do
        name <- ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readVariableName
        spacing
        values <- readInClause <|> (readSequentialSep >> return [])
        return $ \Id
id [Token]
group -> (Token -> m Token
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Token -> m Token) -> Token -> m Token
forall a b. (a -> b) -> a -> b
$ Id -> String -> [Token] -> [Token] -> Token
T_SelectIn Id
id String
name [Token]
values [Token]
group)

readInClause :: ParsecT String UserState (SCBase m) [Token]
readInClause = do
    ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_In
    things <- ParsecT String UserState (SCBase m) Token
readCmdWord ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) [Token]
forall {s} {m :: * -> *} {t} {u} {a} {a}.
(Stream s m t, Show t) =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m [a]
`reluctantlyTill`
                (ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_Semi ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
linefeed ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Do)

    do {
        lookAhead g_Do;
        parseNote ErrorC 1063 "You need a line feed or semicolon before the 'do'.";
    } <|> do {
        optional g_Semi;
        void allspacing;
    }

    return things

prop_readCaseClause :: Bool
prop_readCaseClause = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCaseClause String
"case foo in a ) lol; cow;; b|d) fooo; esac"
prop_readCaseClause2 :: Bool
prop_readCaseClause2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCaseClause String
"case foo\n in * ) echo bar;; esac"
prop_readCaseClause3 :: Bool
prop_readCaseClause3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCaseClause String
"case foo\n in * ) echo bar & ;; esac"
prop_readCaseClause4 :: Bool
prop_readCaseClause4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCaseClause String
"case foo\n in *) echo bar ;& bar) foo; esac"
prop_readCaseClause5 :: Bool
prop_readCaseClause5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCaseClause String
"case foo\n in *) echo bar;;& foo) baz;; esac"
prop_readCaseClause6 :: Bool
prop_readCaseClause6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCaseClause String
"case foo\n in if) :;; done) :;; esac"
readCaseClause :: ParsecT String UserState (SCBase m) Token
readCaseClause = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"case expression" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    g_Case
    word <- readNormalWord
    allspacing
    g_In <|> fail "Expected 'in'"
    readLineBreak
    list <- readCaseList
    g_Esac <|> fail "Expected 'esac' to close the case statement"
    id <- endSpan start
    return $ T_CaseExpression id word list

readCaseList :: ParsecT String UserState (SCBase m) [(CaseType, [Token], [Token])]
readCaseList = ParsecT String UserState (SCBase m) (CaseType, [Token], [Token])
-> ParsecT
     String UserState (SCBase m) [(CaseType, [Token], [Token])]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT String UserState (SCBase m) (CaseType, [Token], [Token])
readCaseItem

readCaseItem :: ParsecT String UserState (SCBase m) (CaseType, [Token], [Token])
readCaseItem = String
-> ParsecT String UserState (SCBase m) (CaseType, [Token], [Token])
-> ParsecT String UserState (SCBase m) (CaseType, [Token], [Token])
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"case item" (ParsecT String UserState (SCBase m) (CaseType, [Token], [Token])
 -> ParsecT
      String UserState (SCBase m) (CaseType, [Token], [Token]))
-> ParsecT String UserState (SCBase m) (CaseType, [Token], [Token])
-> ParsecT String UserState (SCBase m) (CaseType, [Token], [Token])
forall a b. (a -> b) -> a -> b
$ do
    ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Esac
    ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ do
        ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) String
 -> ParsecT String UserState (SCBase m) String)
-> (ParsecT String UserState (SCBase m) String
    -> ParsecT String UserState (SCBase m) String)
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) String
 -> ParsecT String UserState (SCBase m) String)
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
readAnnotationPrefix
        Severity
-> Integer -> String -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1124 String
"ShellCheck directives are only valid in front of complete commands like 'case' statements, not individual case branches."
    ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_Lparen
    ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing
    pattern' <- ParsecT String UserState (SCBase m) [Token]
readPattern
    void g_Rparen <|> do
        parseProblem ErrorC 1085
            "Did you forget to move the ;; after extending this case item?"
        fail "Expected ) to open a new case item"
    readLineBreak
    list <- (lookAhead readCaseSeparator >> return []) <|> readCompoundList
    separator <- readCaseSeparator `attempting` do
        pos <- getPosition
        lookAhead g_Rparen
        parseProblemAt pos ErrorC 1074
            "Did you forget the ;; after the previous case item?"
    readLineBreak
    return (separator, pattern', list)

readCaseSeparator :: ParsecT String UserState (SCBase m) CaseType
readCaseSeparator = [ParsecT String UserState (SCBase m) CaseType]
-> ParsecT String UserState (SCBase m) CaseType
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
    String -> (Id -> ()) -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
";;&" (() -> Id -> ()
forall a b. a -> b -> a
const ()) ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) CaseType
-> ParsecT String UserState (SCBase m) CaseType
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> CaseType -> ParsecT String UserState (SCBase m) CaseType
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return CaseType
CaseContinue,
    String -> (Id -> ()) -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
";&" (() -> Id -> ()
forall a b. a -> b -> a
const ()) ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) CaseType
-> ParsecT String UserState (SCBase m) CaseType
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> CaseType -> ParsecT String UserState (SCBase m) CaseType
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return CaseType
CaseFallThrough,
    ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_DSEMI ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) CaseType
-> ParsecT String UserState (SCBase m) CaseType
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> CaseType -> ParsecT String UserState (SCBase m) CaseType
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return CaseType
CaseBreak,
    ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) ()
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) ()
readLineBreak ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Esac) ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) CaseType
-> ParsecT String UserState (SCBase m) CaseType
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> CaseType -> ParsecT String UserState (SCBase m) CaseType
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return CaseType
CaseBreak
    ]

prop_readFunctionDefinition :: Bool
prop_readFunctionDefinition = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"foo() { command foo --lol \"$@\"; }"
prop_readFunctionDefinition1 :: Bool
prop_readFunctionDefinition1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"foo   (){ command foo --lol \"$@\"; }"
prop_readFunctionDefinition4 :: Bool
prop_readFunctionDefinition4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"foo(a, b) { true; }"
prop_readFunctionDefinition5 :: Bool
prop_readFunctionDefinition5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
":(){ :|:;}"
prop_readFunctionDefinition6 :: Bool
prop_readFunctionDefinition6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"?(){ foo; }"
prop_readFunctionDefinition7 :: Bool
prop_readFunctionDefinition7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"..(){ cd ..; }"
prop_readFunctionDefinition8 :: Bool
prop_readFunctionDefinition8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"foo() (ls)"
prop_readFunctionDefinition9 :: Bool
prop_readFunctionDefinition9 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"function foo { true; }"
prop_readFunctionDefinition10 :: Bool
prop_readFunctionDefinition10 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"function foo () { true; }"
prop_readFunctionDefinition11 :: Bool
prop_readFunctionDefinition11 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"function foo{\ntrue\n}"
prop_readFunctionDefinition12 :: Bool
prop_readFunctionDefinition12 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"function []!() { true; }"
prop_readFunctionDefinition13 :: Bool
prop_readFunctionDefinition13 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readFunctionDefinition String
"@require(){ true; }"
readFunctionDefinition :: ParsecT String UserState (SCBase m) Token
readFunctionDefinition = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"function" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    functionSignature <- try readFunctionSignature
    allspacing
    void (lookAhead $ oneOf "{(") <|> parseProblem ErrorC 1064 "Expected a { to open the function definition."
    group <- readBraceGroup <|> readSubshell
    id <- endSpan start
    return $ functionSignature id group
  where
    readFunctionSignature :: ParsecT String UserState (SCBase m) (Id -> Token -> Token)
readFunctionSignature =
        ParsecT String UserState (SCBase m) (Id -> Token -> Token)
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) (Id -> Token -> Token)
readWithFunction ParsecT String UserState (SCBase m) (Id -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Id -> Token -> Token)
-> ParsecT String UserState (SCBase m) (Id -> Token -> Token)
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) (Id -> Token -> Token)
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m (Id -> Token -> Token)
readWithoutFunction
      where
        readWithFunction :: ParsecT String UserState (SCBase m) (Id -> Token -> Token)
readWithFunction = do
            ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) Char)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall a b. (a -> b) -> a -> b
$ do
                String -> ParsecT String UserState (SCBase m) String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"function"
                ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
whitespace
            ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing
            name <- ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
extendedFunctionChars
            spaces <- spacing
            hasParens <- wasIncluded readParens
            when (not hasParens && null spaces) $
                acceptButWarn (lookAhead (oneOf "{("))
                    ErrorC 1095 "You need a space or linefeed between the function name and body."
            return $ \Id
id -> Id
-> FunctionKeyword
-> FunctionParentheses
-> String
-> Token
-> Token
T_Function Id
id (Bool -> FunctionKeyword
FunctionKeyword Bool
True) (Bool -> FunctionParentheses
FunctionParentheses Bool
hasParens) String
name

        readWithoutFunction :: ParsecT s UserState m (Id -> Token -> Token)
readWithoutFunction = ParsecT s UserState m (Id -> Token -> Token)
-> ParsecT s UserState m (Id -> Token -> Token)
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s UserState m (Id -> Token -> Token)
 -> ParsecT s UserState m (Id -> Token -> Token))
-> ParsecT s UserState m (Id -> Token -> Token)
-> ParsecT s UserState m (Id -> Token -> Token)
forall a b. (a -> b) -> a -> b
$ do
            name <- ParsecT s UserState m Char -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT s UserState m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
functionChars
            guard $ name /= "time"  -- Interferes with time ( foo )
            spacing
            readParens
            return $ \Id
id -> Id
-> FunctionKeyword
-> FunctionParentheses
-> String
-> Token
-> Token
T_Function Id
id (Bool -> FunctionKeyword
FunctionKeyword Bool
False) (Bool -> FunctionParentheses
FunctionParentheses Bool
True) String
name

        readParens :: ParsecT s UserState m ()
readParens = do
            ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_Lparen
            ParsecT s UserState m String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing
            ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_Rparen ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> do
                Severity -> Integer -> String -> ParsecT s UserState m ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1065 String
"Trying to declare parameters? Don't. Use () and refer to params as $1, $2.."
                ParsecT s UserState m Char -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT s UserState m Char -> ParsecT s UserState m String)
-> ParsecT s UserState m Char -> ParsecT s UserState m String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s UserState m Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf String
"\n){"
                ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_Rparen
            () -> ParsecT s UserState m ()
forall a. a -> ParsecT s UserState m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

prop_readCoProc1 :: Bool
prop_readCoProc1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCoProc String
"coproc foo { echo bar; }"
prop_readCoProc2 :: Bool
prop_readCoProc2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCoProc String
"coproc { echo bar; }"
prop_readCoProc3 :: Bool
prop_readCoProc3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCoProc String
"coproc echo bar"
readCoProc :: ParsecT String UserState (SCBase m) Token
readCoProc = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"coproc" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    try $ do
        string "coproc"
        whitespace
    choice [ try $ readCompoundCoProc start, readSimpleCoProc start ]
  where
    readCompoundCoProc :: IncompleteInterval -> ParsecT String UserState (SCBase m) Token
readCompoundCoProc IncompleteInterval
start = do
        var <- ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) (Maybe String)
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m (Maybe a)
optionMaybe (ParsecT String UserState (SCBase m) String
 -> ParsecT String UserState (SCBase m) (Maybe String))
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) (Maybe String)
forall a b. (a -> b) -> a -> b
$
            ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readVariableName ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {t} {u} {a} {a}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`thenSkip` ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
whitespace
        body <- readBody readCompoundCommand
        id <- endSpan start
        return $ T_CoProc id var body
    readSimpleCoProc :: IncompleteInterval -> ParsecT String UserState (SCBase m) Token
readSimpleCoProc IncompleteInterval
start = do
        body <- ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s}.
Monad m =>
ParsecT s UserState m Token -> ParsecT s UserState m Token
readBody ParsecT String UserState (SCBase m) Token
readSimpleCommand
        id <- endSpan start
        return $ T_CoProc id Nothing body
    readBody :: ParsecT s UserState m Token -> ParsecT s UserState m Token
readBody ParsecT s UserState m Token
parser = do
        start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        body <- parser
        id <- endSpan start
        return $ T_CoProcBody id body

readPattern :: ParsecT String UserState (SCBase m) [Token]
readPattern = (ParsecT String UserState (SCBase m) Token
readPatternWord ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {t} {u} {a} {a}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`thenSkip` ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing) ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) [Token]
forall s (m :: * -> *) t u a sep.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
`sepBy1` (Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'|' ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) Char
forall {s} {m :: * -> *} {t} {u} {a} {a}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`thenSkip` ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing)

prop_readConditionCommand :: Bool
prop_readConditionCommand = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readConditionCommand String
"[[ x ]] > foo 2>&1"
readConditionCommand :: ParsecT String UserState (SCBase m) Token
readConditionCommand = do
    cmd <- ParsecT String UserState (SCBase m) Token
readCondition
    redirs <- many readIoRedirect
    id <- getNextIdSpanningTokenList (cmd:redirs)

    pos <- getPosition
    hasDashAo <- isFollowedBy $ do
        c <- choice $ try . string <$> ["-o", "-a", "or", "and"]
        posEnd <- getPosition
        parseProblemAtWithEnd pos posEnd ErrorC 1139 $
            "Use " ++ alt c ++ " instead of '" ++ c ++ "' between test commands."

    -- If the next word is a keyword, readNormalWord will trigger a warning
    hasKeyword <- isFollowedBy readKeyword
    hasWord <- isFollowedBy readNormalWord

    when (hasWord && not (hasKeyword || hasDashAo)) $ do
        -- We have other words following, and no error has been emitted.
        posEnd <- getPosition
        parseProblemAtWithEnd pos posEnd ErrorC 1140 "Unexpected parameters after condition. Missing &&/||, or bad expression?"

    return $ T_Redirecting id redirs cmd
  where
    alt :: String -> String
alt String
"or" = String
"||"
    alt String
"-o" = String
"||"
    alt String
"and" = String
"&&"
    alt String
"-a" = String
"&&"
    alt String
_ = String
"|| or &&"

prop_readCompoundCommand :: Bool
prop_readCompoundCommand = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCompoundCommand String
"{ echo foo; }>/dev/null"
readCompoundCommand :: ParsecT String UserState (SCBase m) Token
readCompoundCommand = do
    cmd <- [ParsecT String UserState (SCBase m) Token]
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
        ParsecT String UserState (SCBase m) Token
readBraceGroup,
        String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> (SourcePos -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) Token
forall (m :: * -> *) p.
Monad m =>
String
-> SCParser m p
-> SCParser m p
-> (SourcePos -> SCParser m ())
-> SCParser m p
readAmbiguous String
"((" ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticExpression ParsecT String UserState (SCBase m) Token
readSubshell (\SourcePos
pos ->
            SourcePos
-> Severity
-> Integer
-> String
-> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos
-> Severity -> Integer -> String -> ParsecT s UserState m ()
parseNoteAt SourcePos
pos Severity
ErrorC Integer
1105 String
"Shells disambiguate (( differently or not at all. For subshell, add spaces around ( . For ((, fix parsing errors."),
        ParsecT String UserState (SCBase m) Token
readSubshell,
        ParsecT String UserState (SCBase m) Token
readWhileClause,
        ParsecT String UserState (SCBase m) Token
readUntilClause,
        ParsecT String UserState (SCBase m) Token
readIfClause,
        ParsecT String UserState (SCBase m) Token
readForClause,
        ParsecT String UserState (SCBase m) Token
readSelectClause,
        ParsecT String UserState (SCBase m) Token
readCaseClause,
        ParsecT String UserState (SCBase m) Token
readBatsTest,
        ParsecT String UserState (SCBase m) Token
readFunctionDefinition
        ]
    redirs <- many readIoRedirect
    id <- getNextIdSpanningTokenList (cmd:redirs)
    optional . lookAhead $ do
        notFollowedBy2 $ choice [readKeyword, g_Lbrace]
        pos <- getPosition
        many1 readNormalWord
        posEnd <- getPosition
        parseProblemAtWithEnd pos posEnd ErrorC 1141 "Unexpected tokens after compound command. Bad redirection or missing ;/&&/||/|?"
    return $ T_Redirecting id redirs cmd


readCompoundList :: ParsecT String UserState (SCBase m) [Token]
readCompoundList = ParsecT String UserState (SCBase m) [Token]
readTerm
readCompoundListOrEmpty :: ParsecT String UserState (SCBase m) [Token]
readCompoundListOrEmpty = do
    ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing
    ParsecT String UserState (SCBase m) [Token]
readTerm ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> [Token] -> ParsecT String UserState (SCBase m) [Token]
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return []

readCmdPrefix :: ParsecT String UserState (SCBase m) [Token]
readCmdPrefix = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String UserState (SCBase m) Token
readIoRedirect ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readAssignmentWord)
readCmdSuffix :: ParsecT String UserState (SCBase m) [Token]
readCmdSuffix = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String UserState (SCBase m) Token
readIoRedirect ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readCmdWord)
readModifierSuffix :: ParsecT String UserState (SCBase m) [Token]
readModifierSuffix = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String UserState (SCBase m) Token
readIoRedirect ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readWellFormedAssignment ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readCmdWord)
readTimeSuffix :: ParsecT String UserState (SCBase m) [Token]
readTimeSuffix = do
    flags <- ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT String UserState (SCBase m) Token
readFlag
    pipeline <- readPipeline
    return $ flags ++ [pipeline]
  where
    -- This fails for quoted variables and such. Fixme?
    readFlag :: ParsecT String UserState (SCBase m) Token
readFlag = do
        ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String UserState (SCBase m) Char
 -> ParsecT String UserState (SCBase m) Char)
-> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) Char
forall a b. (a -> b) -> a -> b
$ Char -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'-'
        ParsecT String UserState (SCBase m) Token
readCmdWord

-- Fixme: this is a hack that doesn't handle let c='4'"5" or let a\>b
readLetSuffix :: Monad m => SCParser m [Token]
readLetSuffix :: forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Token]
readLetSuffix = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIoRedirect ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readLetExpression ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readCmdWord)
  where
    readLetExpression :: Monad m => SCParser m Token
    readLetExpression :: forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readLetExpression = do
        startPos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        expression <- readStringForParser readCmdWord
        let (unQuoted, newPos) = kludgeAwayQuotes expression startPos
        subParse newPos (readArithmeticContents <* eof) unQuoted

    kludgeAwayQuotes :: String -> SourcePos -> (String, SourcePos)
    kludgeAwayQuotes :: String -> SourcePos -> (String, SourcePos)
kludgeAwayQuotes String
s SourcePos
p =
        case String
s of
            Char
first:Char
second:String
rest ->
                let (Char
last NE.:| String
backwards) = NonEmpty Char -> NonEmpty Char
forall a. NonEmpty a -> NonEmpty a
NE.reverse (Char
second Char -> String -> NonEmpty Char
forall a. a -> [a] -> NonEmpty a
NE.:| String
rest)
                    middle :: String
middle = String -> String
forall a. [a] -> [a]
reverse String
backwards
                in
                    if Char
first Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
"'\"" Bool -> Bool -> Bool
&& Char
first Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
last
                    then (String
middle, SourcePos -> Char -> SourcePos
updatePosChar SourcePos
p Char
first)
                    else (String
s, SourcePos
p)
            String
x -> (String
s, SourcePos
p)


-- bash allows a=(b), ksh allows $a=(b). dash allows neither. Let's warn.
readEvalSuffix :: ParsecT String UserState (SCBase m) [Token]
readEvalSuffix = ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) [Token]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 (ParsecT String UserState (SCBase m) Token
readIoRedirect ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
readCmdWord ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {m :: * -> *} {u} {b}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s u m b
evalFallback)
  where
    evalFallback :: ParsecT s u m b
evalFallback = do
        pos <- ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        lookAhead $ char '('
        parseProblemAt pos WarningC 1098 "Quote/escape special characters when using eval, e.g. eval \"a=(b)\"."
        fail "Unexpected parentheses. Make sure to quote when eval'ing as shell parsers differ."

-- Get whatever a parser would parse as a string
readStringForParser :: ParsecT s u m a -> ParsecT s u m String
readStringForParser ParsecT s u m a
parser = do
    pos <- ParsecT s u m SourcePos -> ParsecT s u m SourcePos
forall {s} {m :: * -> *} {s} {u} {b}.
MonadState s m =>
ParsecT s u m b -> ParsecT s u m b
inSeparateContext (ParsecT s u m SourcePos -> ParsecT s u m SourcePos)
-> ParsecT s u m SourcePos -> ParsecT s u m SourcePos
forall a b. (a -> b) -> a -> b
$ ParsecT s u m SourcePos -> ParsecT s u m SourcePos
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s u m a
parser ParsecT s u m a
-> ParsecT s u m SourcePos -> ParsecT s u m SourcePos
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition)
    readUntil pos
  where
    readUntil :: SourcePos -> ParsecT s u m String
readUntil SourcePos
endPos = ParsecT s u m Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar ParsecT s u m Char -> ParsecT s u m () -> ParsecT s u m String
forall {s} {m :: * -> *} {t} {u} {a} {a}.
(Stream s m t, Show t) =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m [a]
`reluctantlyTill` (ParsecT s u m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition ParsecT s u m SourcePos
-> (SourcePos -> ParsecT s u m ()) -> ParsecT s u m ()
forall a b.
ParsecT s u m a -> (a -> ParsecT s u m b) -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Bool -> ParsecT s u m ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> ParsecT s u m ())
-> (SourcePos -> Bool) -> SourcePos -> ParsecT s u m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SourcePos -> SourcePos -> Bool
forall a. Eq a => a -> a -> Bool
== SourcePos
endPos))

-- Like readStringForParser, returning the span as a T_Literal
readLiteralForParser :: ParsecT s UserState m a -> ParsecT s UserState m Token
readLiteralForParser ParsecT s UserState m a
parser = do
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    str <- readStringForParser parser
    id <- endSpan start
    return $ T_Literal id str

prop_readAssignmentWord :: Bool
prop_readAssignmentWord = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"a=42"
prop_readAssignmentWord2 :: Bool
prop_readAssignmentWord2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"b=(1 2 3)"
prop_readAssignmentWord5 :: Bool
prop_readAssignmentWord5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"b+=lol"
prop_readAssignmentWord7 :: Bool
prop_readAssignmentWord7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"a[3$n'']=42"
prop_readAssignmentWord8 :: Bool
prop_readAssignmentWord8 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"a[4''$(cat foo)]=42"
prop_readAssignmentWord9 :: Bool
prop_readAssignmentWord9 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"IFS= "
prop_readAssignmentWord9a :: Bool
prop_readAssignmentWord9a = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"foo="
prop_readAssignmentWord9b :: Bool
prop_readAssignmentWord9b = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"foo=  "
prop_readAssignmentWord9c :: Bool
prop_readAssignmentWord9c = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"foo=  #bar"
prop_readAssignmentWord11 :: Bool
prop_readAssignmentWord11 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"foo=([a]=b [c] [d]= [e f )"
prop_readAssignmentWord12 :: Bool
prop_readAssignmentWord12 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"a[b <<= 3 + c]='thing'"
prop_readAssignmentWord13 :: Bool
prop_readAssignmentWord13 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"var=( (1 2) (3 4) )"
prop_readAssignmentWord14 :: Bool
prop_readAssignmentWord14 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"var=( 1 [2]=(3 4) )"
prop_readAssignmentWord15 :: Bool
prop_readAssignmentWord15 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readAssignmentWord String
"var=(1 [2]=(3 4))"
readAssignmentWord :: ParsecT String UserState (SCBase m) Token
readAssignmentWord = Bool -> ParsecT String UserState (SCBase m) Token
readAssignmentWordExt Bool
True
readWellFormedAssignment :: ParsecT String UserState (SCBase m) Token
readWellFormedAssignment = Bool -> ParsecT String UserState (SCBase m) Token
readAssignmentWordExt Bool
False
readAssignmentWordExt :: Bool -> ParsecT String UserState (SCBase m) Token
readAssignmentWordExt Bool
lenient = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"variable assignment" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    -- Parse up to and including the = in a 'try'
    (id, variable, op, indices) <- ParsecT
  String UserState (SCBase m) (Id, String, AssignmentMode, [Token])
-> ParsecT
     String UserState (SCBase m) (Id, String, AssignmentMode, [Token])
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT
   String UserState (SCBase m) (Id, String, AssignmentMode, [Token])
 -> ParsecT
      String UserState (SCBase m) (Id, String, AssignmentMode, [Token]))
-> ParsecT
     String UserState (SCBase m) (Id, String, AssignmentMode, [Token])
-> ParsecT
     String UserState (SCBase m) (Id, String, AssignmentMode, [Token])
forall a b. (a -> b) -> a -> b
$ do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        pos <- getPosition
        -- Check for a leading $ at parse time, to warn for $foo=(bar) which
        -- would otherwise cause a parse failure so it can't be checked later.
        leadingDollarPos <-
            if lenient
            then optionMaybe $ getSpanPositionsFor (char '$')
            else return Nothing
        variable <- readVariableName
        indices <- many readArrayIndex
        hasLeftSpace <- fmap (not . null) spacing
        opStart <- getPosition
        id <- endSpan start
        op <- readAssignmentOp
        opEnd <- getPosition

        when (isJust leadingDollarPos || hasLeftSpace) $ do
            hasParen <- isFollowedBy (spacing >> char '(')
            when hasParen $
                sequence_ $ do
                    (l, r) <- leadingDollarPos
                    return $ parseProblemAtWithEnd l r ErrorC 1066 "Don't use $ on the left side of assignments."

            -- Fail so that this is not parsed as an assignment.
            fail ""
        -- At this point we know for sure.
        return (id, variable, op, indices)

    rightPosStart <- getPosition
    hasRightSpace <- fmap (not . null) spacing
    rightPosEnd <- getPosition
    isEndOfCommand <- fmap isJust $ optionMaybe (try . lookAhead $ (void (oneOf "\r\n;&|)") <|> eof))

    if hasRightSpace || isEndOfCommand
      then do
        when (variable /= "IFS" && hasRightSpace && not isEndOfCommand) $ do
            parseProblemAtWithEnd rightPosStart rightPosEnd WarningC 1007
                "Remove space after = if trying to assign a value (for empty string, use var='' ... )."
        value <- readEmptyLiteral
        return $ T_Assignment id op variable indices value
      else do
        optional $ do
            lookAhead $ char '='
            parseProblem ErrorC 1097 "Unexpected ==. For assignment, use =. For comparison, use [/[[. Or quote for literal string."

        value <- readArray <|> readNormalWord
        spacing
        return $ T_Assignment id op variable indices value
  where
    readAssignmentOp :: ParsecT s u m AssignmentMode
readAssignmentOp = do
        -- This is probably some kind of ascii art border
        String -> ParsecT s u m String -> ParsecT s u m ()
forall {s} {u} {m :: * -> *} {a}.
String -> ParsecT s u m a -> ParsecT s u m ()
unexpecting String
"===" (String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"===")
        [ParsecT s u m AssignmentMode] -> ParsecT s u m AssignmentMode
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
            String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"+=" ParsecT s u m String
-> ParsecT s u m AssignmentMode -> ParsecT s u m AssignmentMode
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> AssignmentMode -> ParsecT s u m AssignmentMode
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return AssignmentMode
Append,
            String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"=" ParsecT s u m String
-> ParsecT s u m AssignmentMode -> ParsecT s u m AssignmentMode
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> AssignmentMode -> ParsecT s u m AssignmentMode
forall a. a -> ParsecT s u m a
forall (m :: * -> *) a. Monad m => a -> m a
return AssignmentMode
Assign
            ]

readEmptyLiteral :: ParsecT s UserState m Token
readEmptyLiteral = do
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    id <- endSpan start
    return $ T_Literal id ""

readArrayIndex :: ParsecT String UserState (SCBase m) Token
readArrayIndex = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char '['
    pos <- getPosition
    str <- readStringForParser readIndexSpan
    char ']'
    id <- endSpan start
    return $ T_UnparsedIndex id pos str

readArray :: Monad m => SCParser m Token
readArray :: forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArray = String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"array assignment" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    opening <- getPosition
    char '('
    optional $ do
        lookAhead $ char '('
        parseProblemAt opening ErrorC 1116 "Missing $ on a $((..)) expression? (or use ( ( for arrays)."
    allspacing
    words <- readElement `reluctantlyTill` char ')'
    char ')' <|> fail "Expected ) to close array assignment"
    id <- endSpan start
    return $ T_Array id words
  where
    readElement :: ParsecT String UserState (SCBase m) Token
readElement = (ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIndexed ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readRegular) ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {t} {u} {a} {a}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`thenSkip` ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacing
    readIndexed :: ParsecT String UserState (SCBase m) Token
readIndexed = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        index <- try $ do
            x <- many1 readArrayIndex
            char '='
            return x
        value <- readRegular <|> nothing
        id <- endSpan start
        return $ T_IndexedElement id index value
    readRegular :: ParsecT String UserState (SCBase m) Token
readRegular = ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArray ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readNormalWord

    nothing :: ParsecT s UserState m Token
nothing = do
        start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        id <- endSpan start
        return $ T_Literal id ""

tryToken :: String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
s Id -> a
t = ParsecT s UserState m a -> ParsecT s UserState m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s UserState m a -> ParsecT s UserState m a)
-> ParsecT s UserState m a -> ParsecT s UserState m a
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    string s
    id <- endSpan start
    spacing
    return $ t id

redirToken :: Char -> (Id -> a) -> ParsecT s UserState m a
redirToken Char
c Id -> a
t = ParsecT s UserState m a -> ParsecT s UserState m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT s UserState m a -> ParsecT s UserState m a)
-> ParsecT s UserState m a -> ParsecT s UserState m a
forall a b. (a -> b) -> a -> b
$ do
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char c
    id <- endSpan start
    notFollowedBy2 $ char '('
    return $ t id

tryWordToken :: String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
s Id -> a
t = String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryParseWordToken String
s Id -> a
t ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) a
forall {s} {m :: * -> *} {t} {u} {a} {a}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
`thenSkip` ParsecT String UserState (SCBase m) String
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m String
spacing
tryParseWordToken :: String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryParseWordToken String
keyword Id -> a
t = ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) a
 -> ParsecT String UserState (SCBase m) a)
-> ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) a
forall a b. (a -> b) -> a -> b
$ do
    pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
    start <- startSpan
    str <- anycaseString keyword
    id <- endSpan start

    optional $ do
        c <- try . lookAhead $ anyChar
        let warning Integer
code = Severity -> Integer -> String -> ParsecT s u m ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
code (String -> ParsecT s u m ()) -> String -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ String
"You need a space before the " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
c] String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."
        case c of
            Char
'[' -> Integer -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Integer -> ParsecT s u m ()
warning Integer
1069
            Char
'#' -> Integer -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Integer -> ParsecT s u m ()
warning Integer
1099
            Char
'!' -> Integer -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Integer -> ParsecT s u m ()
warning Integer
1129
            Char
':' -> Integer -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Integer -> ParsecT s u m ()
warning Integer
1130
            Char
_ -> () -> ParsecT String UserState (SCBase m) ()
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

    lookAhead keywordSeparator
    when (str /= keyword) $ do
        parseProblemAt pos ErrorC 1081 $
            "Scripts are case sensitive. Use '" ++ keyword ++ "', not '" ++ str ++ "' (or quote if literal)."
        fail ""
    return $ t id

anycaseString :: t Char -> ParsecT s u m (t Char)
anycaseString =
    (Char -> ParsecT s u m Char) -> t Char -> ParsecT s u m (t Char)
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> t a -> m (t b)
mapM Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
anycaseChar
  where
    anycaseChar :: Char -> ParsecT s u m Char
anycaseChar Char
c = Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char (Char -> Char
toLower Char
c) ParsecT s u m Char -> ParsecT s u m Char -> ParsecT s u m Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> Char -> ParsecT s u m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char (Char -> Char
toUpper Char
c)

g_AND_IF :: ParsecT s UserState m Token
g_AND_IF = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
"&&" Id -> Token
T_AND_IF
g_OR_IF :: ParsecT s UserState m Token
g_OR_IF = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
"||" Id -> Token
T_OR_IF
g_DSEMI :: ParsecT s UserState m Token
g_DSEMI = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
";;" Id -> Token
T_DSEMI
g_DLESS :: ParsecT s UserState m Token
g_DLESS = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
"<<" Id -> Token
T_DLESS
g_DGREAT :: ParsecT s UserState m Token
g_DGREAT = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
">>" Id -> Token
T_DGREAT
g_LESSAND :: ParsecT s UserState m Token
g_LESSAND = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
"<&" Id -> Token
T_LESSAND
g_GREATAND :: ParsecT s UserState m Token
g_GREATAND = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
">&" Id -> Token
T_GREATAND
g_LESSGREAT :: ParsecT s UserState m Token
g_LESSGREAT = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
"<>" Id -> Token
T_LESSGREAT
g_DLESSDASH :: ParsecT s UserState m Token
g_DLESSDASH = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
"<<-" Id -> Token
T_DLESSDASH
g_CLOBBER :: ParsecT s UserState m Token
g_CLOBBER = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
">|" Id -> Token
T_CLOBBER
g_OPERATOR :: ParsecT s UserState m Token
g_OPERATOR = ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_AND_IF ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_OR_IF ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_DSEMI ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_DLESSDASH ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_DLESS ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_DGREAT ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_LESSAND ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_GREATAND ParsecT s UserState m Token
-> ParsecT s UserState m Token -> ParsecT s UserState m Token
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_LESSGREAT

g_If :: ParsecT String UserState (SCBase m) Token
g_If = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"if" Id -> Token
T_If
g_Then :: ParsecT String UserState (SCBase m) Token
g_Then = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"then" Id -> Token
T_Then
g_Else :: ParsecT String UserState (SCBase m) Token
g_Else = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"else" Id -> Token
T_Else
g_Elif :: ParsecT String UserState (SCBase m) Token
g_Elif = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"elif" Id -> Token
T_Elif
g_Fi :: ParsecT String UserState (SCBase m) Token
g_Fi = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"fi" Id -> Token
T_Fi
g_Do :: ParsecT String UserState (SCBase m) Token
g_Do = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"do" Id -> Token
T_Do
g_Done :: ParsecT String UserState (SCBase m) Token
g_Done = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"done" Id -> Token
T_Done
g_Case :: ParsecT String UserState (SCBase m) Token
g_Case = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"case" Id -> Token
T_Case
g_Esac :: ParsecT String UserState (SCBase m) Token
g_Esac = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"esac" Id -> Token
T_Esac
g_While :: ParsecT String UserState (SCBase m) Token
g_While = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"while" Id -> Token
T_While
g_Until :: ParsecT String UserState (SCBase m) Token
g_Until = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"until" Id -> Token
T_Until
g_For :: ParsecT String UserState (SCBase m) Token
g_For = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"for" Id -> Token
T_For
g_Select :: ParsecT String UserState (SCBase m) Token
g_Select = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"select" Id -> Token
T_Select
g_In :: ParsecT String UserState (SCBase m) Token
g_In = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"in" Id -> Token
T_In ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) Token
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m ()
skipAnnotationAndWarn
g_Lbrace :: ParsecT String UserState (SCBase m) Token
g_Lbrace = String
-> (Id -> Token) -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {a}.
Monad m =>
String -> (Id -> a) -> ParsecT String UserState (SCBase m) a
tryWordToken String
"{" Id -> Token
T_Lbrace
g_Rbrace :: ParsecT s UserState m Token
g_Rbrace = do -- handled specially due to ksh echo "${ foo; }bar"
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char '}'
    id <- endSpan start
    return $ T_Rbrace id

g_Lparen :: ParsecT s UserState m Token
g_Lparen = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
"(" Id -> Token
T_Lparen
g_Rparen :: ParsecT s UserState m Token
g_Rparen = String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
")" Id -> Token
T_Rparen
g_Bang :: ParsecT s UserState m Token
g_Bang = do
    start <- ParsecT s UserState m IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    char '!'
    id <- endSpan start
    void spacing1 <|> do
        pos <- getPosition
        parseProblemAt pos ErrorC 1035
            "You are missing a required space after the !."
    return $ T_Bang id

g_Semi :: ParsecT s UserState m Token
g_Semi = do
    ParsecT s UserState m Token -> ParsecT s UserState m ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 ParsecT s UserState m Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_DSEMI
    String -> (Id -> Token) -> ParsecT s UserState m Token
forall {m :: * -> *} {s} {m :: * -> *} {a}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
String -> (Id -> a) -> ParsecT s UserState m a
tryToken String
";" Id -> Token
T_Semi

keywordSeparator :: ParsecT String UserState (SCBase m) ()
keywordSeparator =
    ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacingOrFail) ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (String -> ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf String
";()[<>&|")

readKeyword :: ParsecT String UserState (SCBase m) Token
readKeyword = [ParsecT String UserState (SCBase m) Token]
-> ParsecT String UserState (SCBase m) Token
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [ ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Then, ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Else, ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Elif, ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Fi, ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Do, ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Done, ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
g_Esac, ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s}.
Stream s m Char =>
ParsecT s UserState m Token
g_Rbrace, ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_Rparen, ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_DSEMI ]

ifParse :: ParsecT s u m a
-> ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
ifParse ParsecT s u m a
p ParsecT s u m a
t ParsecT s u m a
f =
    (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 (ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try ParsecT s u m a
p) ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
forall a b. ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT s u m a
t) ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT s u m a
f

prop_readShebang1 :: Bool
prop_readShebang1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readShebang String
"#!/bin/sh\n"
prop_readShebang2 :: Bool
prop_readShebang2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readShebang String
"!# /bin/sh\n"
prop_readShebang3 :: Bool
prop_readShebang3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readShebang String
"#shellcheck shell=/bin/sh\n"
prop_readShebang4 :: Bool
prop_readShebang4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readShebang String
"! /bin/sh"
prop_readShebang5 :: Bool
prop_readShebang5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readShebang String
"\n#!/bin/sh"
prop_readShebang6 :: Bool
prop_readShebang6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readShebang String
" # Copyright \n!#/bin/bash"
prop_readShebang7 :: Bool
prop_readShebang7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readShebang String
"# Copyright \nfoo\n#!/bin/bash"
readShebang :: ParsecT String UserState (SCBase m) Token
readShebang = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    anyShebang <|> try readMissingBang <|> withHeader
    many linewhitespace
    str <- many $ noneOf "\r\n"
    id <- endSpan start
    optional carriageReturn
    optional linefeed
    return $ T_Literal id str
  where
    anyShebang :: ParsecT String UserState (SCBase m) ()
anyShebang = [ParsecT String UserState (SCBase m) ()]
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice ([ParsecT String UserState (SCBase m) ()]
 -> ParsecT String UserState (SCBase m) ())
-> [ParsecT String UserState (SCBase m) ()]
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> [ParsecT String UserState (SCBase m) ()]
-> [ParsecT String UserState (SCBase m) ()]
forall a b. (a -> b) -> [a] -> [b]
map ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try [
        ParsecT String UserState (SCBase m) ()
forall {s} {m :: * -> *} {u}. Stream s m Char => ParsecT s u m ()
readCorrect,
        ParsecT String UserState (SCBase m) ()
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) ()
readSwapped,
        ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m ()
readTooManySpaces,
        ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {s} {m :: * -> *}.
(MonadState SystemState m, Stream s m Char,
 MonadReader (Environment m) m) =>
ParsecT s UserState m ()
readMissingHash
        ]
    readCorrect :: ParsecT s u m ()
readCorrect = ParsecT s u m String -> ParsecT s u m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ParsecT s u m String -> ParsecT s u m ())
-> ParsecT s u m String -> ParsecT s u m ()
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"#!"

    readSwapped :: ParsecT String UserState (SCBase m) ()
readSwapped = do
        start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
        string "!#"
        id <- endSpan start
        parseProblemAtId id ErrorC 1084
            "Use #!, not !#, for the shebang."

    skipSpaces :: ParsecT s UserState m Bool
skipSpaces = (String -> Bool)
-> ParsecT s UserState m String -> ParsecT s UserState m Bool
forall a b.
(a -> b) -> ParsecT s UserState m a -> ParsecT s UserState m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null) (ParsecT s UserState m String -> ParsecT s UserState m Bool)
-> ParsecT s UserState m String -> ParsecT s UserState m Bool
forall a b. (a -> b) -> a -> b
$ ParsecT s UserState m Char -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT s UserState m Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
linewhitespace
    readTooManySpaces :: ParsecT s UserState m ()
readTooManySpaces = do
        startPos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        startSpaces <- skipSpaces
        char '#'
        middlePos <- getPosition
        middleSpaces <- skipSpaces
        char '!'
        when startSpaces $
            parseProblemAt startPos ErrorC 1114
                "Remove leading spaces before the shebang."
        when middleSpaces $
            parseProblemAt middlePos ErrorC 1115
                "Remove spaces between # and ! in the shebang."

    readMissingHash :: ParsecT s UserState m ()
readMissingHash = do
        pos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        char '!'
        ensurePathAhead
        parseProblemAt pos ErrorC 1104
            "Use #!, not just !, for the shebang."

    readMissingBang :: ParsecT s UserState m ()
readMissingBang = do
        Char -> ParsecT s UserState m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'#'
        pos <- ParsecT s UserState m SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        ensurePathAhead
        parseProblemAt pos ErrorC 1113
            "Use #!, not just #, for the shebang."

    ensurePathAhead :: ParsecT s UserState m Char
ensurePathAhead = ParsecT s UserState m Char -> ParsecT s UserState m Char
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT s UserState m Char -> ParsecT s UserState m Char)
-> ParsecT s UserState m Char -> ParsecT s UserState m Char
forall a b. (a -> b) -> a -> b
$ do
        ParsecT s UserState m Char -> ParsecT s UserState m String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT s UserState m Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
linewhitespace
        Char -> ParsecT s UserState m Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
'/'

    withHeader :: ParsecT String UserState (SCBase m) ()
withHeader = ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ do
        ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
headerLine
        pos <- ParsecT String UserState (SCBase m) SourcePos
forall (m :: * -> *) s u. Monad m => ParsecT s u m SourcePos
getPosition
        anyShebang <*
            parseProblemAt pos ErrorC 1128 "The shebang must be on the first line. Delete blanks and move comments."

    headerLine :: ParsecT String UserState (SCBase m) Char
headerLine = do
        ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall {s} {u} {m :: * -> *} {a}.
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy2 ParsecT String UserState (SCBase m) ()
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) ()
anyShebang
        ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ParsecT String UserState (SCBase m) Char
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Char
linewhitespace
        ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readAnyComment
        ParsecT String UserState (SCBase m) Char
forall (m :: * -> *). Monad m => SCParser m Char
linefeed

verifyEof :: ParsecT String UserState (SCBase m) ()
verifyEof = ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> [ParsecT String UserState (SCBase m) ()]
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
[ParsecT s u m a] -> ParsecT s u m a
choice [
        ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall {s} {m :: * -> *} {t} {u} {a} {b}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
ifParsable ParsecT String UserState (SCBase m) Token
forall {s} {m :: * -> *} {m :: * -> *}.
(Stream s m Char, MonadState SystemState m,
 MonadReader (Environment m) m) =>
ParsecT s UserState m Token
g_Lparen (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$
            Severity
-> Integer -> String -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1088 String
"Parsing stopped here. Invalid use of parentheses?",

        ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall {s} {m :: * -> *} {t} {u} {a} {b}.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
ifParsable ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readKeyword (ParsecT String UserState (SCBase m) ()
 -> ParsecT String UserState (SCBase m) ())
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall a b. (a -> b) -> a -> b
$
            Severity
-> Integer -> String -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1089 String
"Parsing stopped here. Is this keyword correctly matched up?",

        Severity
-> Integer -> String -> ParsecT String UserState (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1070 String
"Parsing stopped here. Mismatched keywords or invalid parentheses?"
    ]
  where
    ifParsable :: ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m b
ifParsable ParsecT s u m a
p ParsecT s u m b
action = do
        ParsecT s u m a -> ParsecT s u m a
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try (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 ParsecT s u m a
p)
        ParsecT s u m b
action


readConfigFile :: Monad m => FilePath -> SCParser m [Annotation]
readConfigFile :: forall (m :: * -> *). Monad m => String -> SCParser m [Annotation]
readConfigFile String
filename = do
    shouldIgnore <- (Environment m -> Bool) -> ParsecT String UserState (SCBase m) Bool
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
Mr.asks Environment m -> Bool
forall (m :: * -> *). Environment m -> Bool
ignoreRC
    if shouldIgnore then return [] else read' filename
  where
    read' :: String
-> ParsecT
     s u (ReaderT (Environment m) (StateT SystemState m)) [Annotation]
read' String
filename = do
        sys <- (Environment m -> SystemInterface m)
-> ParsecT
     s
     u
     (ReaderT (Environment m) (StateT SystemState m))
     (SystemInterface m)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
Mr.asks Environment m -> SystemInterface m
forall (m :: * -> *). Environment m -> SystemInterface m
systemInterface
        contents <- system $ siGetConfig sys filename
        case contents of
            Maybe (String, String)
Nothing -> [Annotation]
-> ParsecT
     s u (ReaderT (Environment m) (StateT SystemState m)) [Annotation]
forall a.
a -> ParsecT s u (ReaderT (Environment m) (StateT SystemState m)) a
forall (m :: * -> *) a. Monad m => a -> m a
return []
            Just (String
file, String
str) -> String
-> String
-> ParsecT
     s u (ReaderT (Environment m) (StateT SystemState m)) [Annotation]
forall {m :: * -> *} {s} {u}.
Monad m =>
String -> String -> ParsecT s u (SCBase m) [Annotation]
readConfig String
file String
str

    readConfig :: String -> String -> ParsecT s u (SCBase m) [Annotation]
readConfig String
filename String
contents = do
        result <- SCBase m (Either ParseError [Annotation])
-> ParsecT s u (SCBase m) (Either ParseError [Annotation])
forall (m :: * -> *) a. Monad m => m a -> ParsecT s u m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (SCBase m (Either ParseError [Annotation])
 -> ParsecT s u (SCBase m) (Either ParseError [Annotation]))
-> SCBase m (Either ParseError [Annotation])
-> ParsecT s u (SCBase m) (Either ParseError [Annotation])
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) [Annotation]
-> UserState
-> String
-> String
-> SCBase m (Either ParseError [Annotation])
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> u -> String -> s -> m (Either ParseError a)
runParserT ParsecT String UserState (SCBase m) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readConfigKVs UserState
initialUserState String
filename String
contents
        case result of
            Right [Annotation]
result ->
                [Annotation] -> ParsecT s u (SCBase m) [Annotation]
forall a. a -> ParsecT s u (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return [Annotation]
result

            Left ParseError
err -> do
                Severity -> Integer -> String -> ParsecT s u (SCBase m) ()
forall {m :: * -> *} {m :: * -> *} {s} {u}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
Severity -> Integer -> String -> ParsecT s u m ()
parseProblem Severity
ErrorC Integer
1134 (String -> ParsecT s u (SCBase m) ())
-> String -> ParsecT s u (SCBase m) ()
forall a b. (a -> b) -> a -> b
$ String -> ParseError -> String
errorFor String
filename ParseError
err
                [Annotation] -> ParsecT s u (SCBase m) [Annotation]
forall a. a -> ParsecT s u (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return []

    errorFor :: String -> ParseError -> String
errorFor String
filename ParseError
err =
        let line :: String
line = String
"line " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Line -> String
forall a. Show a => a -> String
show (Line -> String) -> (SourcePos -> Line) -> SourcePos -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SourcePos -> Line
sourceLine (SourcePos -> String) -> SourcePos -> String
forall a b. (a -> b) -> a -> b
$ ParseError -> SourcePos
errorPos ParseError
err)
            suggestion :: String
suggestion = [Message] -> String
getStringFromParsec ([Message] -> String) -> [Message] -> String
forall a b. (a -> b) -> a -> b
$ ParseError -> [Message]
errorMessages ParseError
err
        in
            String
"Failed to process " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String -> String
e4m String
filename) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
line String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": "
                String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
suggestion

prop_readConfigKVs1 :: Bool
prop_readConfigKVs1 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readConfigKVs String
"disable=1234"
prop_readConfigKVs2 :: Bool
prop_readConfigKVs2 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readConfigKVs String
"# Comment\ndisable=1234 # Comment\n"
prop_readConfigKVs3 :: Bool
prop_readConfigKVs3 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readConfigKVs String
""
prop_readConfigKVs4 :: Bool
prop_readConfigKVs4 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readConfigKVs String
"\n\n\n\n\t \n"
prop_readConfigKVs5 :: Bool
prop_readConfigKVs5 = ParsecT String UserState (SCBase Identity) [Annotation]
-> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) [Annotation]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [Annotation]
readConfigKVs String
"# shellcheck accepts annotation-like comments in rc files\ndisable=1234"
readConfigKVs :: ParsecT String UserState (SCBase m) [Annotation]
readConfigKVs = do
    ParsecT String UserState (SCBase m) [()]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [()]
anySpacingOrComment
    annotations <- ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [[Annotation]]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (Bool -> ParsecT String UserState (SCBase m) [Annotation]
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) [Annotation]
readAnnotationWithoutPrefix Bool
False ParsecT String UserState (SCBase m) [Annotation]
-> ParsecT String UserState (SCBase m) [()]
-> ParsecT String UserState (SCBase m) [Annotation]
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT String UserState (SCBase m) [()]
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) [()]
anySpacingOrComment)
    eof
    return $ concat annotations
anySpacingOrComment :: ParsecT String UserState (SCBase m) [()]
anySpacingOrComment =
    ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) [()]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) String
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) String
allspacingOrFail ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) String
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) String
forall {s} {m :: * -> *} {u}.
Stream s m Char =>
ParsecT s u m String
readAnyComment)

prop_readScript1 :: Bool
prop_readScript1 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"#!/bin/bash\necho hello world\n"
prop_readScript2 :: Bool
prop_readScript2 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"#!/bin/bash\r\necho hello world\n"
prop_readScript3 :: Bool
prop_readScript3 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"#!/bin/bash\necho hello\xA0world"
prop_readScript4 :: Bool
prop_readScript4 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"#!/usr/bin/perl\nfoo=("
prop_readScript5 :: Bool
prop_readScript5 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"#!/bin/bash\n#This is an empty script\n\n"
prop_readScript6 :: Bool
prop_readScript6 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"#!/usr/bin/env -S X=FOO bash\n#This is an empty script\n\n"
prop_readScript7 :: Bool
prop_readScript7 = ParsecT String UserState (SCBase Identity) Token -> String -> Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript String
"#!/bin/zsh\n# shellcheck disable=SC1071\nfor f (a b); echo $f\n"
readScriptFile :: Bool -> ParsecT String UserState (SCBase m) Token
readScriptFile Bool
sourced = do
    start <- ParsecT String UserState (SCBase m) IncompleteInterval
forall {m :: * -> *} {s} {u}.
Monad m =>
ParsecT s u m IncompleteInterval
startSpan
    pos <- getPosition
    rcAnnotations <- if sourced
                     then return []
                     else do
                        filename <- Mr.asks currentFilename
                        readConfigFile filename

    -- Put the rc annotations on the stack so that one can ignore e.g. SC1084 in .shellcheckrc
    withAnnotations rcAnnotations $ do
        hasBom <- wasIncluded readUtf8Bom
        shebang <- readShebang <|> readEmptyLiteral
        let (T_Literal _ shebangString) = shebang
        allspacing
        annotationStart <- startSpan
        fileAnnotations <- readAnnotations

        -- Similarly put the filewide annotations on the stack to allow earlier suppression
        withAnnotations fileAnnotations $ do
            when (hasBom) $
                parseProblemAt pos ErrorC 1082
                    "This file has a UTF-8 BOM. Remove it with: LC_CTYPE=C sed '1s/^...//' < yourscript ."
            let annotations = [Annotation]
fileAnnotations [Annotation] -> [Annotation] -> [Annotation]
forall a. [a] -> [a] -> [a]
++ [Annotation]
rcAnnotations
            annotationId <- endSpan annotationStart
            let shellAnnotationSpecified =
                    (Annotation -> Bool) -> [Annotation] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Annotation
x -> case Annotation
x of ShellOverride {} -> Bool
True; Annotation
_ -> Bool
False) [Annotation]
annotations
            shellFlagSpecified <- isJust <$> Mr.asks shellTypeOverride
            let ignoreShebang = Bool
shellAnnotationSpecified Bool -> Bool -> Bool
|| Bool
shellFlagSpecified

            unless ignoreShebang $
                verifyShebang pos (executableFromShebang shebangString)
            if ignoreShebang || isValidShell (executableFromShebang shebangString) /= Just False
              then do
                    commands <- readCompoundListOrEmpty
                    id <- endSpan start
                    readPendingHereDocs
                    verifyEof
                    let script = Id -> [Annotation] -> Token -> Token
T_Annotation Id
annotationId [Annotation]
annotations (Token -> Token) -> Token -> Token
forall a b. (a -> b) -> a -> b
$
                                    Id -> Token -> [Token] -> Token
T_Script Id
id Token
shebang [Token]
commands
                    userstate <- getState
                    reparseIndices $ reattachHereDocs script (hereDocMap userstate)
                else do
                    many anyChar
                    id <- endSpan start
                    return $ T_Script id shebang []

  where
    verifyShebang :: SourcePos -> String -> m ()
verifyShebang SourcePos
pos String
s = do
        case String -> Maybe Bool
isValidShell String
s of
            Just Bool
True -> () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
            Just Bool
False -> SourcePos -> Severity -> Integer -> String -> m ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
pos Severity
ErrorC Integer
1071 String
"ShellCheck only supports sh/bash/dash/ksh/'busybox sh' scripts. Sorry!"
            Maybe Bool
Nothing -> SourcePos -> Severity -> Integer -> String -> m ()
forall {m :: * -> *} {m :: * -> *}.
(MonadState SystemState m, MonadReader (Environment m) m) =>
SourcePos -> Severity -> Integer -> String -> m ()
parseProblemAt SourcePos
pos Severity
ErrorC Integer
1008 String
"This shebang was unrecognized. ShellCheck only supports sh/bash/dash/ksh/'busybox sh'. Add a 'shell' directive to specify."

    isValidShell :: String -> Maybe Bool
isValidShell String
s =
        let good :: Bool
good = String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
s Bool -> Bool -> Bool
|| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
s) [String]
goodShells
            bad :: Bool
bad = (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
s) [String]
badShells
        in
            if Bool
good
                then Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
                else if Bool
bad
                        then Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
                        else Maybe Bool
forall a. Maybe a
Nothing

    goodShells :: [String]
goodShells = [
        String
"sh",
        String
"ash",
        String
"dash",
        String
"busybox sh",
        String
"bash",
        String
"bats",
        String
"ksh"
        ]
    badShells :: [String]
badShells = [
        String
"awk",
        String
"csh",
        String
"expect",
        String
"fish",
        String
"perl",
        String
"python",
        String
"ruby",
        String
"tcsh",
        String
"zsh"
        ]

    readUtf8Bom :: ParsecT s u m String
readUtf8Bom = String -> ParsecT s u m String -> ParsecT s u m String
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"Byte Order Mark" (ParsecT s u m String -> ParsecT s u m String)
-> ParsecT s u m String -> ParsecT s u m String
forall a b. (a -> b) -> a -> b
$ String -> ParsecT s u m String
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m String
string String
"\xFEFF"

readScript :: ParsecT String UserState (SCBase m) Token
readScript = Bool -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
Bool -> ParsecT String UserState (SCBase m) Token
readScriptFile Bool
False

-- Interactively run a specific parser in ghci:
-- debugParse readSimpleCommand "echo 'hello world'"
debugParse :: SCParser Identity v -> String -> Either ParseError v
debugParse SCParser Identity v
p String
string = Identity (Either ParseError v) -> Either ParseError v
forall a. Identity a -> a
runIdentity (Identity (Either ParseError v) -> Either ParseError v)
-> Identity (Either ParseError v) -> Either ParseError v
forall a b. (a -> b) -> a -> b
$ do
    (res, _) <- Environment Identity
-> SCParser Identity v
-> String
-> String
-> Identity (Either ParseError v, SystemState)
forall (m :: * -> *) v.
Monad m =>
Environment m
-> SCParser m v
-> String
-> String
-> m (Either ParseError v, SystemState)
runParser Environment Identity
testEnvironment SCParser Identity v
p String
"-" String
string
    return res

-- Interactively run the complete parser in ghci:
-- debugParseScript "#!/bin/bash\necho 'Hello World'\n"
debugParseScript :: String -> ParseResult
debugParseScript String
string =
    ParseResult
result {
        -- Remove the noisiest parts
        prTokenPositions = Map.fromList [
            (Id 0, (newPosition {
                posFile = "removed for clarity",
                posLine = -1,
                posColumn = -1
            }, newPosition {
                posFile = "removed for clarity",
                posLine = -1,
                posColumn = -1
            }))]
    }
  where
    result :: ParseResult
result = Identity ParseResult -> ParseResult
forall a. Identity a -> a
runIdentity (Identity ParseResult -> ParseResult)
-> Identity ParseResult -> ParseResult
forall a b. (a -> b) -> a -> b
$
        SystemInterface Identity -> ParseSpec -> Identity ParseResult
forall (m :: * -> *).
Monad m =>
SystemInterface m -> ParseSpec -> m ParseResult
parseScript ([(String, String)] -> SystemInterface Identity
mockedSystemInterface []) (ParseSpec -> Identity ParseResult)
-> ParseSpec -> Identity ParseResult
forall a b. (a -> b) -> a -> b
$ ParseSpec
newParseSpec {
            psFilename = "debug",
            psScript = string
        }

testEnvironment :: Environment Identity
testEnvironment =
    Environment {
        systemInterface :: SystemInterface Identity
systemInterface = ([(String, String)] -> SystemInterface Identity
mockedSystemInterface []),
        checkSourced :: Bool
checkSourced = Bool
False,
        currentFilename :: String
currentFilename = String
"myscript",
        ignoreRC :: Bool
ignoreRC = Bool
False,
        shellTypeOverride :: Maybe Shell
shellTypeOverride = Maybe Shell
forall a. Maybe a
Nothing
    }


isOk :: ParsecT String UserState (SCBase Identity) a -> String -> Bool
isOk ParsecT String UserState (SCBase Identity) a
p String
s =      ParsecT String UserState (SCBase Identity) a
-> String -> Maybe Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a
-> String -> Maybe Bool
parsesCleanly ParsecT String UserState (SCBase Identity) a
p String
s Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True   -- The string parses with no warnings
isWarning :: ParsecT String UserState (SCBase Identity) a -> String -> Bool
isWarning ParsecT String UserState (SCBase Identity) a
p String
s = ParsecT String UserState (SCBase Identity) a
-> String -> Maybe Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a
-> String -> Maybe Bool
parsesCleanly ParsecT String UserState (SCBase Identity) a
p String
s Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False  -- The string parses with warnings
isNotOk :: ParsecT String UserState (SCBase Identity) a -> String -> Bool
isNotOk ParsecT String UserState (SCBase Identity) a
p String
s =   ParsecT String UserState (SCBase Identity) a
-> String -> Maybe Bool
forall {a}.
ParsecT String UserState (SCBase Identity) a
-> String -> Maybe Bool
parsesCleanly ParsecT String UserState (SCBase Identity) a
p String
s Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe Bool
forall a. Maybe a
Nothing     -- The string does not parse

parsesCleanly :: ParsecT String UserState (SCBase Identity) a
-> String -> Maybe Bool
parsesCleanly ParsecT String UserState (SCBase Identity) a
parser String
string = Identity (Maybe Bool) -> Maybe Bool
forall a. Identity a -> a
runIdentity (Identity (Maybe Bool) -> Maybe Bool)
-> Identity (Maybe Bool) -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ do
    (res, sys) <- Environment Identity
-> SCParser Identity UserState
-> String
-> String
-> Identity (Either ParseError UserState, SystemState)
forall (m :: * -> *) v.
Monad m =>
Environment m
-> SCParser m v
-> String
-> String
-> m (Either ParseError v, SystemState)
runParser Environment Identity
testEnvironment
                    (ParsecT String UserState (SCBase Identity) a
parser ParsecT String UserState (SCBase Identity) a
-> ParsecT String UserState (SCBase Identity) ()
-> ParsecT String UserState (SCBase Identity) ()
forall a b.
ParsecT String UserState (SCBase Identity) a
-> ParsecT String UserState (SCBase Identity) b
-> ParsecT String UserState (SCBase Identity) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT String UserState (SCBase Identity) ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof ParsecT String UserState (SCBase Identity) ()
-> SCParser Identity UserState -> SCParser Identity UserState
forall a b.
ParsecT String UserState (SCBase Identity) a
-> ParsecT String UserState (SCBase Identity) b
-> ParsecT String UserState (SCBase Identity) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> SCParser Identity UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState) String
"-" String
string
    case (res, sys) of
        (Right UserState
userState, SystemState
systemState) ->
            Maybe Bool -> Identity (Maybe Bool)
forall a. a -> Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Bool -> Identity (Maybe Bool))
-> Maybe Bool -> Identity (Maybe Bool)
forall a b. (a -> b) -> a -> b
$ Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Bool -> Maybe Bool)
-> ([ParseNote] -> Bool) -> [ParseNote] -> Maybe Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ParseNote] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([ParseNote] -> Maybe Bool) -> [ParseNote] -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ UserState -> [ParseNote]
parseNotes UserState
userState [ParseNote] -> [ParseNote] -> [ParseNote]
forall a. [a] -> [a] -> [a]
++ SystemState -> [ParseNote]
parseProblems SystemState
systemState
        (Left ParseError
_, SystemState
_) -> Maybe Bool -> Identity (Maybe Bool)
forall a. a -> Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Bool
forall a. Maybe a
Nothing

parseWithNotes :: ParsecT s b m a -> ParsecT s b m (a, b)
parseWithNotes ParsecT s b m a
parser = do
    item <- ParsecT s b m a
parser
    state <- getState
    return (item, state)

compareNotes :: ParseNote -> ParseNote -> Ordering
compareNotes (ParseNote SourcePos
pos1 SourcePos
pos1' Severity
level1 Integer
_ String
s1) (ParseNote SourcePos
pos2 SourcePos
pos2' Severity
level2 Integer
_ String
s2) = (SourcePos, SourcePos, Severity)
-> (SourcePos, SourcePos, Severity) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (SourcePos
pos1, SourcePos
pos1', Severity
level1) (SourcePos
pos2, SourcePos
pos2', Severity
level2)
sortNotes :: [ParseNote] -> [ParseNote]
sortNotes = (ParseNote -> ParseNote -> Ordering) -> [ParseNote] -> [ParseNote]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy ParseNote -> ParseNote -> Ordering
compareNotes


makeErrorFor :: ParseError -> ParseNote
makeErrorFor ParseError
parsecError =
    SourcePos
-> SourcePos -> Severity -> Integer -> String -> ParseNote
ParseNote SourcePos
pos SourcePos
pos Severity
ErrorC Integer
1072 (String -> ParseNote) -> String -> ParseNote
forall a b. (a -> b) -> a -> b
$
        [Message] -> String
getStringFromParsec ([Message] -> String) -> [Message] -> String
forall a b. (a -> b) -> a -> b
$ ParseError -> [Message]
errorMessages ParseError
parsecError
    where
      pos :: SourcePos
pos = ParseError -> SourcePos
errorPos ParseError
parsecError

getStringFromParsec :: [Message] -> String
getStringFromParsec [Message]
errors =
        String -> [String] -> String
forall {a}. a -> [a] -> a
headOrDefault String
"" ((Message -> Maybe String) -> [Message] -> [String]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Message -> Maybe String
f ([Message] -> [String]) -> [Message] -> [String]
forall a b. (a -> b) -> a -> b
$ [Message] -> [Message]
forall a. [a] -> [a]
reverse [Message]
errors)  String -> String -> String
forall a. [a] -> [a] -> [a]
++
            String
" Fix any mentioned problems and try again."
    where
        f :: Message -> Maybe String
f Message
err =
            case Message
err of
                UnExpect String
s    ->  Maybe String
forall a. Maybe a
Nothing -- Due to not knowing Parsec, none of these
                SysUnExpect String
s ->  Maybe String
forall a. Maybe a
Nothing -- are actually helpful. <?> has been hidden
                Expect String
s      ->  Maybe String
forall a. Maybe a
Nothing -- and we only show explicit fail statements.
                Message String
s     ->  if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
s then Maybe String
forall a. Maybe a
Nothing else String -> Maybe String
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."

runParser :: Monad m =>
    Environment m ->
    SCParser m v ->
    String ->
    String ->
    m (Either ParseError v, SystemState)

runParser :: forall (m :: * -> *) v.
Monad m =>
Environment m
-> SCParser m v
-> String
-> String
-> m (Either ParseError v, SystemState)
runParser Environment m
env SCParser m v
p String
filename String
contents =
    StateT SystemState m (Either ParseError v)
-> SystemState -> m (Either ParseError v, SystemState)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
Ms.runStateT
        (ReaderT
  (Environment m) (StateT SystemState m) (Either ParseError v)
-> Environment m -> StateT SystemState m (Either ParseError v)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
Mr.runReaderT
            (SCParser m v
-> UserState
-> String
-> String
-> ReaderT
     (Environment m) (StateT SystemState m) (Either ParseError v)
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> u -> String -> s -> m (Either ParseError a)
runParserT SCParser m v
p UserState
initialUserState String
filename String
contents)
            Environment m
env)
        SystemState
initialSystemState
system :: m a -> t (t (t m)) a
system = t (t m) a -> t (t (t m)) a
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (t (t m) a -> t (t (t m)) a)
-> (m a -> t (t m) a) -> m a -> t (t (t m)) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t m a -> t (t m) a
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (t m a -> t (t m) a) -> (m a -> t m a) -> m a -> t (t m) a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> t m a
forall (m :: * -> *) a. Monad m => m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift

parseShell :: Environment m -> String -> String -> m ParseResult
parseShell Environment m
env String
name String
contents = do
    (result, state) <- Environment m
-> SCParser m (Token, UserState)
-> String
-> String
-> m (Either ParseError (Token, UserState), SystemState)
forall (m :: * -> *) v.
Monad m =>
Environment m
-> SCParser m v
-> String
-> String
-> m (Either ParseError v, SystemState)
runParser Environment m
env (ParsecT String UserState (SCBase m) Token
-> SCParser m (Token, UserState)
forall {m :: * -> *} {s} {b} {a}.
Monad m =>
ParsecT s b m a -> ParsecT s b m (a, b)
parseWithNotes ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readScript) String
name String
contents
    case result of
        Right (Token
script, UserState
userstate) ->
            ParseResult -> m ParseResult
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ParseResult
newParseResult {
                prComments = map toPositionedComment $ nub $ parseNotes userstate ++ parseProblems state,
                prTokenPositions = Map.map startEndPosToPos (positionMap userstate),
                prRoot = Just script
            }
        Left ParseError
err -> do
            let context :: [Context]
context = SystemState -> [Context]
contextStack SystemState
state
            ParseResult -> m ParseResult
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ParseResult
newParseResult {
                prComments =
                    map toPositionedComment $
                        (filter (not . isIgnored context) $
                            notesForContext context
                            ++ [makeErrorFor err])
                        ++ parseProblems state,
                prTokenPositions = Map.empty,
                prRoot = Nothing
            }
  where
    -- A final pass for ignoring parse errors after failed parsing
    isIgnored :: t Context -> ParseNote -> Bool
isIgnored t Context
stack ParseNote
note = (Context -> Bool) -> t Context -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Bool -> Integer -> Context -> Bool
contextItemDisablesCode Bool
False (ParseNote -> Integer
codeForParseNote ParseNote
note)) t Context
stack

notesForContext :: [Context] -> [ParseNote]
notesForContext [Context]
list = (((SourcePos, String) -> ParseNote)
 -> (SourcePos, String) -> ParseNote)
-> [(SourcePos, String) -> ParseNote]
-> [(SourcePos, String)]
-> [ParseNote]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith ((SourcePos, String) -> ParseNote)
-> (SourcePos, String) -> ParseNote
forall a b. (a -> b) -> a -> b
($) [(SourcePos, String) -> ParseNote
first, (SourcePos, String) -> ParseNote
second] [(SourcePos
pos, String
str) | ContextName SourcePos
pos String
str <- [Context]
list]
  where
    first :: (SourcePos, String) -> ParseNote
first (SourcePos
pos, String
str) = SourcePos
-> SourcePos -> Severity -> Integer -> String -> ParseNote
ParseNote SourcePos
pos SourcePos
pos Severity
ErrorC Integer
1073 (String -> ParseNote) -> String -> ParseNote
forall a b. (a -> b) -> a -> b
$
        String
"Couldn't parse this " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
str String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
". Fix to allow more checks."
    second :: (SourcePos, String) -> ParseNote
second (SourcePos
pos, String
str) = SourcePos
-> SourcePos -> Severity -> Integer -> String -> ParseNote
ParseNote SourcePos
pos SourcePos
pos Severity
InfoC Integer
1009 (String -> ParseNote) -> String -> ParseNote
forall a b. (a -> b) -> a -> b
$
        String
"The mentioned syntax error was in this " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
str String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."

-- Go over all T_UnparsedIndex and reparse them as either arithmetic or text
-- depending on declare -A statements.
reparseIndices :: Token -> ParsecT String UserState (SCBase m) Token
reparseIndices Token
root = Token -> ParsecT String UserState (SCBase m) Token
forall (m :: * -> *). Monad m => Token -> SCParser m Token
process Token
root
  where
    process :: Token -> ParsecT String UserState (SCBase m) Token
process = (Token -> ParsecT String UserState (SCBase m) ())
-> (Token -> ParsecT String UserState (SCBase m) ())
-> (Token -> ParsecT String UserState (SCBase m) Token)
-> Token
-> ParsecT String UserState (SCBase m) Token
forall (m :: * -> *).
Monad m =>
(Token -> m ())
-> (Token -> m ()) -> (Token -> m Token) -> Token -> m Token
analyze Token -> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *). Monad m => Token -> m ()
blank Token -> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *). Monad m => Token -> m ()
blank Token -> ParsecT String UserState (SCBase m) Token
f
    associative :: [String]
associative = Token -> [String]
getAssociativeArrays Token
root
    isAssociative :: String -> Bool
isAssociative String
s = String
s String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
associative
    f :: Token -> ParsecT String UserState (SCBase m) Token
f (T_Assignment Id
id AssignmentMode
mode String
name [Token]
indices Token
value) = do
        newIndices <- (Token -> ParsecT String UserState (SCBase m) Token)
-> [Token] -> ParsecT String UserState (SCBase m) [Token]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (String -> Token -> ParsecT String UserState (SCBase m) Token
fixAssignmentIndex String
name) [Token]
indices
        newValue <- case value of
            (T_Array Id
id2 [Token]
words) -> do
                newWords <- (Token -> ParsecT String UserState (SCBase m) Token)
-> [Token] -> ParsecT String UserState (SCBase m) [Token]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (String -> Token -> ParsecT String UserState (SCBase m) Token
fixIndexElement String
name) [Token]
words
                return $ T_Array id2 newWords
            Token
x -> Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
x
        return $ T_Assignment id mode name newIndices newValue
    f (TA_Variable Id
id String
name [Token]
indices) = do
        newIndices <- (Token -> ParsecT String UserState (SCBase m) Token)
-> [Token] -> ParsecT String UserState (SCBase m) [Token]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (String -> Token -> ParsecT String UserState (SCBase m) Token
fixAssignmentIndex String
name) [Token]
indices
        return $ TA_Variable id name newIndices
    f Token
t = Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
t

    fixIndexElement :: String -> Token -> ParsecT String UserState (SCBase m) Token
fixIndexElement String
name Token
word =
        case Token
word of
            T_IndexedElement Id
id [Token]
indices Token
value -> do
                new <- (Token -> ParsecT String UserState (SCBase m) Token)
-> [Token] -> ParsecT String UserState (SCBase m) [Token]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (String -> Token -> ParsecT String UserState (SCBase m) Token
fixAssignmentIndex String
name) [Token]
indices
                return $ T_IndexedElement id new value
            Token
_ -> Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
word

    fixAssignmentIndex :: String -> Token -> ParsecT String UserState (SCBase m) Token
fixAssignmentIndex String
name Token
word =
        case Token
word of
            T_UnparsedIndex Id
id SourcePos
pos String
src -> do
                idx <- String
-> SourcePos -> String -> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
String
-> SourcePos -> String -> ParsecT String UserState (SCBase m) Token
parsed String
name SourcePos
pos String
src
                process idx -- Recursively parse for cases like x[y[z=1]]=1
            Token
_ -> Token -> ParsecT String UserState (SCBase m) Token
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return Token
word

    parsed :: String
-> SourcePos -> String -> ParsecT String UserState (SCBase m) Token
parsed String
name SourcePos
pos String
src =
        if String -> Bool
isAssociative String
name
        then SourcePos
-> ParsecT String UserState (SCBase m) Token
-> String
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {u} {b}.
Monad m =>
SourcePos -> ParsecT s u m b -> s -> ParsecT s u m b
subParse SourcePos
pos (String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"associative array index" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readIndexSpan) String
src
        else SourcePos
-> ParsecT String UserState (SCBase m) Token
-> String
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {u} {b}.
Monad m =>
SourcePos -> ParsecT s u m b -> s -> ParsecT s u m b
subParse SourcePos
pos (String
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *} {s} {t} {u} {b}.
(Stream s m t, MonadState SystemState m) =>
String -> ParsecT s u m b -> ParsecT s u m b
called String
"arithmetic array index expression" (ParsecT String UserState (SCBase m) Token
 -> ParsecT String UserState (SCBase m) Token)
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b. (a -> b) -> a -> b
$ ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
space ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) Token
-> ParsecT String UserState (SCBase m) Token
forall a b.
ParsecT String UserState (SCBase m) a
-> ParsecT String UserState (SCBase m) b
-> ParsecT String UserState (SCBase m) b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT String UserState (SCBase m) Token
forall {m :: * -> *}.
Monad m =>
ParsecT String UserState (SCBase m) Token
readArithmeticContents) String
src

reattachHereDocs :: Token -> Map Id [Token] -> Token
reattachHereDocs Token
root Map Id [Token]
map =
    (Token -> Token) -> Token -> Token
doTransform Token -> Token
f Token
root
  where
    f :: Token -> Token
f t :: Token
t@(T_HereDoc Id
id Dashed
dash Quoted
quote String
string []) = Token -> Maybe Token -> Token
forall a. a -> Maybe a -> a
fromMaybe Token
t (Maybe Token -> Token) -> Maybe Token -> Token
forall a b. (a -> b) -> a -> b
$ do
        list <- Id -> Map Id [Token] -> Maybe [Token]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Id
id Map Id [Token]
map
        return $ T_HereDoc id dash quote string list
    f Token
t = Token
t

toPositionedComment :: ParseNote -> PositionedComment
toPositionedComment :: ParseNote -> PositionedComment
toPositionedComment (ParseNote SourcePos
start SourcePos
end Severity
severity Integer
code String
message) =
    PositionedComment
newPositionedComment {
        pcStartPos = (posToPos start)
      , pcEndPos = (posToPos end)
      , pcComment = newComment {
          cSeverity = severity
        , cCode = code
        , cMessage = message
      }
    }

posToPos :: SourcePos -> Position
posToPos :: SourcePos -> Position
posToPos SourcePos
sp = Position
newPosition {
    posFile = sourceName sp,
    posLine = fromIntegral $ sourceLine sp,
    posColumn = fromIntegral $ sourceColumn sp
}

startEndPosToPos :: (SourcePos, SourcePos) -> (Position, Position)
startEndPosToPos :: (SourcePos, SourcePos) -> (Position, Position)
startEndPosToPos (SourcePos
s, SourcePos
e) = (SourcePos -> Position
posToPos SourcePos
s, SourcePos -> Position
posToPos SourcePos
e)

-- TODO: Clean up crusty old code that this is layered on top of
parseScript :: Monad m =>
        SystemInterface m -> ParseSpec -> m ParseResult
parseScript :: forall (m :: * -> *).
Monad m =>
SystemInterface m -> ParseSpec -> m ParseResult
parseScript SystemInterface m
sys ParseSpec
spec =
    Environment m -> String -> String -> m ParseResult
forall {m :: * -> *}.
Monad m =>
Environment m -> String -> String -> m ParseResult
parseShell Environment m
env (ParseSpec -> String
psFilename ParseSpec
spec) (ParseSpec -> String
psScript ParseSpec
spec)
  where
    env :: Environment m
env = Environment {
        systemInterface :: SystemInterface m
systemInterface = SystemInterface m
sys,
        checkSourced :: Bool
checkSourced = ParseSpec -> Bool
psCheckSourced ParseSpec
spec,
        currentFilename :: String
currentFilename = ParseSpec -> String
psFilename ParseSpec
spec,
        ignoreRC :: Bool
ignoreRC = ParseSpec -> Bool
psIgnoreRC ParseSpec
spec,
        shellTypeOverride :: Maybe Shell
shellTypeOverride = ParseSpec -> Maybe Shell
psShellTypeOverride ParseSpec
spec
    }

-- Same as 'try' but emit syntax errors if the parse fails.
tryWithErrors :: Monad m => SCParser m v -> SCParser m v
tryWithErrors :: forall (m :: * -> *) v. Monad m => SCParser m v -> SCParser m v
tryWithErrors SCParser m v
parser = do
    userstate <- ParsecT String UserState (SCBase m) UserState
forall (m :: * -> *) s u. Monad m => ParsecT s u m u
getState
    oldContext <- getCurrentContexts
    input <- getInput
    pos <- getPosition
    result <- lift $ runParserT (setPosition pos >> getResult parser) userstate (sourceName pos) input
    case result of
        Right (v
result, SourcePos
endPos, String
endInput, UserState
endState) -> do
            -- 'many' objects if we don't consume anything at all, so read a dummy value
            ParsecT String UserState (SCBase m) Char
-> ParsecT String UserState (SCBase m) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ParsecT String UserState (SCBase m) Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
anyChar ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
-> ParsecT String UserState (SCBase m) ()
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT String UserState (SCBase m) ()
forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof
            UserState -> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *) u s. Monad m => u -> ParsecT s u m ()
putState UserState
endState
            SourcePos -> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *) s u. Monad m => SourcePos -> ParsecT s u m ()
setPosition SourcePos
endPos
            String -> ParsecT String UserState (SCBase m) ()
forall (m :: * -> *) s u. Monad m => s -> ParsecT s u m ()
setInput String
endInput
            v -> SCParser m v
forall a. a -> ParsecT String UserState (SCBase m) a
forall (m :: * -> *) a. Monad m => a -> m a
return v
result

        Left ParseError
err -> do
            newContext <- ParsecT String UserState (SCBase m) [Context]
forall {m :: * -> *}. MonadState SystemState m => m [Context]
getCurrentContexts
            addParseProblem $ makeErrorFor err
            mapM_ addParseProblem $ notesForContext newContext
            setCurrentContexts oldContext
            fail ""
  where
    getResult :: ParsecT c d m a -> ParsecT c d m (a, SourcePos, c, d)
getResult ParsecT c d m a
p = do
        result <- ParsecT c d m a
p
        endPos <- getPosition
        endInput <- getInput
        endState <- getState
        return (result, endPos, endInput, endState)

return []
runTests :: IO Bool
runTests = $Bool
String
[(String, Property)]
Bool -> Property
[(String, Property)] -> (Property -> IO Result) -> IO Bool
Property -> IO Result
forall prop. Testable prop => prop -> IO Result
forall prop. Testable prop => prop -> Property
prop_spacing1 :: Bool
prop_spacing2 :: Bool
prop_spacing3 :: Bool
prop_allspacing :: Bool
prop_allspacing2 :: Bool
prop_allspacing3 :: Bool
prop_a1 :: Bool
prop_a2 :: Bool
prop_a3 :: Bool
prop_a4 :: Bool
prop_a5 :: Bool
prop_a6 :: Bool
prop_a7 :: Bool
prop_a8 :: Bool
prop_a9 :: Bool
prop_a10 :: Bool
prop_a11 :: Bool
prop_a12 :: Bool
prop_a13 :: Bool
prop_a14 :: Bool
prop_a15 :: Bool
prop_a16 :: Bool
prop_a17 :: Bool
prop_a18 :: Bool
prop_a19 :: Bool
prop_a20 :: Bool
prop_a21 :: Bool
prop_a22 :: Bool
prop_a23 :: Bool
prop_readCondition :: Bool
prop_readCondition2 :: Bool
prop_readCondition3 :: Bool
prop_readCondition4 :: Bool
prop_readCondition5 :: Bool
prop_readCondition5a :: Bool
prop_readCondition5b :: Bool
prop_readCondition6 :: Bool
prop_readCondition7 :: Bool
prop_readCondition8 :: Bool
prop_readCondition9 :: Bool
prop_readCondition10 :: Bool
prop_readCondition10a :: Bool
prop_readCondition10b :: Bool
prop_readCondition11 :: Bool
prop_readCondition12 :: Bool
prop_readCondition13 :: Bool
prop_readCondition14 :: Bool
prop_readCondition15 :: Bool
prop_readCondition16 :: Bool
prop_readCondition17 :: Bool
prop_readCondition18 :: Bool
prop_readCondition19 :: Bool
prop_readCondition20 :: Bool
prop_readCondition21 :: Bool
prop_readCondition22 :: Bool
prop_readCondition23 :: Bool
prop_readCondition25 :: Bool
prop_readCondition26 :: Bool
prop_readCondition27 :: Bool
prop_readCondition28 :: Bool
prop_readCondition29 :: Bool
prop_readAnnotation1 :: Bool
prop_readAnnotation2 :: Bool
prop_readAnnotation3 :: Bool
prop_readAnnotation4 :: Bool
prop_readAnnotation5 :: Bool
prop_readAnnotation6 :: Bool
prop_readAnnotation7 :: Bool
prop_readAnnotation8 :: Bool
prop_readAnnotation9 :: Bool
prop_readAnnotation10 :: Bool
prop_readAnnotation11 :: Bool
prop_readAnyComment :: Bool
prop_readNormalWord :: Bool
prop_readNormalWord2 :: Bool
prop_readNormalWord3 :: Bool
prop_readNormalWord4 :: Bool
prop_readNormalWord5 :: Bool
prop_readNormalWord6 :: Bool
prop_readNormalWord7 :: Bool
prop_readNormalWord8 :: Bool
prop_readNormalWord9 :: Bool
prop_readNormalWord10 :: Bool
prop_readNormalWord11 :: Bool
prop_readNormalWord12 :: Bool
prop_readProcSub1 :: Bool
prop_readProcSub2 :: Bool
prop_readProcSub3 :: Bool
prop_readSingleQuoted :: Bool
prop_readSingleQuoted2 :: Bool
prop_readSingleQuoted4 :: Bool
prop_readSingleQuoted5 :: Bool
prop_readSingleQuoted6 :: Bool
prop_readSingleQuoted7 :: Bool
prop_readSingleQuoted8 :: Bool
prop_readBackTicked :: Bool
prop_readBackTicked2 :: Bool
prop_readBackTicked3 :: Bool
prop_readBackTicked4 :: Bool
prop_readBackTicked5 :: Bool
prop_readBackTicked6 :: Bool
prop_readBackTicked7 :: Bool
prop_readBackTicked8 :: Bool
prop_readDoubleQuoted :: Bool
prop_readDoubleQuoted2 :: Bool
prop_readDoubleQuoted3 :: Bool
prop_readDoubleQuoted4 :: Bool
prop_readDoubleQuoted5 :: Bool
prop_readDoubleQuoted6 :: Bool
prop_readDoubleQuoted7 :: Bool
prop_readDoubleQuoted8 :: Bool
prop_readDoubleQuoted10 :: Bool
prop_readGlob1 :: Bool
prop_readGlob2 :: Bool
prop_readGlob3 :: Bool
prop_readGlob4 :: Bool
prop_readGlob5 :: Bool
prop_readGlob6 :: Bool
prop_readGlob7 :: Bool
prop_readGlob8 :: Bool
prop_readGlob9 :: Bool
prop_readGlob10 :: Bool
prop_readExtglob1 :: Bool
prop_readExtglob2 :: Bool
prop_readExtglob4 :: Bool
prop_readExtglob5 :: Bool
prop_readExtglob6 :: Bool
prop_readExtglob7 :: Bool
prop_readExtglob8 :: Bool
prop_readBraced :: Bool
prop_readBraced2 :: Bool
prop_readBraced3 :: Bool
prop_readBraced4 :: Bool
prop_readBraced5 :: Bool
prop_readBraced6 :: Bool
prop_readBraced7 :: Bool
prop_readBraced8 :: Bool
prop_readDollarExpression1 :: Bool
prop_readDollarExpression2 :: Bool
prop_readDollarExpression3 :: Bool
prop_readDollarSingleQuote :: Bool
prop_readDollarDoubleQuote :: Bool
prop_readDollarArithmetic :: Bool
prop_readDollarArithmetic2 :: Bool
prop_readArithmeticExpression :: Bool
prop_readDollarBraceCommandExpansion1 :: Bool
prop_readDollarBraceCommandExpansion2 :: Bool
prop_readDollarBraced1 :: Bool
prop_readDollarBraced2 :: Bool
prop_readDollarBraced3 :: Bool
prop_readDollarBraced4 :: Bool
prop_readDollarExpansion1 :: Bool
prop_readDollarExpansion2 :: Bool
prop_readDollarExpansion3 :: Bool
prop_readDollarVariable :: Bool
prop_readDollarVariable2 :: Bool
prop_readDollarVariable3 :: Bool
prop_readDollarVariable4 :: Bool
prop_readDollarVariable5 :: Bool
prop_readDollarLonely1 :: Bool
prop_readDollarLonely2 :: Bool
prop_readDollarLonely3 :: Bool
prop_readDollarLonely4 :: Bool
prop_readDollarLonely5 :: Bool
prop_readHereDoc :: Bool
prop_readHereDoc2 :: Bool
prop_readHereDoc3 :: Bool
prop_readHereDoc4 :: Bool
prop_readHereDoc5 :: Bool
prop_readHereDoc6 :: Bool
prop_readHereDoc7 :: Bool
prop_readHereDoc8 :: Bool
prop_readHereDoc9 :: Bool
prop_readHereDoc10 :: Bool
prop_readHereDoc11 :: Bool
prop_readHereDoc12 :: Bool
prop_readHereDoc13 :: Bool
prop_readHereDoc14 :: Bool
prop_readHereDoc15 :: Bool
prop_readHereDoc16 :: Bool
prop_readHereDoc17 :: Bool
prop_readHereDoc18 :: Bool
prop_readHereDoc20 :: Bool
prop_readHereDoc21 :: Bool
prop_readHereDoc22 :: Bool
prop_readHereDoc23 :: Bool
prop_readIoFile :: Bool
prop_readIoRedirect :: Bool
prop_readIoRedirect2 :: Bool
prop_readIoRedirect3 :: Bool
prop_readIoRedirect4 :: Bool
prop_readIoRedirect5 :: Bool
prop_readIoRedirect6 :: Bool
prop_readIoRedirect7 :: Bool
prop_readHereString :: Bool
prop_readNewlineList1 :: Bool
prop_readSeparator1 :: Bool
prop_readSeparator2 :: Bool
prop_readSeparator3 :: Bool
prop_readSeparator4 :: Bool
prop_readSeparator5 :: Bool
prop_readSimpleCommand :: Bool
prop_readSimpleCommand2 :: Bool
prop_readSimpleCommand3 :: Bool
prop_readSimpleCommand4 :: Bool
prop_readSimpleCommand5 :: Bool
prop_readSimpleCommand6 :: Bool
prop_readSimpleCommand7 :: Bool
prop_readSimpleCommand7b :: Bool
prop_readSimpleCommand8 :: Bool
prop_readSimpleCommand9 :: Bool
prop_readSimpleCommand10 :: Bool
prop_readSimpleCommand11 :: Bool
prop_readSimpleCommand12 :: Bool
prop_readSimpleCommand13 :: Bool
prop_readSimpleCommand14 :: Bool
prop_readSimpleCommand15 :: Bool
prop_readPipeline :: Bool
prop_readPipeline2 :: Bool
prop_readPipeline3 :: Bool
prop_readPipeline4 :: Bool
prop_readPipeline5 :: Bool
prop_readAndOr :: Bool
prop_readAndOr1 :: Bool
prop_readAndOr2 :: Bool
prop_readTerm :: Bool
prop_readIfClause :: Bool
prop_readIfClause2 :: Bool
prop_readIfClause3 :: Bool
prop_readIfClause4 :: Bool
prop_readIfClause5 :: Bool
prop_readIfClause6 :: Bool
prop_readSubshell :: Bool
prop_readBraceGroup :: Bool
prop_readBraceGroup2 :: Bool
prop_readBraceGroup3 :: Bool
prop_readBatsTest1 :: Bool
prop_readBatsTest2 :: Bool
prop_readBatsTest3 :: Bool
prop_readBatsTest4 :: Bool
prop_readWhileClause :: Bool
prop_readUntilClause :: Bool
prop_readForClause :: Bool
prop_readForClause1 :: Bool
prop_readForClause3 :: Bool
prop_readForClause4 :: Bool
prop_readForClause5 :: Bool
prop_readForClause6 :: Bool
prop_readForClause7 :: Bool
prop_readForClause8 :: Bool
prop_readForClause9 :: Bool
prop_readForClause10 :: Bool
prop_readForClause12 :: Bool
prop_readForClause13 :: Bool
prop_readSelectClause1 :: Bool
prop_readSelectClause2 :: Bool
prop_readCaseClause :: Bool
prop_readCaseClause2 :: Bool
prop_readCaseClause3 :: Bool
prop_readCaseClause4 :: Bool
prop_readCaseClause5 :: Bool
prop_readCaseClause6 :: Bool
prop_readFunctionDefinition :: Bool
prop_readFunctionDefinition1 :: Bool
prop_readFunctionDefinition4 :: Bool
prop_readFunctionDefinition5 :: Bool
prop_readFunctionDefinition6 :: Bool
prop_readFunctionDefinition7 :: Bool
prop_readFunctionDefinition8 :: Bool
prop_readFunctionDefinition9 :: Bool
prop_readFunctionDefinition10 :: Bool
prop_readFunctionDefinition11 :: Bool
prop_readFunctionDefinition12 :: Bool
prop_readFunctionDefinition13 :: Bool
prop_readCoProc1 :: Bool
prop_readCoProc2 :: Bool
prop_readCoProc3 :: Bool
prop_readConditionCommand :: Bool
prop_readCompoundCommand :: Bool
prop_readAssignmentWord :: Bool
prop_readAssignmentWord2 :: Bool
prop_readAssignmentWord5 :: Bool
prop_readAssignmentWord7 :: Bool
prop_readAssignmentWord8 :: Bool
prop_readAssignmentWord9 :: Bool
prop_readAssignmentWord9a :: Bool
prop_readAssignmentWord9b :: Bool
prop_readAssignmentWord9c :: Bool
prop_readAssignmentWord11 :: Bool
prop_readAssignmentWord12 :: Bool
prop_readAssignmentWord13 :: Bool
prop_readAssignmentWord14 :: Bool
prop_readAssignmentWord15 :: Bool
prop_readShebang1 :: Bool
prop_readShebang2 :: Bool
prop_readShebang3 :: Bool
prop_readShebang4 :: Bool
prop_readShebang5 :: Bool
prop_readShebang6 :: Bool
prop_readShebang7 :: Bool
prop_readConfigKVs1 :: Bool
prop_readConfigKVs2 :: Bool
prop_readConfigKVs3 :: Bool
prop_readConfigKVs4 :: Bool
prop_readConfigKVs5 :: Bool
prop_readScript1 :: Bool
prop_readScript2 :: Bool
prop_readScript3 :: Bool
prop_readScript4 :: Bool
prop_readScript5 :: Bool
prop_readScript6 :: Bool
prop_readScript7 :: Bool
quickCheckResult :: forall prop. Testable prop => prop -> IO Result
property :: forall prop. Testable prop => prop -> Property
runQuickCheckAll :: [(String, Property)] -> (Property -> IO Result) -> IO Bool
quickCheckAll