{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TemplateHaskell #-}
module ShellCheck.AnalyzerLib where
import ShellCheck.AST
import ShellCheck.ASTLib
import ShellCheck.Data
import ShellCheck.Interface
import ShellCheck.Parser
import ShellCheck.Regex
import Control.Arrow (first)
import Control.DeepSeq
import Control.Monad.Identity
import Control.Monad.RWS
import Control.Monad.State
import Control.Monad.Writer
import Data.Char
import Data.List
import Data.Maybe
import Data.Semigroup
import qualified Data.Map as Map
import Test.QuickCheck.All (forAllProperties)
import Test.QuickCheck.Test (maxSuccess, quickCheckWithResult, stdArgs)
type Analysis = AnalyzerM ()
type AnalyzerM a = RWS Parameters [TokenComment] Cache a
nullCheck :: b -> RWST Parameters [TokenComment] Cache Identity ()
nullCheck = RWST Parameters [TokenComment] Cache Identity ()
-> b -> RWST Parameters [TokenComment] Cache Identity ()
forall a b. a -> b -> a
const (RWST Parameters [TokenComment] Cache Identity ()
-> b -> RWST Parameters [TokenComment] Cache Identity ())
-> RWST Parameters [TokenComment] Cache Identity ()
-> b
-> RWST Parameters [TokenComment] Cache Identity ()
forall a b. (a -> b) -> a -> b
$ () -> RWST Parameters [TokenComment] Cache Identity ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
data Checker = Checker {
Checker -> Root -> RWST Parameters [TokenComment] Cache Identity ()
perScript :: Root -> Analysis,
Checker
-> Token -> RWST Parameters [TokenComment] Cache Identity ()
perToken :: Token -> Analysis
}
runChecker :: Parameters -> Checker -> [TokenComment]
runChecker :: Parameters -> Checker -> [TokenComment]
runChecker params :: Parameters
params checker :: Checker
checker = [TokenComment]
notes
where
root :: Token
root = Parameters -> Token
rootNode Parameters
params
check :: Root -> RWST Parameters [TokenComment] Cache Identity ()
check = Checker -> Root -> RWST Parameters [TokenComment] Cache Identity ()
perScript Checker
checker (Root -> RWST Parameters [TokenComment] Cache Identity ())
-> (Root -> RWST Parameters [TokenComment] Cache Identity ())
-> Root
-> RWST Parameters [TokenComment] Cache Identity ()
forall a.
(a -> RWST Parameters [TokenComment] Cache Identity ())
-> (a -> RWST Parameters [TokenComment] Cache Identity ())
-> a
-> RWST Parameters [TokenComment] Cache Identity ()
`composeAnalyzers` (\(Root x :: Token
x) -> RWST Parameters [TokenComment] Cache Identity Token
-> RWST Parameters [TokenComment] Cache Identity ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (RWST Parameters [TokenComment] Cache Identity Token
-> RWST Parameters [TokenComment] Cache Identity ())
-> RWST Parameters [TokenComment] Cache Identity Token
-> RWST Parameters [TokenComment] Cache Identity ()
forall a b. (a -> b) -> a -> b
$ (Token -> RWST Parameters [TokenComment] Cache Identity ())
-> Token -> RWST Parameters [TokenComment] Cache Identity Token
forall (m :: * -> *).
Monad m =>
(Token -> m ()) -> Token -> m Token
doAnalysis (Checker
-> Token -> RWST Parameters [TokenComment] Cache Identity ()
perToken Checker
checker) Token
x)
notes :: [TokenComment]
notes = ((), [TokenComment]) -> [TokenComment]
forall a b. (a, b) -> b
snd (((), [TokenComment]) -> [TokenComment])
-> ((), [TokenComment]) -> [TokenComment]
forall a b. (a -> b) -> a -> b
$ RWST Parameters [TokenComment] Cache Identity ()
-> Parameters -> Cache -> ((), [TokenComment])
forall r w s a. RWS r w s a -> r -> s -> (a, w)
evalRWS (Root -> RWST Parameters [TokenComment] Cache Identity ()
check (Root -> RWST Parameters [TokenComment] Cache Identity ())
-> Root -> RWST Parameters [TokenComment] Cache Identity ()
forall a b. (a -> b) -> a -> b
$ Token -> Root
Root Token
root) Parameters
params Cache
Cache
instance Semigroup Checker where
<> :: Checker -> Checker -> Checker
(<>) x :: Checker
x y :: Checker
y = Checker :: (Root -> RWST Parameters [TokenComment] Cache Identity ())
-> (Token -> RWST Parameters [TokenComment] Cache Identity ())
-> Checker
Checker {
perScript :: Root -> RWST Parameters [TokenComment] Cache Identity ()
perScript = Checker -> Root -> RWST Parameters [TokenComment] Cache Identity ()
perScript Checker
x (Root -> RWST Parameters [TokenComment] Cache Identity ())
-> (Root -> RWST Parameters [TokenComment] Cache Identity ())
-> Root
-> RWST Parameters [TokenComment] Cache Identity ()
forall a.
(a -> RWST Parameters [TokenComment] Cache Identity ())
-> (a -> RWST Parameters [TokenComment] Cache Identity ())
-> a
-> RWST Parameters [TokenComment] Cache Identity ()
`composeAnalyzers` Checker -> Root -> RWST Parameters [TokenComment] Cache Identity ()
perScript Checker
y,
perToken :: Token -> RWST Parameters [TokenComment] Cache Identity ()
perToken = Checker
-> Token -> RWST Parameters [TokenComment] Cache Identity ()
perToken Checker
x (Token -> RWST Parameters [TokenComment] Cache Identity ())
-> (Token -> RWST Parameters [TokenComment] Cache Identity ())
-> Token
-> RWST Parameters [TokenComment] Cache Identity ()
forall a.
(a -> RWST Parameters [TokenComment] Cache Identity ())
-> (a -> RWST Parameters [TokenComment] Cache Identity ())
-> a
-> RWST Parameters [TokenComment] Cache Identity ()
`composeAnalyzers` Checker
-> Token -> RWST Parameters [TokenComment] Cache Identity ()
perToken Checker
y
}
instance Monoid Checker where
mempty :: Checker
mempty = Checker :: (Root -> RWST Parameters [TokenComment] Cache Identity ())
-> (Token -> RWST Parameters [TokenComment] Cache Identity ())
-> Checker
Checker {
perScript :: Root -> RWST Parameters [TokenComment] Cache Identity ()
perScript = Root -> RWST Parameters [TokenComment] Cache Identity ()
forall b. b -> RWST Parameters [TokenComment] Cache Identity ()
nullCheck,
perToken :: Token -> RWST Parameters [TokenComment] Cache Identity ()
perToken = Token -> RWST Parameters [TokenComment] Cache Identity ()
forall b. b -> RWST Parameters [TokenComment] Cache Identity ()
nullCheck
}
mappend :: Checker -> Checker -> Checker
mappend = Checker -> Checker -> Checker
forall a. Semigroup a => a -> a -> a
(Data.Semigroup.<>)
composeAnalyzers :: (a -> Analysis) -> (a -> Analysis) -> a -> Analysis
composeAnalyzers :: (a -> RWST Parameters [TokenComment] Cache Identity ())
-> (a -> RWST Parameters [TokenComment] Cache Identity ())
-> a
-> RWST Parameters [TokenComment] Cache Identity ()
composeAnalyzers f :: a -> RWST Parameters [TokenComment] Cache Identity ()
f g :: a -> RWST Parameters [TokenComment] Cache Identity ()
g x :: a
x = a -> RWST Parameters [TokenComment] Cache Identity ()
f a
x RWST Parameters [TokenComment] Cache Identity ()
-> RWST Parameters [TokenComment] Cache Identity ()
-> RWST Parameters [TokenComment] Cache Identity ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> a -> RWST Parameters [TokenComment] Cache Identity ()
g a
x
data Parameters = Parameters {
Parameters -> Bool
hasLastpipe :: Bool,
Parameters -> Bool
hasSetE :: Bool,
Parameters -> [StackData]
variableFlow :: [StackData],
Parameters -> Map Id Token
parentMap :: Map.Map Id Token,
Parameters -> Shell
shellType :: Shell,
Parameters -> Bool
shellTypeSpecified :: Bool,
Parameters -> Token
rootNode :: Token,
Parameters -> Map Id (Position, Position)
tokenPositions :: Map.Map Id (Position, Position)
} deriving (Int -> Parameters -> ShowS
[Parameters] -> ShowS
Parameters -> String
(Int -> Parameters -> ShowS)
-> (Parameters -> String)
-> ([Parameters] -> ShowS)
-> Show Parameters
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Parameters] -> ShowS
$cshowList :: [Parameters] -> ShowS
show :: Parameters -> String
$cshow :: Parameters -> String
showsPrec :: Int -> Parameters -> ShowS
$cshowsPrec :: Int -> Parameters -> ShowS
Show)
data Cache = Cache {}
data Scope = SubshellScope String | NoneScope deriving (Int -> Scope -> ShowS
[Scope] -> ShowS
Scope -> String
(Int -> Scope -> ShowS)
-> (Scope -> String) -> ([Scope] -> ShowS) -> Show Scope
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Scope] -> ShowS
$cshowList :: [Scope] -> ShowS
show :: Scope -> String
$cshow :: Scope -> String
showsPrec :: Int -> Scope -> ShowS
$cshowsPrec :: Int -> Scope -> ShowS
Show, Scope -> Scope -> Bool
(Scope -> Scope -> Bool) -> (Scope -> Scope -> Bool) -> Eq Scope
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Scope -> Scope -> Bool
$c/= :: Scope -> Scope -> Bool
== :: Scope -> Scope -> Bool
$c== :: Scope -> Scope -> Bool
Eq)
data StackData =
StackScope Scope
| StackScopeEnd
| Assignment (Token, Token, String, DataType)
| Reference (Token, Token, String)
deriving (Int -> StackData -> ShowS
[StackData] -> ShowS
StackData -> String
(Int -> StackData -> ShowS)
-> (StackData -> String)
-> ([StackData] -> ShowS)
-> Show StackData
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [StackData] -> ShowS
$cshowList :: [StackData] -> ShowS
show :: StackData -> String
$cshow :: StackData -> String
showsPrec :: Int -> StackData -> ShowS
$cshowsPrec :: Int -> StackData -> ShowS
Show)
data DataType = DataString DataSource | DataArray DataSource
deriving (Int -> DataType -> ShowS
[DataType] -> ShowS
DataType -> String
(Int -> DataType -> ShowS)
-> (DataType -> String) -> ([DataType] -> ShowS) -> Show DataType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DataType] -> ShowS
$cshowList :: [DataType] -> ShowS
show :: DataType -> String
$cshow :: DataType -> String
showsPrec :: Int -> DataType -> ShowS
$cshowsPrec :: Int -> DataType -> ShowS
Show)
data DataSource =
SourceFrom [Token]
| SourceExternal
| SourceDeclaration
| SourceInteger
| SourceChecked
deriving (Int -> DataSource -> ShowS
[DataSource] -> ShowS
DataSource -> String
(Int -> DataSource -> ShowS)
-> (DataSource -> String)
-> ([DataSource] -> ShowS)
-> Show DataSource
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DataSource] -> ShowS
$cshowList :: [DataSource] -> ShowS
show :: DataSource -> String
$cshow :: DataSource -> String
showsPrec :: Int -> DataSource -> ShowS
$cshowsPrec :: Int -> DataSource -> ShowS
Show)
data VariableState = Dead Token String | Alive deriving (Int -> VariableState -> ShowS
[VariableState] -> ShowS
VariableState -> String
(Int -> VariableState -> ShowS)
-> (VariableState -> String)
-> ([VariableState] -> ShowS)
-> Show VariableState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [VariableState] -> ShowS
$cshowList :: [VariableState] -> ShowS
show :: VariableState -> String
$cshow :: VariableState -> String
showsPrec :: Int -> VariableState -> ShowS
$cshowsPrec :: Int -> VariableState -> ShowS
Show)
defaultSpec :: ParseResult -> AnalysisSpec
defaultSpec pr :: ParseResult
pr = AnalysisSpec
spec {
asShellType :: Maybe Shell
asShellType = Maybe Shell
forall a. Maybe a
Nothing,
asCheckSourced :: Bool
asCheckSourced = Bool
False,
asExecutionMode :: ExecutionMode
asExecutionMode = ExecutionMode
Executed,
asTokenPositions :: Map Id (Position, Position)
asTokenPositions = ParseResult -> Map Id (Position, Position)
prTokenPositions ParseResult
pr
} where spec :: AnalysisSpec
spec = Token -> AnalysisSpec
newAnalysisSpec (Maybe Token -> Token
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Token -> Token) -> Maybe Token -> Token
forall a b. (a -> b) -> a -> b
$ ParseResult -> Maybe Token
prRoot ParseResult
pr)
pScript :: String -> ParseResult
pScript s :: String
s =
let
pSpec :: ParseSpec
pSpec = ParseSpec
newParseSpec {
psFilename :: String
psFilename = "script",
psScript :: String
psScript = String
s
}
in 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
pSpec
producesComments :: Checker -> String -> Maybe Bool
c :: Checker
c s :: String
s = do
let pr :: ParseResult
pr = String -> ParseResult
pScript String
s
ParseResult -> Maybe Token
prRoot ParseResult
pr
let spec :: AnalysisSpec
spec = ParseResult -> AnalysisSpec
defaultSpec ParseResult
pr
let params :: Parameters
params = AnalysisSpec -> Parameters
makeParameters AnalysisSpec
spec
Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Maybe Bool)
-> ([TokenComment] -> Bool) -> [TokenComment] -> Maybe Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> Bool)
-> ([TokenComment] -> Bool) -> [TokenComment] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [TokenComment] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([TokenComment] -> Maybe Bool) -> [TokenComment] -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ Parameters -> Checker -> [TokenComment]
runChecker Parameters
params Checker
c
makeComment :: Severity -> Id -> Code -> String -> TokenComment
severity :: Severity
severity id :: Id
id code :: Code
code note :: String
note =
TokenComment
newTokenComment {
tcId :: Id
tcId = Id
id,
tcComment :: Comment
tcComment = Comment
newComment {
cSeverity :: Severity
cSeverity = Severity
severity,
cCode :: Code
cCode = Code
code,
cMessage :: String
cMessage = String
note
}
}
note :: a
note = a
note a -> m () -> m ()
forall a b. NFData a => a -> b -> b
`deepseq` [a] -> m ()
forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [a
note]
warn :: MonadWriter [TokenComment] m => Id -> Code -> String -> m ()
warn :: Id -> Code -> String -> m ()
warn id :: Id
id code :: Code
code str :: String
str = TokenComment -> m ()
forall a (m :: * -> *). (NFData a, MonadWriter [a] m) => a -> m ()
addComment (TokenComment -> m ()) -> TokenComment -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> Id -> Code -> String -> TokenComment
makeComment Severity
WarningC Id
id Code
code String
str
err :: Id -> Code -> String -> m ()
err id :: Id
id code :: Code
code str :: String
str = TokenComment -> m ()
forall a (m :: * -> *). (NFData a, MonadWriter [a] m) => a -> m ()
addComment (TokenComment -> m ()) -> TokenComment -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> Id -> Code -> String -> TokenComment
makeComment Severity
ErrorC Id
id Code
code String
str
info :: Id -> Code -> String -> m ()
info id :: Id
id code :: Code
code str :: String
str = TokenComment -> m ()
forall a (m :: * -> *). (NFData a, MonadWriter [a] m) => a -> m ()
addComment (TokenComment -> m ()) -> TokenComment -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> Id -> Code -> String -> TokenComment
makeComment Severity
InfoC Id
id Code
code String
str
style :: Id -> Code -> String -> m ()
style id :: Id
id code :: Code
code str :: String
str = TokenComment -> m ()
forall a (m :: * -> *). (NFData a, MonadWriter [a] m) => a -> m ()
addComment (TokenComment -> m ()) -> TokenComment -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> Id -> Code -> String -> TokenComment
makeComment Severity
StyleC Id
id Code
code String
str
warnWithFix :: MonadWriter [TokenComment] m => Id -> Code -> String -> Fix -> m ()
warnWithFix :: Id -> Code -> String -> Fix -> m ()
warnWithFix = Severity -> Id -> Code -> String -> Fix -> m ()
forall (m :: * -> *).
MonadWriter [TokenComment] m =>
Severity -> Id -> Code -> String -> Fix -> m ()
addCommentWithFix Severity
WarningC
styleWithFix :: MonadWriter [TokenComment] m => Id -> Code -> String -> Fix -> m ()
styleWithFix :: Id -> Code -> String -> Fix -> m ()
styleWithFix = Severity -> Id -> Code -> String -> Fix -> m ()
forall (m :: * -> *).
MonadWriter [TokenComment] m =>
Severity -> Id -> Code -> String -> Fix -> m ()
addCommentWithFix Severity
StyleC
addCommentWithFix :: MonadWriter [TokenComment] m => Severity -> Id -> Code -> String -> Fix -> m ()
severity :: Severity
severity id :: Id
id code :: Code
code str :: String
str fix :: Fix
fix =
TokenComment -> m ()
forall a (m :: * -> *). (NFData a, MonadWriter [a] m) => a -> m ()
addComment (TokenComment -> m ()) -> TokenComment -> m ()
forall a b. (a -> b) -> a -> b
$ Severity -> Id -> Code -> String -> Fix -> TokenComment
makeCommentWithFix Severity
severity Id
id Code
code String
str Fix
fix
makeCommentWithFix :: Severity -> Id -> Code -> String -> Fix -> TokenComment
severity :: Severity
severity id :: Id
id code :: Code
code str :: String
str fix :: Fix
fix =
let comment :: TokenComment
comment = Severity -> Id -> Code -> String -> TokenComment
makeComment Severity
severity Id
id Code
code String
str
withFix :: TokenComment
withFix = TokenComment
comment {
tcFix :: Maybe Fix
tcFix = Fix -> Maybe Fix
forall a. a -> Maybe a
Just Fix
fix
}
in TokenComment
withFix TokenComment -> TokenComment -> TokenComment
forall a b. NFData a => a -> b -> b
`deepseq` TokenComment
withFix
makeParameters :: AnalysisSpec -> Parameters
makeParameters spec :: AnalysisSpec
spec =
let params :: Parameters
params = Parameters :: Bool
-> Bool
-> [StackData]
-> Map Id Token
-> Shell
-> Bool
-> Token
-> Map Id (Position, Position)
-> Parameters
Parameters {
rootNode :: Token
rootNode = Token
root,
shellType :: Shell
shellType = Shell -> Maybe Shell -> Shell
forall a. a -> Maybe a -> a
fromMaybe (Maybe Shell -> Token -> Shell
determineShell (AnalysisSpec -> Maybe Shell
asFallbackShell AnalysisSpec
spec) Token
root) (Maybe Shell -> Shell) -> Maybe Shell -> Shell
forall a b. (a -> b) -> a -> b
$ AnalysisSpec -> Maybe Shell
asShellType AnalysisSpec
spec,
hasSetE :: Bool
hasSetE = Token -> Bool
containsSetE Token
root,
hasLastpipe :: Bool
hasLastpipe =
case Parameters -> Shell
shellType Parameters
params of
Bash -> Token -> Bool
containsLastpipe Token
root
Dash -> Bool
False
Sh -> Bool
False
Ksh -> Bool
True,
shellTypeSpecified :: Bool
shellTypeSpecified = Maybe Shell -> Bool
forall a. Maybe a -> Bool
isJust (AnalysisSpec -> Maybe Shell
asShellType AnalysisSpec
spec) Bool -> Bool -> Bool
|| Maybe Shell -> Bool
forall a. Maybe a -> Bool
isJust (AnalysisSpec -> Maybe Shell
asFallbackShell AnalysisSpec
spec),
parentMap :: Map Id Token
parentMap = Token -> Map Id Token
getParentTree Token
root,
variableFlow :: [StackData]
variableFlow = Parameters -> Token -> [StackData]
getVariableFlow Parameters
params Token
root,
tokenPositions :: Map Id (Position, Position)
tokenPositions = AnalysisSpec -> Map Id (Position, Position)
asTokenPositions AnalysisSpec
spec
} in Parameters
params
where root :: Token
root = AnalysisSpec -> Token
asScript AnalysisSpec
spec
containsSetE :: Token -> Bool
containsSetE root :: Token
root = Maybe Token -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe Token -> Bool) -> Maybe Token -> Bool
forall a b. (a -> b) -> a -> b
$ (Token -> Maybe ()) -> Token -> Maybe Token
forall (m :: * -> *).
Monad m =>
(Token -> m ()) -> Token -> m Token
doAnalysis (Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> (Token -> Bool) -> Token -> Maybe ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> Bool) -> (Token -> Bool) -> Token -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Token -> Bool
isSetE) Token
root
where
isSetE :: Token -> Bool
isSetE t :: Token
t =
case Token
t of
T_Script _ (T_Literal _ str :: String
str) _ -> String
str String -> Regex -> Bool
`matches` Regex
re
T_SimpleCommand {} ->
Token
t Token -> String -> Bool
`isUnqualifiedCommand` "set" Bool -> Bool -> Bool
&&
("errexit" String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Token -> [String]
oversimplify Token
t Bool -> Bool -> Bool
||
"e" String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ((Token, String) -> String) -> [(Token, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Token, String) -> String
forall a b. (a, b) -> b
snd (Token -> [(Token, String)]
getAllFlags Token
t))
_ -> Bool
False
re :: Regex
re = String -> Regex
mkRegex "[[:space:]]-[^-]*e"
containsLastpipe :: Token -> Bool
containsLastpipe root :: Token
root =
Maybe Token -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe Token -> Bool) -> Maybe Token -> Bool
forall a b. (a -> b) -> a -> b
$ (Token -> Maybe ()) -> Token -> Maybe Token
forall (m :: * -> *).
Monad m =>
(Token -> m ()) -> Token -> m Token
doAnalysis (Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> (Token -> Bool) -> Token -> Maybe ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> Bool) -> (Token -> Bool) -> Token -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Token -> Bool
isShoptLastPipe) Token
root
where
isShoptLastPipe :: Token -> Bool
isShoptLastPipe t :: Token
t =
case Token
t of
T_SimpleCommand {} ->
Token
t Token -> String -> Bool
`isUnqualifiedCommand` "shopt" Bool -> Bool -> Bool
&&
("lastpipe" String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` Token -> [String]
oversimplify Token
t)
_ -> Bool
False
prop_determineShell0 :: Bool
prop_determineShell0 = String -> Shell
determineShellTest "#!/bin/sh" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Sh
prop_determineShell1 :: Bool
prop_determineShell1 = String -> Shell
determineShellTest "#!/usr/bin/env ksh" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Ksh
prop_determineShell2 :: Bool
prop_determineShell2 = String -> Shell
determineShellTest "" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Bash
prop_determineShell3 :: Bool
prop_determineShell3 = String -> Shell
determineShellTest "#!/bin/sh -e" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Sh
prop_determineShell4 :: Bool
prop_determineShell4 = String -> Shell
determineShellTest "#!/bin/ksh\n#shellcheck shell=sh\nfoo" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Sh
prop_determineShell5 :: Bool
prop_determineShell5 = String -> Shell
determineShellTest "#shellcheck shell=sh\nfoo" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Sh
prop_determineShell6 :: Bool
prop_determineShell6 = String -> Shell
determineShellTest "#! /bin/sh" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Sh
prop_determineShell7 :: Bool
prop_determineShell7 = String -> Shell
determineShellTest "#! /bin/ash" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Dash
prop_determineShell8 :: Bool
prop_determineShell8 = Maybe Shell -> String -> Shell
determineShellTest' (Shell -> Maybe Shell
forall a. a -> Maybe a
Just Shell
Ksh) "#!/bin/sh" Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Sh
determineShellTest :: String -> Shell
determineShellTest = Maybe Shell -> String -> Shell
determineShellTest' Maybe Shell
forall a. Maybe a
Nothing
determineShellTest' :: Maybe Shell -> String -> Shell
determineShellTest' fallbackShell :: Maybe Shell
fallbackShell = Maybe Shell -> Token -> Shell
determineShell Maybe Shell
fallbackShell (Token -> Shell) -> (String -> Token) -> String -> Shell
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe Token -> Token
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Token -> Token)
-> (String -> Maybe Token) -> String -> Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseResult -> Maybe Token
prRoot (ParseResult -> Maybe Token)
-> (String -> ParseResult) -> String -> Maybe Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ParseResult
pScript
determineShell :: Maybe Shell -> Token -> Shell
determineShell fallbackShell :: Maybe Shell
fallbackShell t :: Token
t = Shell -> Maybe Shell -> Shell
forall a. a -> Maybe a -> a
fromMaybe Shell
Bash (Maybe Shell -> Shell) -> Maybe Shell -> Shell
forall a b. (a -> b) -> a -> b
$ do
String
shellString <- (Maybe String -> Maybe String -> Maybe String)
-> Maybe String -> [Maybe String] -> Maybe String
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Maybe String -> Maybe String -> Maybe String
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
mplus Maybe String
forall a. Maybe a
Nothing ([Maybe String] -> Maybe String) -> [Maybe String] -> Maybe String
forall a b. (a -> b) -> a -> b
$ Token -> [Maybe String]
getCandidates Token
t
String -> Maybe Shell
shellForExecutable String
shellString Maybe Shell -> Maybe Shell -> Maybe Shell
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` Maybe Shell
fallbackShell
where
forAnnotation :: Annotation -> m String
forAnnotation t :: Annotation
t =
case Annotation
t of
(ShellOverride s :: String
s) -> String -> m String
forall (m :: * -> *) a. Monad m => a -> m a
return String
s
_ -> String -> m String
forall (m :: * -> *) a. MonadFail m => String -> m a
fail ""
getCandidates :: Token -> [Maybe String]
getCandidates :: Token -> [Maybe String]
getCandidates t :: Token
t@T_Script {} = [String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ Token -> String
fromShebang Token
t]
getCandidates (T_Annotation _ annotations :: [Annotation]
annotations s :: Token
s) =
(Annotation -> Maybe String) -> [Annotation] -> [Maybe String]
forall a b. (a -> b) -> [a] -> [b]
map Annotation -> Maybe String
forall (m :: * -> *). MonadFail m => Annotation -> m String
forAnnotation [Annotation]
annotations [Maybe String] -> [Maybe String] -> [Maybe String]
forall a. [a] -> [a] -> [a]
++
[String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ Token -> String
fromShebang Token
s]
fromShebang :: Token -> String
fromShebang (T_Script _ (T_Literal _ s :: String
s) _) = ShowS
executableFromShebang String
s
executableFromShebang :: String -> String
executableFromShebang :: ShowS
executableFromShebang = ShowS
shellFor
where
shellFor :: ShowS
shellFor s :: String
s | "/env " String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf` String
s = [String] -> String
forall a. [a] -> a
head (Int -> [String] -> [String]
forall a. Int -> [a] -> [a]
drop 1 (String -> [String]
words String
s)[String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++[""])
shellFor s :: String
s | ' ' Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s = ShowS
shellFor ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= ' ') String
s
shellFor s :: String
s = ShowS
forall a. [a] -> [a]
reverse ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '/') ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
forall a. [a] -> [a]
reverse ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ String
s
getParentTree :: Token -> Map.Map Id Token
getParentTree :: Token -> Map Id Token
getParentTree t :: Token
t =
([Token], Map Id Token) -> Map Id Token
forall a b. (a, b) -> b
snd (([Token], Map Id Token) -> Map Id Token)
-> ((Token, ([Token], Map Id Token)) -> ([Token], Map Id Token))
-> (Token, ([Token], Map Id Token))
-> Map Id Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Token, ([Token], Map Id Token)) -> ([Token], Map Id Token)
forall a b. (a, b) -> b
snd ((Token, ([Token], Map Id Token)) -> Map Id Token)
-> (Token, ([Token], Map Id Token)) -> Map Id Token
forall a b. (a -> b) -> a -> b
$ State ([Token], Map Id Token) Token
-> ([Token], Map Id Token) -> (Token, ([Token], Map Id Token))
forall s a. State s a -> s -> (a, s)
runState ((Token -> StateT ([Token], Map Id Token) Identity ())
-> (Token -> StateT ([Token], Map Id Token) Identity ())
-> Token
-> State ([Token], Map Id Token) Token
forall (m :: * -> *).
Monad m =>
(Token -> m ()) -> (Token -> m ()) -> Token -> m Token
doStackAnalysis Token -> StateT ([Token], Map Id Token) Identity ()
forall a d (m :: * -> *). MonadState ([a], d) m => a -> m ()
pre Token -> StateT ([Token], Map Id Token) Identity ()
forall (m :: * -> *) a.
MonadState ([a], Map Id a) m =>
Token -> m ()
post Token
t) ([], Map Id Token
forall k a. Map k a
Map.empty)
where
pre :: a -> m ()
pre t :: a
t = (([a], d) -> ([a], d)) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (([a] -> [a]) -> ([a], d) -> ([a], d)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first ((:) a
t))
post :: Token -> m ()
post t :: Token
t = do
(x :: [a]
x, map :: Map Id a
map) <- m ([a], Map Id a)
forall s (m :: * -> *). MonadState s m => m s
get
case [a]
x of
_:rest :: [a]
rest -> case [a]
rest of [] -> ([a], Map Id a) -> m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put ([a]
rest, Map Id a
map)
(x :: a
x:_) -> ([a], Map Id a) -> m ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put ([a]
rest, Id -> a -> Map Id a -> Map Id a
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert (Token -> Id
getId Token
t) a
x Map Id a
map)
getTokenMap :: Token -> Map.Map Id Token
getTokenMap :: Token -> Map Id Token
getTokenMap t :: Token
t =
State (Map Id Token) Token -> Map Id Token -> Map Id Token
forall s a. State s a -> s -> s
execState ((Token -> StateT (Map Id Token) Identity ())
-> Token -> State (Map Id Token) Token
forall (m :: * -> *).
Monad m =>
(Token -> m ()) -> Token -> m Token
doAnalysis Token -> StateT (Map Id Token) Identity ()
forall (m :: * -> *). MonadState (Map Id Token) m => Token -> m ()
f Token
t) Map Id Token
forall k a. Map k a
Map.empty
where
f :: Token -> m ()
f t :: Token
t = (Map Id Token -> Map Id Token) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (Id -> Token -> Map Id Token -> Map Id Token
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert (Token -> Id
getId Token
t) Token
t)
isStrictlyQuoteFree :: Map Id Token -> Token -> Bool
isStrictlyQuoteFree = Bool -> Map Id Token -> Token -> Bool
isQuoteFreeNode Bool
True
isQuoteFree :: Map Id Token -> Token -> Bool
isQuoteFree = Bool -> Map Id Token -> Token -> Bool
isQuoteFreeNode Bool
False
isQuoteFreeNode :: Bool -> Map Id Token -> Token -> Bool
isQuoteFreeNode strict :: Bool
strict tree :: Map Id Token
tree t :: Token
t =
(Token -> Maybe Bool
isQuoteFreeElement Token
t Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True) Bool -> Bool -> Bool
||
[Bool] -> Bool
forall a. [a] -> a
head ((Token -> Maybe Bool) -> [Token] -> [Bool]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Token -> Maybe Bool
isQuoteFreeContext (Int -> [Token] -> [Token]
forall a. Int -> [a] -> [a]
drop 1 ([Token] -> [Token]) -> [Token] -> [Token]
forall a b. (a -> b) -> a -> b
$ Map Id Token -> Token -> [Token]
getPath Map Id Token
tree Token
t) [Bool] -> [Bool] -> [Bool]
forall a. [a] -> [a] -> [a]
++ [Bool
False])
where
isQuoteFreeElement :: Token -> Maybe Bool
isQuoteFreeElement t :: Token
t =
case Token
t of
T_Assignment {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_FdRedirect {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
_ -> Maybe Bool
forall a. Maybe a
Nothing
isQuoteFreeContext :: Token -> Maybe Bool
isQuoteFreeContext t :: Token
t =
case Token
t of
TC_Nullary _ DoubleBracket _ -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
TC_Unary _ DoubleBracket _ _ -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
TC_Binary _ DoubleBracket _ _ _ -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
TA_Sequence {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_Arithmetic {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_Assignment {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_Redirecting {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
T_DoubleQuoted _ _ -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_DollarDoubleQuoted _ _ -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_CaseExpression {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_HereDoc {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_DollarBraced {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_ForIn {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Bool
not Bool
strict)
T_SelectIn {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Bool
not Bool
strict)
_ -> Maybe Bool
forall a. Maybe a
Nothing
isParamTo :: Map.Map Id Token -> String -> Token -> Bool
isParamTo :: Map Id Token -> String -> Token -> Bool
isParamTo tree :: Map Id Token
tree cmd :: String
cmd =
Token -> Bool
go
where
go :: Token -> Bool
go x :: Token
x = case Id -> Map Id Token -> Maybe Token
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (Token -> Id
getId Token
x) Map Id Token
tree of
Nothing -> Bool
False
Just parent :: Token
parent -> Token -> Bool
check Token
parent
check :: Token -> Bool
check t :: Token
t =
case Token
t of
T_SingleQuoted _ _ -> Token -> Bool
go Token
t
T_DoubleQuoted _ _ -> Token -> Bool
go Token
t
T_NormalWord _ _ -> Token -> Bool
go Token
t
T_SimpleCommand {} -> Token -> String -> Bool
isCommand Token
t String
cmd
T_Redirecting {} -> Token -> String -> Bool
isCommand Token
t String
cmd
_ -> Bool
False
getClosestCommand :: Map.Map Id Token -> Token -> Maybe Token
getClosestCommand :: Map Id Token -> Token -> Maybe Token
getClosestCommand tree :: Map Id Token
tree t :: Token
t =
(Token -> Maybe Bool) -> [Token] -> Maybe Token
forall a. (a -> Maybe Bool) -> [a] -> Maybe a
findFirst Token -> Maybe Bool
findCommand ([Token] -> Maybe Token) -> [Token] -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Map Id Token -> Token -> [Token]
getPath Map Id Token
tree Token
t
where
findCommand :: Token -> Maybe Bool
findCommand t :: Token
t =
case Token
t of
T_Redirecting {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
T_Script {} -> Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
_ -> Maybe Bool
forall a. Maybe a
Nothing
getClosestCommandM :: Token -> m (Maybe Token)
getClosestCommandM t :: Token
t = do
Map Id Token
tree <- (Parameters -> Map Id Token) -> m (Map Id Token)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Parameters -> Map Id Token
parentMap
Maybe Token -> m (Maybe Token)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Token -> m (Maybe Token)) -> Maybe Token -> m (Maybe Token)
forall a b. (a -> b) -> a -> b
$ Map Id Token -> Token -> Maybe Token
getClosestCommand Map Id Token
tree Token
t
usedAsCommandName :: Map Id Token -> Token -> Bool
usedAsCommandName tree :: Map Id Token
tree token :: Token
token = Id -> [Token] -> Bool
go (Token -> Id
getId Token
token) ([Token] -> [Token]
forall a. [a] -> [a]
tail ([Token] -> [Token]) -> [Token] -> [Token]
forall a b. (a -> b) -> a -> b
$ Map Id Token -> Token -> [Token]
getPath Map Id Token
tree Token
token)
where
go :: Id -> [Token] -> Bool
go currentId :: Id
currentId (T_NormalWord id :: Id
id [word :: Token
word]:rest :: [Token]
rest)
| Id
currentId Id -> Id -> Bool
forall a. Eq a => a -> a -> Bool
== Token -> Id
getId Token
word = Id -> [Token] -> Bool
go Id
id [Token]
rest
go currentId :: Id
currentId (T_DoubleQuoted id :: Id
id [word :: Token
word]:rest :: [Token]
rest)
| Id
currentId Id -> Id -> Bool
forall a. Eq a => a -> a -> Bool
== Token -> Id
getId Token
word = Id -> [Token] -> Bool
go Id
id [Token]
rest
go currentId :: Id
currentId (T_SimpleCommand _ _ (word :: Token
word:_):_)
| Id
currentId Id -> Id -> Bool
forall a. Eq a => a -> a -> Bool
== Token -> Id
getId Token
word = Bool
True
go _ _ = Bool
False
getPath :: Map Id Token -> Token -> [Token]
getPath tree :: Map Id Token
tree t :: Token
t = Token
t Token -> [Token] -> [Token]
forall a. a -> [a] -> [a]
:
case Id -> Map Id Token -> Maybe Token
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (Token -> Id
getId Token
t) Map Id Token
tree of
Nothing -> []
Just parent :: Token
parent -> Map Id Token -> Token -> [Token]
getPath Map Id Token
tree Token
parent
getPathM :: Token -> m [Token]
getPathM t :: Token
t = do
Map Id Token
map <- (Parameters -> Map Id Token) -> m (Map Id Token)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Parameters -> Map Id Token
parentMap
[Token] -> m [Token]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Token] -> m [Token]) -> [Token] -> m [Token]
forall a b. (a -> b) -> a -> b
$ Map Id Token -> Token -> [Token]
getPath Map Id Token
map Token
t
isParentOf :: Map Id Token -> Token -> Token -> Bool
isParentOf tree :: Map Id Token
tree parent :: Token
parent child :: Token
child =
Id -> [Id] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem (Token -> Id
getId Token
parent) ([Id] -> Bool) -> ([Token] -> [Id]) -> [Token] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Token -> Id) -> [Token] -> [Id]
forall a b. (a -> b) -> [a] -> [b]
map Token -> Id
getId ([Token] -> Bool) -> [Token] -> Bool
forall a b. (a -> b) -> a -> b
$ Map Id Token -> Token -> [Token]
getPath Map Id Token
tree Token
child
parents :: Parameters -> Token -> [Token]
parents params :: Parameters
params = Map Id Token -> Token -> [Token]
getPath (Parameters -> Map Id Token
parentMap Parameters
params)
findFirst :: (a -> Maybe Bool) -> [a] -> Maybe a
findFirst :: (a -> Maybe Bool) -> [a] -> Maybe a
findFirst p :: a -> Maybe Bool
p l :: [a]
l =
case [a]
l of
[] -> Maybe a
forall a. Maybe a
Nothing
(x :: a
x:xs :: [a]
xs) ->
case a -> Maybe Bool
p a
x of
Just True -> a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x
Just False -> Maybe a
forall a. Maybe a
Nothing
Nothing -> (a -> Maybe Bool) -> [a] -> Maybe a
forall a. (a -> Maybe Bool) -> [a] -> Maybe a
findFirst a -> Maybe Bool
p [a]
xs
tokenIsJustCommandOutput :: Token -> Bool
tokenIsJustCommandOutput t :: Token
t = case Token
t of
T_NormalWord id :: Id
id [T_DollarExpansion _ cmds :: [Token]
cmds] -> [Token] -> Bool
check [Token]
cmds
T_NormalWord id :: Id
id [T_DoubleQuoted _ [T_DollarExpansion _ cmds :: [Token]
cmds]] -> [Token] -> Bool
check [Token]
cmds
T_NormalWord id :: Id
id [T_Backticked _ cmds :: [Token]
cmds] -> [Token] -> Bool
check [Token]
cmds
T_NormalWord id :: Id
id [T_DoubleQuoted _ [T_Backticked _ cmds :: [Token]
cmds]] -> [Token] -> Bool
check [Token]
cmds
_ -> Bool
False
where
check :: [Token] -> Bool
check [x :: Token
x] = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Token -> Bool
isOnlyRedirection Token
x
check _ = Bool
False
getVariableFlow :: Parameters -> Token -> [StackData]
getVariableFlow params :: Parameters
params t :: Token
t =
let (_, stack :: [StackData]
stack) = State [StackData] Token -> [StackData] -> (Token, [StackData])
forall s a. State s a -> s -> (a, s)
runState ((Token -> StateT [StackData] Identity ())
-> (Token -> StateT [StackData] Identity ())
-> Token
-> State [StackData] Token
forall (m :: * -> *).
Monad m =>
(Token -> m ()) -> (Token -> m ()) -> Token -> m Token
doStackAnalysis Token -> StateT [StackData] Identity ()
forall (m :: * -> *). MonadState [StackData] m => Token -> m ()
startScope Token -> StateT [StackData] Identity ()
forall (m :: * -> *). MonadState [StackData] m => Token -> m ()
endScope Token
t) []
in [StackData] -> [StackData]
forall a. [a] -> [a]
reverse [StackData]
stack
where
startScope :: Token -> m ()
startScope t :: Token
t =
let scopeType :: Scope
scopeType = Parameters -> Token -> Scope
leadType Parameters
params Token
t
in do
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Scope
scopeType Scope -> Scope -> Bool
forall a. Eq a => a -> a -> Bool
/= Scope
NoneScope) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ ([StackData] -> [StackData]) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (Scope -> StackData
StackScope Scope
scopeTypeStackData -> [StackData] -> [StackData]
forall a. a -> [a] -> [a]
:)
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Token -> Bool
assignFirst Token
t) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Token -> m ()
forall (m :: * -> *). MonadState [StackData] m => Token -> m ()
setWritten Token
t
endScope :: Token -> m ()
endScope t :: Token
t =
let scopeType :: Scope
scopeType = Parameters -> Token -> Scope
leadType Parameters
params Token
t
in do
Token -> m ()
forall (m :: * -> *). MonadState [StackData] m => Token -> m ()
setRead Token
t
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Token -> Bool
assignFirst Token
t) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Token -> m ()
forall (m :: * -> *). MonadState [StackData] m => Token -> m ()
setWritten Token
t
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Scope
scopeType Scope -> Scope -> Bool
forall a. Eq a => a -> a -> Bool
/= Scope
NoneScope) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ ([StackData] -> [StackData]) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (StackData
StackScopeEndStackData -> [StackData] -> [StackData]
forall a. a -> [a] -> [a]
:)
assignFirst :: Token -> Bool
assignFirst T_ForIn {} = Bool
True
assignFirst T_SelectIn {} = Bool
True
assignFirst (T_BatsTest {}) = Bool
True
assignFirst _ = Bool
False
setRead :: Token -> m ()
setRead t :: Token
t =
let read :: [(Token, Token, String)]
read = Map Id Token -> Token -> [(Token, Token, String)]
getReferencedVariables (Parameters -> Map Id Token
parentMap Parameters
params) Token
t
in ((Token, Token, String) -> m ())
-> [(Token, Token, String)] -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\v :: (Token, Token, String)
v -> ([StackData] -> [StackData]) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((Token, Token, String) -> StackData
Reference (Token, Token, String)
vStackData -> [StackData] -> [StackData]
forall a. a -> [a] -> [a]
:)) [(Token, Token, String)]
read
setWritten :: Token -> m ()
setWritten t :: Token
t =
let written :: [(Token, Token, String, DataType)]
written = Token -> [(Token, Token, String, DataType)]
getModifiedVariables Token
t
in ((Token, Token, String, DataType) -> m ())
-> [(Token, Token, String, DataType)] -> m ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\v :: (Token, Token, String, DataType)
v -> ([StackData] -> [StackData]) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((Token, Token, String, DataType) -> StackData
Assignment (Token, Token, String, DataType)
vStackData -> [StackData] -> [StackData]
forall a. a -> [a] -> [a]
:)) [(Token, Token, String, DataType)]
written
leadType :: Parameters -> Token -> Scope
leadType params :: Parameters
params t :: Token
t =
case Token
t of
T_DollarExpansion _ _ -> String -> Scope
SubshellScope "$(..) expansion"
T_Backticked _ _ -> String -> Scope
SubshellScope "`..` expansion"
T_Backgrounded _ _ -> String -> Scope
SubshellScope "backgrounding &"
T_Subshell _ _ -> String -> Scope
SubshellScope "(..) group"
T_BatsTest {} -> String -> Scope
SubshellScope "@bats test"
T_CoProcBody _ _ -> String -> Scope
SubshellScope "coproc"
T_Redirecting {} ->
if Bool -> Maybe Bool -> Bool
forall a. a -> Maybe a -> a
fromMaybe Bool
False Maybe Bool
causesSubshell
then String -> Scope
SubshellScope "pipeline"
else Scope
NoneScope
_ -> Scope
NoneScope
where
parentPipeline :: Maybe Token
parentPipeline = do
Token
parent <- Id -> Map Id Token -> Maybe Token
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (Token -> Id
getId Token
t) (Parameters -> Map Id Token
parentMap Parameters
params)
case Token
parent of
T_Pipeline {} -> Token -> Maybe Token
forall (m :: * -> *) a. Monad m => a -> m a
return Token
parent
_ -> Maybe Token
forall a. Maybe a
Nothing
causesSubshell :: Maybe Bool
causesSubshell = do
(T_Pipeline _ _ list :: [Token]
list) <- Maybe Token
parentPipeline
if [Token] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Token]
list Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 1
then Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
else if Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Parameters -> Bool
hasLastpipe Parameters
params
then Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
else Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Maybe Bool) -> (Bool -> Bool) -> Bool -> Maybe Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> Maybe Bool) -> Bool -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ (Token -> Id
getId (Token -> Id) -> ([Token] -> Token) -> [Token] -> Id
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Token] -> Token
forall a. [a] -> a
head ([Token] -> Id) -> [Token] -> Id
forall a b. (a -> b) -> a -> b
$ [Token] -> [Token]
forall a. [a] -> [a]
reverse [Token]
list) Id -> Id -> Bool
forall a. Eq a => a -> a -> Bool
== Token -> Id
getId Token
t
getModifiedVariables :: Token -> [(Token, Token, String, DataType)]
getModifiedVariables t :: Token
t =
case Token
t of
T_SimpleCommand _ vars :: [Token]
vars [] ->
(Token -> [(Token, Token, String, DataType)])
-> [Token] -> [(Token, Token, String, DataType)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\x :: Token
x -> case Token
x of
T_Assignment id :: Id
id _ name :: String
name _ w :: Token
w ->
[(Token
x, Token
x, String
name, (DataSource -> DataType) -> Token -> DataType
dataTypeFrom DataSource -> DataType
DataString Token
w)]
_ -> []
) [Token]
vars
c :: Token
c@T_SimpleCommand {} ->
Token -> [(Token, Token, String, DataType)]
getModifiedVariableCommand Token
c
TA_Unary _ "++|" v :: Token
v@(TA_Variable _ name :: String
name _) ->
[(Token
t, Token
v, String
name, DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token
v])]
TA_Unary _ "|++" v :: Token
v@(TA_Variable _ name :: String
name _) ->
[(Token
t, Token
v, String
name, DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token
v])]
TA_Assignment _ op :: String
op (TA_Variable _ name :: String
name _) rhs :: Token
rhs -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ do
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String
op String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ["=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="]
(Token, Token, String, DataType)
-> Maybe (Token, Token, String, DataType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
t, Token
t, String
name, DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token
rhs])
T_BatsTest {} -> [
(Token
t, Token
t, "lines", DataSource -> DataType
DataArray DataSource
SourceExternal),
(Token
t, Token
t, "status", DataSource -> DataType
DataString DataSource
SourceInteger),
(Token
t, Token
t, "output", DataSource -> DataType
DataString DataSource
SourceExternal)
]
TC_Unary id :: Id
id _ "-v" token :: Token
token -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ do
String
str <- ShowS -> Maybe String -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '[')) (Maybe String -> Maybe String) -> Maybe String -> Maybe String
forall a b. (a -> b) -> a -> b
$
((Token -> Maybe String) -> Token -> Maybe String)
-> Token -> (Token -> Maybe String) -> Maybe String
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Token -> Maybe String) -> Token -> Maybe String
getLiteralStringExt Token
token ((Token -> Maybe String) -> Maybe String)
-> (Token -> Maybe String) -> Maybe String
forall a b. (a -> b) -> a -> b
$ \x :: Token
x ->
case Token
x of
T_Glob _ s :: String
s -> String -> Maybe String
forall (m :: * -> *) a. Monad m => a -> m a
return String
s
_ -> Maybe String
forall a. Maybe a
Nothing
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> (String -> Bool) -> String -> Maybe ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (String -> Maybe ()) -> String -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String
str
(Token, Token, String, DataType)
-> Maybe (Token, Token, String, DataType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
t, Token
token, String
str, DataSource -> DataType
DataString DataSource
SourceChecked)
T_DollarBraced _ _ l :: Token
l -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ do
let string :: String
string = Token -> String
bracedString Token
t
let modifier :: String
modifier = ShowS
getBracedModifier String
string
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ ":=" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
modifier
(Token, Token, String, DataType)
-> Maybe (Token, Token, String, DataType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
t, Token
t, ShowS
getBracedReference String
string, DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token
l])
t :: Token
t@(T_FdRedirect _ ('{':var :: String
var) op :: Token
op) ->
[(Token
t, Token
t, (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '}') String
var, DataSource -> DataType
DataString DataSource
SourceInteger) | Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Token -> Bool
isClosingFileOp Token
op]
t :: Token
t@(T_CoProc _ name :: Maybe String
name _) ->
[(Token
t, Token
t, String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe "COPROC" Maybe String
name, DataSource -> DataType
DataArray DataSource
SourceInteger)]
T_ForIn id :: Id
id str :: String
str [] _ -> [(Token
t, Token
t, String
str, DataSource -> DataType
DataString DataSource
SourceExternal)]
T_ForIn id :: Id
id str :: String
str words :: [Token]
words _ -> [(Token
t, Token
t, String
str, DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token]
words)]
T_SelectIn id :: Id
id str :: String
str words :: [Token]
words _ -> [(Token
t, Token
t, String
str, DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token]
words)]
_ -> []
isClosingFileOp :: Token -> Bool
isClosingFileOp op :: Token
op =
case Token
op of
T_IoDuplicate _ (T_GREATAND _) "-" -> Bool
True
T_IoDuplicate _ (T_LESSAND _) "-" -> Bool
True
_ -> Bool
False
getReferencedVariableCommand :: Token -> [(Token, Token, String)]
getReferencedVariableCommand base :: Token
base@(T_SimpleCommand _ _ (T_NormalWord _ (T_Literal _ x :: String
x:_):rest :: [Token]
rest)) =
case String
x of
"export" -> if "f" String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
flags
then []
else (Token -> [(Token, Token, String)])
-> [Token] -> [(Token, Token, String)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Token -> [(Token, Token, String)]
getReference [Token]
rest
"declare" -> if
(String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
flags) ["x", "p"] Bool -> Bool -> Bool
&&
(Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
flags) ["f", "F"])
then (Token -> [(Token, Token, String)])
-> [Token] -> [(Token, Token, String)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Token -> [(Token, Token, String)]
getReference [Token]
rest
else []
"trap" ->
case [Token]
rest of
head :: Token
head:_ -> (String -> (Token, Token, String))
-> [String] -> [(Token, Token, String)]
forall a b. (a -> b) -> [a] -> [b]
map (\x :: String
x -> (Token
head, Token
head, String
x)) ([String] -> [(Token, Token, String)])
-> [String] -> [(Token, Token, String)]
forall a b. (a -> b) -> a -> b
$ Token -> [String]
getVariablesFromLiteralToken Token
head
_ -> []
_ -> []
where
getReference :: Token -> [(Token, Token, String)]
getReference t :: Token
t@(T_Assignment _ _ name :: String
name _ value :: Token
value) = [(Token
t, Token
t, String
name)]
getReference t :: Token
t@(T_NormalWord _ [T_Literal _ name :: String
name]) | Bool -> Bool
not ("-" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
name) = [(Token
t, Token
t, String
name)]
getReference _ = []
flags :: [String]
flags = ((Token, String) -> String) -> [(Token, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Token, String) -> String
forall a b. (a, b) -> b
snd ([(Token, String)] -> [String]) -> [(Token, String)] -> [String]
forall a b. (a -> b) -> a -> b
$ Token -> [(Token, String)]
getAllFlags Token
base
getReferencedVariableCommand _ = []
getModifiedVariableCommand :: Token -> [(Token, Token, String, DataType)]
getModifiedVariableCommand base :: Token
base@(T_SimpleCommand _ _ (T_NormalWord _ (T_Literal _ x :: String
x:_):rest :: [Token]
rest)) =
((Token, Token, String, DataType) -> Bool)
-> [(Token, Token, String, DataType)]
-> [(Token, Token, String, DataType)]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(_,_,s :: String
s,_) -> Bool -> Bool
not ("-" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
s)) ([(Token, Token, String, DataType)]
-> [(Token, Token, String, DataType)])
-> [(Token, Token, String, DataType)]
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$
case String
x of
"read" ->
let params :: [Maybe (Token, Token, String, DataType)]
params = (Token -> Maybe (Token, Token, String, DataType))
-> [Token] -> [Maybe (Token, Token, String, DataType)]
forall a b. (a -> b) -> [a] -> [b]
map Token -> Maybe (Token, Token, String, DataType)
getLiteral [Token]
rest
readArrayVars :: [Maybe (Token, Token, String, DataType)]
readArrayVars = [Token] -> [Maybe (Token, Token, String, DataType)]
getReadArrayVariables [Token]
rest
in
[Maybe (Token, Token, String, DataType)]
-> [(Token, Token, String, DataType)]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe (Token, Token, String, DataType)]
-> [(Token, Token, String, DataType)])
-> ([Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)])
-> [Maybe (Token, Token, String, DataType)]
-> [(Token, Token, String, DataType)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)]
forall a. [a] -> [a] -> [a]
++ [Maybe (Token, Token, String, DataType)]
readArrayVars) ([Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)])
-> ([Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)])
-> [Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe (Token, Token, String, DataType) -> Bool)
-> [Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile Maybe (Token, Token, String, DataType) -> Bool
forall a. Maybe a -> Bool
isJust ([Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)])
-> ([Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)])
-> [Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe (Token, Token, String, DataType)]
-> [Maybe (Token, Token, String, DataType)]
forall a. [a] -> [a]
reverse ([Maybe (Token, Token, String, DataType)]
-> [(Token, Token, String, DataType)])
-> [Maybe (Token, Token, String, DataType)]
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ [Maybe (Token, Token, String, DataType)]
params
"getopts" ->
case [Token]
rest of
opts :: Token
opts:var :: Token
var:_ -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ Token -> Maybe (Token, Token, String, DataType)
getLiteral Token
var
_ -> []
"let" -> (Token -> [(Token, Token, String, DataType)])
-> [Token] -> [(Token, Token, String, DataType)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Token -> [(Token, Token, String, DataType)]
letParamToLiteral [Token]
rest
"export" ->
if "f" String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
flags then [] else (Token -> [(Token, Token, String, DataType)])
-> [Token] -> [(Token, Token, String, DataType)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Token -> [(Token, Token, String, DataType)]
getModifierParamString [Token]
rest
"declare" -> if (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
flags) ["F", "f", "p"] then [] else [(Token, Token, String, DataType)]
declaredVars
"typeset" -> [(Token, Token, String, DataType)]
declaredVars
"local" -> (Token -> [(Token, Token, String, DataType)])
-> [Token] -> [(Token, Token, String, DataType)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Token -> [(Token, Token, String, DataType)]
getModifierParamString [Token]
rest
"readonly" ->
if (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
flags) ["f", "p"]
then []
else (Token -> [(Token, Token, String, DataType)])
-> [Token] -> [(Token, Token, String, DataType)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Token -> [(Token, Token, String, DataType)]
getModifierParamString [Token]
rest
"set" -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ do
[Token]
params <- [Token] -> Maybe [Token]
getSetParams [Token]
rest
(Token, Token, String, DataType)
-> Maybe (Token, Token, String, DataType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
base, Token
base, "@", DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token]
params)
"printf" -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ [Token] -> Maybe (Token, Token, String, DataType)
forall (m :: * -> *).
MonadFail m =>
[Token] -> m (Token, Token, String, DataType)
getPrintfVariable [Token]
rest
"mapfile" -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ Token -> [Token] -> Maybe (Token, Token, String, DataType)
forall a. a -> [Token] -> Maybe (a, Token, String, DataType)
getMapfileArray Token
base [Token]
rest
"readarray" -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ Token -> [Token] -> Maybe (Token, Token, String, DataType)
forall a. a -> [Token] -> Maybe (a, Token, String, DataType)
getMapfileArray Token
base [Token]
rest
"DEFINE_boolean" -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ [Token] -> Maybe (Token, Token, String, DataType)
getFlagVariable [Token]
rest
"DEFINE_float" -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ [Token] -> Maybe (Token, Token, String, DataType)
getFlagVariable [Token]
rest
"DEFINE_integer" -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ [Token] -> Maybe (Token, Token, String, DataType)
getFlagVariable [Token]
rest
"DEFINE_string" -> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ [Token] -> Maybe (Token, Token, String, DataType)
getFlagVariable [Token]
rest
_ -> []
where
flags :: [String]
flags = ((Token, String) -> String) -> [(Token, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Token, String) -> String
forall a b. (a, b) -> b
snd ([(Token, String)] -> [String]) -> [(Token, String)] -> [String]
forall a b. (a -> b) -> a -> b
$ Token -> [(Token, String)]
getAllFlags Token
base
stripEquals :: ShowS
stripEquals s :: String
s = let rest :: String
rest = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '=') String
s in
if String
rest String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "" then "" else ShowS
forall a. [a] -> [a]
tail String
rest
stripEqualsFrom :: Token -> Token
stripEqualsFrom (T_NormalWord id1 :: Id
id1 (T_Literal id2 :: Id
id2 s :: String
s:rs :: [Token]
rs)) =
Id -> [Token] -> Token
T_NormalWord Id
id1 (Id -> String -> Token
T_Literal Id
id2 (ShowS
stripEquals String
s)Token -> [Token] -> [Token]
forall a. a -> [a] -> [a]
:[Token]
rs)
stripEqualsFrom (T_NormalWord id1 :: Id
id1 [T_DoubleQuoted id2 :: Id
id2 [T_Literal id3 :: Id
id3 s :: String
s]]) =
Id -> [Token] -> Token
T_NormalWord Id
id1 [Id -> [Token] -> Token
T_DoubleQuoted Id
id2 [Id -> String -> Token
T_Literal Id
id3 (ShowS
stripEquals String
s)]]
stripEqualsFrom t :: Token
t = Token
t
declaredVars :: [(Token, Token, String, DataType)]
declaredVars = (Token -> [(Token, Token, String, DataType)])
-> [Token] -> [(Token, Token, String, DataType)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ((DataSource -> DataType)
-> Token -> [(Token, Token, String, DataType)]
getModifierParam DataSource -> DataType
defaultType) [Token]
rest
where
defaultType :: DataSource -> DataType
defaultType = if (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [String]
flags) ["a", "A"] then DataSource -> DataType
DataArray else DataSource -> DataType
DataString
getLiteralOfDataType :: Token -> d -> Maybe (Token, Token, String, d)
getLiteralOfDataType t :: Token
t d :: d
d = do
String
s <- Token -> Maybe String
getLiteralString Token
t
Bool -> Maybe () -> Maybe ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ("-" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
s) (Maybe () -> Maybe ()) -> Maybe () -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String -> Maybe ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "argument"
(Token, Token, String, d) -> Maybe (Token, Token, String, d)
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
base, Token
t, String
s, d
d)
getLiteral :: Token -> Maybe (Token, Token, String, DataType)
getLiteral t :: Token
t = Token -> DataType -> Maybe (Token, Token, String, DataType)
forall d. Token -> d -> Maybe (Token, Token, String, d)
getLiteralOfDataType Token
t (DataSource -> DataType
DataString DataSource
SourceExternal)
getLiteralArray :: Token -> Maybe (Token, Token, String, DataType)
getLiteralArray t :: Token
t = Token -> DataType -> Maybe (Token, Token, String, DataType)
forall d. Token -> d -> Maybe (Token, Token, String, d)
getLiteralOfDataType Token
t (DataSource -> DataType
DataArray DataSource
SourceExternal)
getModifierParamString :: Token -> [(Token, Token, String, DataType)]
getModifierParamString = (DataSource -> DataType)
-> Token -> [(Token, Token, String, DataType)]
getModifierParam DataSource -> DataType
DataString
getModifierParam :: (DataSource -> DataType)
-> Token -> [(Token, Token, String, DataType)]
getModifierParam def :: DataSource -> DataType
def t :: Token
t@(T_Assignment _ _ name :: String
name _ value :: Token
value) =
[(Token
base, Token
t, String
name, (DataSource -> DataType) -> Token -> DataType
dataTypeFrom DataSource -> DataType
def Token
value)]
getModifierParam def :: DataSource -> DataType
def t :: Token
t@T_NormalWord {} = Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a. Maybe a -> [a]
maybeToList (Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)])
-> Maybe (Token, Token, String, DataType)
-> [(Token, Token, String, DataType)]
forall a b. (a -> b) -> a -> b
$ do
String
name <- Token -> Maybe String
getLiteralString Token
t
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String -> Bool
isVariableName String
name
(Token, Token, String, DataType)
-> Maybe (Token, Token, String, DataType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
base, Token
t, String
name, DataSource -> DataType
def DataSource
SourceDeclaration)
getModifierParam _ _ = []
letParamToLiteral :: Token -> [(Token, Token, String, DataType)]
letParamToLiteral token :: Token
token =
if String
var String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ""
then []
else [(Token
base, Token
token, String
var, DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token -> Token
stripEqualsFrom Token
token])]
where var :: String
var = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile Char -> Bool
isVariableChar ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` "+-") ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ Token -> [String]
oversimplify Token
token
getSetParams :: [Token] -> Maybe [Token]
getSetParams (t :: Token
t:_:rest :: [Token]
rest) | Token -> Maybe String
getLiteralString Token
t Maybe String -> Maybe String -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Maybe String
forall a. a -> Maybe a
Just "-o" = [Token] -> Maybe [Token]
getSetParams [Token]
rest
getSetParams (t :: Token
t:rest :: [Token]
rest) =
let s :: Maybe String
s = Token -> Maybe String
getLiteralString Token
t in
case Maybe String
s of
Just "--" -> [Token] -> Maybe [Token]
forall (m :: * -> *) a. Monad m => a -> m a
return [Token]
rest
Just ('-':_) -> [Token] -> Maybe [Token]
getSetParams [Token]
rest
_ -> [Token] -> Maybe [Token]
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
tToken -> [Token] -> [Token]
forall a. a -> [a] -> [a]
:[Token] -> Maybe [Token] -> [Token]
forall a. a -> Maybe a -> a
fromMaybe [] ([Token] -> Maybe [Token]
getSetParams [Token]
rest))
getSetParams [] = Maybe [Token]
forall a. Maybe a
Nothing
getPrintfVariable :: [Token] -> m (Token, Token, String, DataType)
getPrintfVariable list :: [Token]
list = [(Token, Maybe String)] -> m (Token, Token, String, DataType)
forall (m :: * -> *) b.
MonadFail m =>
[(b, Maybe String)] -> m (Token, b, String, DataType)
f ([(Token, Maybe String)] -> m (Token, Token, String, DataType))
-> [(Token, Maybe String)] -> m (Token, Token, String, DataType)
forall a b. (a -> b) -> a -> b
$ (Token -> (Token, Maybe String))
-> [Token] -> [(Token, Maybe String)]
forall a b. (a -> b) -> [a] -> [b]
map (\x :: Token
x -> (Token
x, Token -> Maybe String
getLiteralString Token
x)) [Token]
list
where
f :: [(b, Maybe String)] -> m (Token, b, String, DataType)
f ((_, Just "-v") : (t :: b
t, Just var :: String
var) : _) = (Token, b, String, DataType) -> m (Token, b, String, DataType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
base, b
t, String
varName, DataSource -> DataType
varType (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token]
list)
where
(varName :: String
varName, varType :: DataSource -> DataType
varType) = case Char -> String -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
elemIndex '[' String
var of
Just i :: Int
i -> (Int -> ShowS
forall a. Int -> [a] -> [a]
take Int
i String
var, DataSource -> DataType
DataArray)
Nothing -> (String
var, DataSource -> DataType
DataString)
f (_:rest :: [(b, Maybe String)]
rest) = [(b, Maybe String)] -> m (Token, b, String, DataType)
f [(b, Maybe String)]
rest
f [] = String -> m (Token, b, String, DataType)
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "not found"
getMapfileArray :: a -> [Token] -> Maybe (a, Token, String, DataType)
getMapfileArray base :: a
base arguments :: [Token]
arguments = do
Token
lastArg <- [Token] -> Maybe Token
forall a. [a] -> Maybe a
listToMaybe ([Token] -> [Token]
forall a. [a] -> [a]
reverse [Token]
arguments)
String
name <- Token -> Maybe String
getLiteralString Token
lastArg
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String -> Bool
isVariableName String
name
(a, Token, String, DataType) -> Maybe (a, Token, String, DataType)
forall (m :: * -> *) a. Monad m => a -> m a
return (a
base, Token
lastArg, String
name, DataSource -> DataType
DataArray DataSource
SourceExternal)
getReadArrayVariables :: [Token] -> [Maybe (Token, Token, String, DataType)]
getReadArrayVariables args :: [Token]
args =
((Token, Token) -> Maybe (Token, Token, String, DataType))
-> [(Token, Token)] -> [Maybe (Token, Token, String, DataType)]
forall a b. (a -> b) -> [a] -> [b]
map (Token -> Maybe (Token, Token, String, DataType)
getLiteralArray (Token -> Maybe (Token, Token, String, DataType))
-> ((Token, Token) -> Token)
-> (Token, Token)
-> Maybe (Token, Token, String, DataType)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Token, Token) -> Token
forall a b. (a, b) -> b
snd)
(((Token, Token) -> Bool) -> [(Token, Token)] -> [(Token, Token)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Token -> Bool
isArrayFlag (Token -> Bool)
-> ((Token, Token) -> Token) -> (Token, Token) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Token, Token) -> Token
forall a b. (a, b) -> a
fst) ([Token] -> [Token] -> [(Token, Token)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Token]
args ([Token] -> [Token]
forall a. [a] -> [a]
tail [Token]
args)))
isArrayFlag :: Token -> Bool
isArrayFlag x :: Token
x = Bool -> Maybe Bool -> Bool
forall a. a -> Maybe a -> a
fromMaybe Bool
False (Maybe Bool -> Bool) -> Maybe Bool -> Bool
forall a b. (a -> b) -> a -> b
$ do
String
str <- Token -> Maybe String
getLiteralString Token
x
Bool -> Maybe Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Maybe Bool) -> Bool -> Maybe Bool
forall a b. (a -> b) -> a -> b
$ case String
str of
'-':'-':_ -> Bool
False
'-':str :: String
str -> 'a' Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
str
_ -> Bool
False
getFlagVariable :: [Token] -> Maybe (Token, Token, String, DataType)
getFlagVariable (n :: Token
n:v :: Token
v:_) = do
String
name <- Token -> Maybe String
getLiteralString Token
n
(Token, Token, String, DataType)
-> Maybe (Token, Token, String, DataType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Token
base, Token
n, "FLAGS_" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
name, DataSource -> DataType
DataString (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ DataSource
SourceExternal)
getFlagVariable _ = Maybe (Token, Token, String, DataType)
forall a. Maybe a
Nothing
getModifiedVariableCommand _ = []
getIndexReferences :: String -> [String]
getIndexReferences s :: String
s = [String] -> Maybe [String] -> [String]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [String] -> [String]) -> Maybe [String] -> [String]
forall a b. (a -> b) -> a -> b
$ do
[String]
match <- Regex -> String -> Maybe [String]
matchRegex Regex
re String
s
String
index <- [String]
match [String] -> Int -> Maybe String
forall a. [a] -> Int -> Maybe a
!!! 0
[String] -> Maybe [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> Maybe [String]) -> [String] -> Maybe [String]
forall a b. (a -> b) -> a -> b
$ Regex -> String -> [String]
matchAllStrings Regex
variableNameRegex String
index
where
re :: Regex
re = String -> Regex
mkRegex "(\\[.*\\])"
prop_getOffsetReferences1 :: Bool
prop_getOffsetReferences1 = String -> [String]
getOffsetReferences ":bar" [String] -> [String] -> Bool
forall a. Eq a => a -> a -> Bool
== ["bar"]
prop_getOffsetReferences2 :: Bool
prop_getOffsetReferences2 = String -> [String]
getOffsetReferences ":bar:baz" [String] -> [String] -> Bool
forall a. Eq a => a -> a -> Bool
== ["bar", "baz"]
prop_getOffsetReferences3 :: Bool
prop_getOffsetReferences3 = String -> [String]
getOffsetReferences "[foo]:bar" [String] -> [String] -> Bool
forall a. Eq a => a -> a -> Bool
== ["bar"]
prop_getOffsetReferences4 :: Bool
prop_getOffsetReferences4 = String -> [String]
getOffsetReferences "[foo]:bar:baz" [String] -> [String] -> Bool
forall a. Eq a => a -> a -> Bool
== ["bar", "baz"]
getOffsetReferences :: String -> [String]
getOffsetReferences mods :: String
mods = [String] -> Maybe [String] -> [String]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [String] -> [String]) -> Maybe [String] -> [String]
forall a b. (a -> b) -> a -> b
$ do
[String]
match <- Regex -> String -> Maybe [String]
matchRegex Regex
re String
mods
String
offsets <- [String]
match [String] -> Int -> Maybe String
forall a. [a] -> Int -> Maybe a
!!! 1
[String] -> Maybe [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> Maybe [String]) -> [String] -> Maybe [String]
forall a b. (a -> b) -> a -> b
$ Regex -> String -> [String]
matchAllStrings Regex
variableNameRegex String
offsets
where
re :: Regex
re = String -> Regex
mkRegex "^(\\[.+\\])? *:([^-=?+].*)"
getReferencedVariables :: Map Id Token -> Token -> [(Token, Token, String)]
getReferencedVariables parents :: Map Id Token
parents t :: Token
t =
case Token
t of
T_DollarBraced id :: Id
id _ l :: Token
l -> let str :: String
str = Token -> String
bracedString Token
t in
(Token
t, Token
t, ShowS
getBracedReference String
str) (Token, Token, String)
-> [(Token, Token, String)] -> [(Token, Token, String)]
forall a. a -> [a] -> [a]
:
(String -> (Token, Token, String))
-> [String] -> [(Token, Token, String)]
forall a b. (a -> b) -> [a] -> [b]
map (\x :: String
x -> (Token
l, Token
l, String
x)) (
String -> [String]
getIndexReferences String
str
[String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ String -> [String]
getOffsetReferences (ShowS
getBracedModifier String
str))
TA_Variable id :: Id
id name :: String
name _ ->
if Token -> Bool
isArithmeticAssignment Token
t
then []
else [(Token
t, Token
t, String
name)]
T_Assignment id :: Id
id mode :: AssignmentMode
mode str :: String
str _ word :: Token
word ->
[(Token
t, Token
t, String
str) | AssignmentMode
mode AssignmentMode -> AssignmentMode -> Bool
forall a. Eq a => a -> a -> Bool
== AssignmentMode
Append] [(Token, Token, String)]
-> [(Token, Token, String)] -> [(Token, Token, String)]
forall a. [a] -> [a] -> [a]
++ String -> Token -> Token -> [(Token, Token, String)]
forall b. String -> b -> Token -> [(b, b, String)]
specialReferences String
str Token
t Token
word
TC_Unary id :: Id
id _ "-v" token :: Token
token -> Token -> Token -> [(Token, Token, String)]
forall a. a -> Token -> [(a, Token, String)]
getIfReference Token
t Token
token
TC_Unary id :: Id
id _ "-R" token :: Token
token -> Token -> Token -> [(Token, Token, String)]
forall a. a -> Token -> [(a, Token, String)]
getIfReference Token
t Token
token
TC_Binary id :: Id
id DoubleBracket op :: String
op lhs :: Token
lhs rhs :: Token
rhs ->
if String -> Bool
isDereferencing String
op
then (Token -> [(Token, Token, String)])
-> [Token] -> [(Token, Token, String)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Token -> Token -> [(Token, Token, String)]
forall a. a -> Token -> [(a, Token, String)]
getIfReference Token
t) [Token
lhs, Token
rhs]
else []
T_BatsTest {} -> [
(Token
t, Token
t, "lines"),
(Token
t, Token
t, "status"),
(Token
t, Token
t, "output")
]
t :: Token
t@(T_FdRedirect _ ('{':var :: String
var) op :: Token
op) ->
[(Token
t, Token
t, (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '}') String
var) | Token -> Bool
isClosingFileOp Token
op]
x :: Token
x -> Token -> [(Token, Token, String)]
getReferencedVariableCommand Token
x
where
specialReferences :: String -> b -> Token -> [(b, b, String)]
specialReferences name :: String
name base :: b
base word :: Token
word =
if String
name String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [
"PS1", "PS2", "PS3", "PS4",
"PROMPT_COMMAND"
]
then
(String -> (b, b, String)) -> [String] -> [(b, b, String)]
forall a b. (a -> b) -> [a] -> [b]
map (\x :: String
x -> (b
base, b
base, String
x)) ([String] -> [(b, b, String)]) -> [String] -> [(b, b, String)]
forall a b. (a -> b) -> a -> b
$
Token -> [String]
getVariablesFromLiteralToken Token
word
else []
literalizer :: Token -> Maybe String
literalizer t :: Token
t = case Token
t of
T_Glob _ s :: String
s -> String -> Maybe String
forall (m :: * -> *) a. Monad m => a -> m a
return String
s
_ -> Maybe String
forall a. Maybe a
Nothing
getIfReference :: a -> Token -> [(a, Token, String)]
getIfReference context :: a
context token :: Token
token = Maybe (a, Token, String) -> [(a, Token, String)]
forall a. Maybe a -> [a]
maybeToList (Maybe (a, Token, String) -> [(a, Token, String)])
-> Maybe (a, Token, String) -> [(a, Token, String)]
forall a b. (a -> b) -> a -> b
$ do
String
str <- (Token -> Maybe String) -> Token -> Maybe String
getLiteralStringExt Token -> Maybe String
literalizer Token
token
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> (Bool -> Bool) -> Bool -> Maybe ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
str
Bool -> Maybe () -> Maybe ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Char -> Bool
isDigit (Char -> Bool) -> Char -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Char
forall a. [a] -> a
head String
str) (Maybe () -> Maybe ()) -> Maybe () -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String -> Maybe ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "is a number"
(a, Token, String) -> Maybe (a, Token, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (a
context, Token
token, ShowS
getBracedReference String
str)
isDereferencing :: String -> Bool
isDereferencing = (String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ["-eq", "-ne", "-lt", "-le", "-gt", "-ge"])
isArithmeticAssignment :: Token -> Bool
isArithmeticAssignment t :: Token
t = case Map Id Token -> Token -> [Token]
getPath Map Id Token
parents Token
t of
this :: Token
this: TA_Assignment _ "=" lhs :: Token
lhs _ :_ -> Token
lhs Token -> Token -> Bool
forall a. Eq a => a -> a -> Bool
== Token
t
_ -> Bool
False
dataTypeFrom :: (DataSource -> DataType) -> Token -> DataType
dataTypeFrom defaultType :: DataSource -> DataType
defaultType v :: Token
v = (case Token
v of T_Array {} -> DataSource -> DataType
DataArray; _ -> DataSource -> DataType
defaultType) (DataSource -> DataType) -> DataSource -> DataType
forall a b. (a -> b) -> a -> b
$ [Token] -> DataSource
SourceFrom [Token
v]
isCommand :: Token -> String -> Bool
isCommand token :: Token
token str :: String
str = Token -> (String -> Bool) -> Bool
isCommandMatch Token
token (\cmd :: String
cmd -> String
cmd String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
str Bool -> Bool -> Bool
|| ('/' Char -> ShowS
forall a. a -> [a] -> [a]
: String
str) String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` String
cmd)
isUnqualifiedCommand :: Token -> String -> Bool
isUnqualifiedCommand token :: Token
token str :: String
str = Token -> (String -> Bool) -> Bool
isCommandMatch Token
token (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
str)
isCommandMatch :: Token -> (String -> Bool) -> Bool
isCommandMatch token :: Token
token matcher :: String -> Bool
matcher = Bool -> Maybe Bool -> Bool
forall a. a -> Maybe a -> a
fromMaybe Bool
False (Maybe Bool -> Bool) -> Maybe Bool -> Bool
forall a b. (a -> b) -> a -> b
$
(String -> Bool) -> Maybe String -> Maybe Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Bool
matcher (Token -> Maybe String
getCommandName Token
token)
isConfusedGlobRegex :: String -> Bool
isConfusedGlobRegex :: String -> Bool
isConfusedGlobRegex ('*':_) = Bool
True
isConfusedGlobRegex [x :: Char
x,'*'] | Char
x Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` "\\." = Bool
True
isConfusedGlobRegex _ = Bool
False
isVariableStartChar :: Char -> Bool
isVariableStartChar x :: Char
x = Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '_' Bool -> Bool -> Bool
|| Char -> Bool
isAsciiLower Char
x Bool -> Bool -> Bool
|| Char -> Bool
isAsciiUpper Char
x
isVariableChar :: Char -> Bool
isVariableChar x :: Char
x = Char -> Bool
isVariableStartChar Char
x Bool -> Bool -> Bool
|| Char -> Bool
isDigit Char
x
variableNameRegex :: Regex
variableNameRegex = String -> Regex
mkRegex "[_a-zA-Z][_a-zA-Z0-9]*"
prop_isVariableName1 :: Bool
prop_isVariableName1 = String -> Bool
isVariableName "_fo123"
prop_isVariableName2 :: Bool
prop_isVariableName2 = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Bool
isVariableName "4"
prop_isVariableName3 :: Bool
prop_isVariableName3 = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Bool
isVariableName "test: "
isVariableName :: String -> Bool
isVariableName (x :: Char
x:r :: String
r) = Char -> Bool
isVariableStartChar Char
x Bool -> Bool -> Bool
&& (Char -> Bool) -> String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isVariableChar String
r
isVariableName _ = Bool
False
getVariablesFromLiteralToken :: Token -> [String]
getVariablesFromLiteralToken token :: Token
token =
String -> [String]
getVariablesFromLiteral (Maybe String -> String
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ (Token -> Maybe String) -> Token -> Maybe String
getLiteralStringExt (Maybe String -> Token -> Maybe String
forall a b. a -> b -> a
const (Maybe String -> Token -> Maybe String)
-> Maybe String -> Token -> Maybe String
forall a b. (a -> b) -> a -> b
$ String -> Maybe String
forall (m :: * -> *) a. Monad m => a -> m a
return " ") Token
token)
prop_getVariablesFromLiteral1 :: Bool
prop_getVariablesFromLiteral1 =
String -> [String]
getVariablesFromLiteral "$foo${bar//a/b}$BAZ" [String] -> [String] -> Bool
forall a. Eq a => a -> a -> Bool
== ["foo", "bar", "BAZ"]
getVariablesFromLiteral :: String -> [String]
getVariablesFromLiteral string :: String
string =
([String] -> String) -> [[String]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ([String] -> Int -> String
forall a. [a] -> Int -> a
!! 0) ([[String]] -> [String]) -> [[String]] -> [String]
forall a b. (a -> b) -> a -> b
$ Regex -> String -> [[String]]
matchAllSubgroups Regex
variableRegex String
string
where
variableRegex :: Regex
variableRegex = String -> Regex
mkRegex "\\$\\{?([A-Za-z0-9_]+)"
prop_getBracedReference1 :: Bool
prop_getBracedReference1 = ShowS
getBracedReference "foo" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "foo"
prop_getBracedReference2 :: Bool
prop_getBracedReference2 = ShowS
getBracedReference "#foo" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "foo"
prop_getBracedReference3 :: Bool
prop_getBracedReference3 = ShowS
getBracedReference "#" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "#"
prop_getBracedReference4 :: Bool
prop_getBracedReference4 = ShowS
getBracedReference "##" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "#"
prop_getBracedReference5 :: Bool
prop_getBracedReference5 = ShowS
getBracedReference "#!" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "!"
prop_getBracedReference6 :: Bool
prop_getBracedReference6 = ShowS
getBracedReference "!#" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "#"
prop_getBracedReference7 :: Bool
prop_getBracedReference7 = ShowS
getBracedReference "!foo#?" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "foo"
prop_getBracedReference8 :: Bool
prop_getBracedReference8 = ShowS
getBracedReference "foo-bar" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "foo"
prop_getBracedReference9 :: Bool
prop_getBracedReference9 = ShowS
getBracedReference "foo:-bar" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "foo"
prop_getBracedReference10 :: Bool
prop_getBracedReference10= ShowS
getBracedReference "foo: -1" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "foo"
prop_getBracedReference11 :: Bool
prop_getBracedReference11= ShowS
getBracedReference "!os*" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ""
prop_getBracedReference12 :: Bool
prop_getBracedReference12= ShowS
getBracedReference "!os?bar**" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ""
prop_getBracedReference13 :: Bool
prop_getBracedReference13= ShowS
getBracedReference "foo[bar]" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "foo"
getBracedReference :: ShowS
getBracedReference s :: String
s = String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe String
s (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$
String -> Maybe String
nameExpansion String
s Maybe String -> Maybe String -> Maybe String
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` String -> Maybe String
forall (m :: * -> *).
(Monad m, Alternative m) =>
String -> m String
takeName String
noPrefix Maybe String -> Maybe String -> Maybe String
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` String -> Maybe String
forall (m :: * -> *). MonadFail m => String -> m String
getSpecial String
noPrefix Maybe String -> Maybe String -> Maybe String
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` String -> Maybe String
forall (m :: * -> *). MonadFail m => String -> m String
getSpecial String
s
where
noPrefix :: String
noPrefix = ShowS
dropPrefix String
s
dropPrefix :: ShowS
dropPrefix (c :: Char
c:rest :: String
rest) = if Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` "!#" then String
rest else Char
cChar -> ShowS
forall a. a -> [a] -> [a]
:String
rest
dropPrefix "" = ""
takeName :: String -> m String
takeName s :: String
s = do
let name :: String
name = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile Char -> Bool
isVariableChar String
s
Bool -> m ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> m ()) -> (Bool -> Bool) -> Bool -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> m ()) -> Bool -> m ()
forall a b. (a -> b) -> a -> b
$ String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
name
String -> m String
forall (m :: * -> *) a. Monad m => a -> m a
return String
name
getSpecial :: String -> m String
getSpecial (c :: Char
c:_) =
if Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` "*@#?-$!" then String -> m String
forall (m :: * -> *) a. Monad m => a -> m a
return [Char
c] else String -> m String
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "not special"
getSpecial _ = String -> m String
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "empty"
nameExpansion :: String -> Maybe String
nameExpansion ('!':rest :: String
rest) = do
let suffix :: String
suffix = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isVariableChar String
rest
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String
suffix String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
rest
Char
first <- String
suffix String -> Int -> Maybe Char
forall a. [a] -> Int -> Maybe a
!!! 0
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Char
first Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` "*?"
String -> Maybe String
forall (m :: * -> *) a. Monad m => a -> m a
return ""
nameExpansion _ = Maybe String
forall a. Maybe a
Nothing
prop_getBracedModifier1 :: Bool
prop_getBracedModifier1 = ShowS
getBracedModifier "foo:bar:baz" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ":bar:baz"
prop_getBracedModifier2 :: Bool
prop_getBracedModifier2 = ShowS
getBracedModifier "!var:-foo" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ":-foo"
prop_getBracedModifier3 :: Bool
prop_getBracedModifier3 = ShowS
getBracedModifier "foo[bar]" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "[bar]"
getBracedModifier :: ShowS
getBracedModifier s :: String
s = String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe "" (Maybe String -> String)
-> ([String] -> Maybe String) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> Maybe String
forall a. [a] -> Maybe a
listToMaybe ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ do
let var :: String
var = ShowS
getBracedReference String
s
String
a <- String -> [String]
dropModifier String
s
String -> String -> [String]
forall a. Eq a => [a] -> [a] -> [[a]]
dropPrefix String
var String
a
where
dropPrefix :: [a] -> [a] -> [[a]]
dropPrefix [] t :: [a]
t = [a] -> [[a]]
forall (m :: * -> *) a. Monad m => a -> m a
return [a]
t
dropPrefix (a :: a
a:b :: [a]
b) (c :: a
c:d :: [a]
d) | a
a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
c = [a] -> [a] -> [[a]]
dropPrefix [a]
b [a]
d
dropPrefix _ _ = []
dropModifier :: String -> [String]
dropModifier (c :: Char
c:rest :: String
rest) | Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` "#!" = [String
rest, Char
cChar -> ShowS
forall a. a -> [a] -> [a]
:String
rest]
dropModifier x :: String
x = [String
x]
potentially :: Monad m => Maybe (m ()) -> m ()
potentially :: Maybe (m ()) -> m ()
potentially = m () -> Maybe (m ()) -> m ()
forall a. a -> Maybe a -> a
fromMaybe (() -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
headOrDefault :: p -> [p] -> p
headOrDefault _ (a :: p
a:_) = p
a
headOrDefault def :: p
def _ = p
def
!!! :: [a] -> Int -> Maybe a
(!!!) list :: [a]
list i :: Int
i =
case Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop Int
i [a]
list of
[] -> Maybe a
forall a. Maybe a
Nothing
(r :: a
r:_) -> a -> Maybe a
forall a. a -> Maybe a
Just a
r
whenShell :: t Shell -> m () -> m ()
whenShell l :: t Shell
l c :: m ()
c = do
Shell
shell <- (Parameters -> Shell) -> m Shell
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Parameters -> Shell
shellType
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Shell
shell Shell -> t Shell -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` t Shell
l ) m ()
c
filterByAnnotation :: AnalysisSpec -> Parameters -> [TokenComment] -> [TokenComment]
filterByAnnotation asSpec :: AnalysisSpec
asSpec params :: Parameters
params =
(TokenComment -> Bool) -> [TokenComment] -> [TokenComment]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (TokenComment -> Bool) -> TokenComment -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TokenComment -> Bool
shouldIgnore)
where
token :: Token
token = AnalysisSpec -> Token
asScript AnalysisSpec
asSpec
shouldIgnore :: TokenComment -> Bool
shouldIgnore note :: TokenComment
note =
(Token -> Bool) -> [Token] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Code -> Token -> Bool
shouldIgnoreFor (TokenComment -> Code
getCode TokenComment
note)) ([Token] -> Bool) -> [Token] -> Bool
forall a b. (a -> b) -> a -> b
$
Map Id Token -> Token -> [Token]
getPath Map Id Token
parents (Id -> Token
T_Bang (Id -> Token) -> Id -> Token
forall a b. (a -> b) -> a -> b
$ TokenComment -> Id
tcId TokenComment
note)
shouldIgnoreFor :: Code -> Token -> Bool
shouldIgnoreFor _ T_Include {} = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ AnalysisSpec -> Bool
asCheckSourced AnalysisSpec
asSpec
shouldIgnoreFor code :: Code
code t :: Token
t = Code -> Token -> Bool
isAnnotationIgnoringCode Code
code Token
t
parents :: Map Id Token
parents = Parameters -> Map Id Token
parentMap Parameters
params
getCode :: TokenComment -> Code
getCode = Comment -> Code
cCode (Comment -> Code)
-> (TokenComment -> Comment) -> TokenComment -> Code
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TokenComment -> Comment
tcComment
shouldIgnoreCode :: Parameters -> Code -> Token -> Bool
shouldIgnoreCode params :: Parameters
params code :: Code
code t :: Token
t =
(Token -> Bool) -> [Token] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Code -> Token -> Bool
isAnnotationIgnoringCode Code
code) ([Token] -> Bool) -> [Token] -> Bool
forall a b. (a -> b) -> a -> b
$
Map Id Token -> Token -> [Token]
getPath (Parameters -> Map Id Token
parentMap Parameters
params) Token
t
isCountingReference :: Token -> Bool
isCountingReference (T_DollarBraced id :: Id
id _ token :: Token
token) =
case [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ Token -> [String]
oversimplify Token
token of
'#':_ -> Bool
True
_ -> Bool
False
isCountingReference _ = Bool
False
isQuotedAlternativeReference :: Token -> Bool
isQuotedAlternativeReference t :: Token
t =
case Token
t of
T_DollarBraced _ _ _ ->
ShowS
getBracedModifier (Token -> String
bracedString Token
t) String -> Regex -> Bool
`matches` Regex
re
_ -> Bool
False
where
re :: Regex
re = String -> Regex
mkRegex "(^|\\]):?\\+"
getGnuOpts :: String -> Token -> Maybe [(String, Token)]
getGnuOpts = (Token -> [(Token, String)])
-> String -> Token -> Maybe [(String, Token)]
getOpts Token -> [(Token, String)]
getAllFlags
getBsdOpts :: String -> Token -> Maybe [(String, Token)]
getBsdOpts = (Token -> [(Token, String)])
-> String -> Token -> Maybe [(String, Token)]
getOpts Token -> [(Token, String)]
getLeadingFlags
getOpts :: (Token -> [(Token, String)]) -> String -> Token -> Maybe [(String, Token)]
getOpts :: (Token -> [(Token, String)])
-> String -> Token -> Maybe [(String, Token)]
getOpts flagTokenizer :: Token -> [(Token, String)]
flagTokenizer string :: String
string cmd :: Token
cmd = [(Token, String)] -> Maybe [(String, Token)]
forall b. [(b, String)] -> Maybe [(String, b)]
process [(Token, String)]
flags
where
flags :: [(Token, String)]
flags = Token -> [(Token, String)]
flagTokenizer Token
cmd
flagList :: String -> [(String, Bool)]
flagList (c :: Char
c:':':rest :: String
rest) = ([Char
c], Bool
True) (String, Bool) -> [(String, Bool)] -> [(String, Bool)]
forall a. a -> [a] -> [a]
: String -> [(String, Bool)]
flagList String
rest
flagList (c :: Char
c:rest :: String
rest) = ([Char
c], Bool
False) (String, Bool) -> [(String, Bool)] -> [(String, Bool)]
forall a. a -> [a] -> [a]
: String -> [(String, Bool)]
flagList String
rest
flagList [] = []
flagMap :: Map String Bool
flagMap = [(String, Bool)] -> Map String Bool
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList ([(String, Bool)] -> Map String Bool)
-> [(String, Bool)] -> Map String Bool
forall a b. (a -> b) -> a -> b
$ ("", Bool
False) (String, Bool) -> [(String, Bool)] -> [(String, Bool)]
forall a. a -> [a] -> [a]
: String -> [(String, Bool)]
flagList String
string
process :: [(b, String)] -> Maybe [(String, b)]
process [] = [(String, b)] -> Maybe [(String, b)]
forall (m :: * -> *) a. Monad m => a -> m a
return []
process [(token :: b
token, flag :: String
flag)] = do
Bool
takesArg <- String -> Map String Bool -> Maybe Bool
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
flag Map String Bool
flagMap
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not Bool
takesArg
[(String, b)] -> Maybe [(String, b)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(String
flag, b
token)]
process ((token1 :: b
token1, flag1 :: String
flag1):rest2 :: [(b, String)]
rest2@((token2 :: b
token2, flag2 :: String
flag2):rest :: [(b, String)]
rest)) = do
Bool
takesArg <- String -> Map String Bool -> Maybe Bool
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
flag1 Map String Bool
flagMap
if Bool
takesArg
then do
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ String
flag2 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ""
[(String, b)]
more <- [(b, String)] -> Maybe [(String, b)]
process [(b, String)]
rest
[(String, b)] -> Maybe [(String, b)]
forall (m :: * -> *) a. Monad m => a -> m a
return ([(String, b)] -> Maybe [(String, b)])
-> [(String, b)] -> Maybe [(String, b)]
forall a b. (a -> b) -> a -> b
$ (String
flag1, b
token2) (String, b) -> [(String, b)] -> [(String, b)]
forall a. a -> [a] -> [a]
: [(String, b)]
more
else do
[(String, b)]
more <- [(b, String)] -> Maybe [(String, b)]
process [(b, String)]
rest2
[(String, b)] -> Maybe [(String, b)]
forall (m :: * -> *) a. Monad m => a -> m a
return ([(String, b)] -> Maybe [(String, b)])
-> [(String, b)] -> Maybe [(String, b)]
forall a b. (a -> b) -> a -> b
$ (String
flag1, b
token1) (String, b) -> [(String, b)] -> [(String, b)]
forall a. a -> [a] -> [a]
: [(String, b)]
more
supportsArrays :: Shell -> Bool
supportsArrays shell :: Shell
shell = Shell
shell Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Bash Bool -> Bool -> Bool
|| Shell
shell Shell -> Shell -> Bool
forall a. Eq a => a -> a -> Bool
== Shell
Ksh
isBashLike :: Parameters -> Bool
isBashLike :: Parameters -> Bool
isBashLike params :: Parameters
params =
case Parameters -> Shell
shellType Parameters
params of
Bash -> Bool
True
Ksh -> Bool
True
Dash -> Bool
False
Sh -> Bool
False
return []
runTests :: IO Bool
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])