select loops and bases in arithmetic contexts
This commit is contained in:
parent
059ef63b44
commit
b517ad9e19
|
@ -23,7 +23,7 @@ import qualified Text.Regex as Re
|
|||
|
||||
data Id = Id Int deriving (Show, Eq, Ord)
|
||||
|
||||
data Token = T_AND_IF Id | T_OR_IF Id | T_DSEMI Id | T_Semi Id | T_DLESS Id | T_DGREAT Id | T_LESSAND Id | T_GREATAND Id | T_LESSGREAT Id | T_DLESSDASH Id | T_CLOBBER Id | T_If Id | T_Then Id | T_Else Id | T_Elif Id | T_Fi Id | T_Do Id | T_Done Id | T_Case Id | T_Esac Id | T_While Id | T_Until Id | T_For Id | T_Lbrace Id | T_Rbrace Id | T_Lparen Id | T_Rparen Id | T_Bang Id | T_In Id | T_NEWLINE Id | T_EOF Id | T_Less Id | T_Greater Id | T_SingleQuoted Id String | T_Literal Id String | T_NormalWord Id [Token] | T_DoubleQuoted Id [Token] | T_DollarExpansion Id [Token] | T_DollarBraced Id Token | T_DollarArithmetic Id Token | T_BraceExpansion Id String | T_IoFile Id Token Token | T_HereDoc Id Bool Bool String | T_HereString Id Token | T_FdRedirect Id String Token | T_Assignment Id String Token | T_Array Id [Token] | T_Redirecting Id [Token] Token | T_SimpleCommand Id [Token] [Token] | T_Pipeline Id [Token] | T_Banged Id Token | T_AndIf Id (Token) (Token) | T_OrIf Id (Token) (Token) | T_Backgrounded Id Token | T_IfExpression Id [([Token],[Token])] [Token] | T_Subshell Id [Token] | T_BraceGroup Id [Token] | T_WhileExpression Id [Token] [Token] | T_UntilExpression Id [Token] [Token] | T_ForIn Id String [Token] [Token] | T_CaseExpression Id Token [([Token],[Token])] | T_Function Id String Token | T_Arithmetic Id Token | T_Script Id String [Token] | T_Condition Id ConditionType Token | T_Extglob Id String [Token] | TC_And Id ConditionType String Token Token | TC_Or Id ConditionType String Token Token | TC_Group Id ConditionType Token | TC_Binary Id ConditionType String Token Token | TC_Unary Id ConditionType String Token | TC_Noary Id ConditionType Token | TA_Binary Id String Token Token | TA_Unary Id String Token | TA_Sequence Id [Token] | TA_Variable Id String | TA_Trinary Id Token Token Token | TA_Expansion Id Token | TA_Literal Id String | T_Backticked Id String | T_ProcSub Id String [Token] | T_Glob Id String | T_ForArithmetic Id Token Token Token [Token] | T_DollarSingleQuoted Id String | T_DollarDoubleQuoted Id [Token]
|
||||
data Token = T_AND_IF Id | T_OR_IF Id | T_DSEMI Id | T_Semi Id | T_DLESS Id | T_DGREAT Id | T_LESSAND Id | T_GREATAND Id | T_LESSGREAT Id | T_DLESSDASH Id | T_CLOBBER Id | T_If Id | T_Then Id | T_Else Id | T_Elif Id | T_Fi Id | T_Do Id | T_Done Id | T_Case Id | T_Esac Id | T_While Id | T_Until Id | T_For Id | T_Select Id | T_Lbrace Id | T_Rbrace Id | T_Lparen Id | T_Rparen Id | T_Bang Id | T_In Id | T_NEWLINE Id | T_EOF Id | T_Less Id | T_Greater Id | T_SingleQuoted Id String | T_Literal Id String | T_NormalWord Id [Token] | T_DoubleQuoted Id [Token] | T_DollarExpansion Id [Token] | T_DollarBraced Id Token | T_DollarArithmetic Id Token | T_BraceExpansion Id String | T_IoFile Id Token Token | T_HereDoc Id Bool Bool String | T_HereString Id Token | T_FdRedirect Id String Token | T_Assignment Id String Token | T_Array Id [Token] | T_Redirecting Id [Token] Token | T_SimpleCommand Id [Token] [Token] | T_Pipeline Id [Token] | T_Banged Id Token | T_AndIf Id (Token) (Token) | T_OrIf Id (Token) (Token) | T_Backgrounded Id Token | T_IfExpression Id [([Token],[Token])] [Token] | T_Subshell Id [Token] | T_BraceGroup Id [Token] | T_WhileExpression Id [Token] [Token] | T_UntilExpression Id [Token] [Token] | T_ForIn Id String [Token] [Token] | T_SelectIn Id String [Token] [Token] | T_CaseExpression Id Token [([Token],[Token])] | T_Function Id String Token | T_Arithmetic Id Token | T_Script Id String [Token] | T_Condition Id ConditionType Token | T_Extglob Id String [Token] | TC_And Id ConditionType String Token Token | TC_Or Id ConditionType String Token Token | TC_Group Id ConditionType Token | TC_Binary Id ConditionType String Token Token | TC_Unary Id ConditionType String Token | TC_Noary Id ConditionType Token | TA_Binary Id String Token Token | TA_Unary Id String Token | TA_Sequence Id [Token] | TA_Variable Id String | TA_Trinary Id Token Token Token | TA_Expansion Id Token | TA_Literal Id String | T_Backticked Id String | T_ProcSub Id String [Token] | T_Glob Id String | T_ForArithmetic Id Token Token Token [Token] | T_DollarSingleQuoted Id String | T_DollarDoubleQuoted Id [Token] | TA_Base Id String Token
|
||||
|
||||
deriving (Show)
|
||||
|
||||
|
@ -96,6 +96,7 @@ analyze f g i t =
|
|||
delve (T_WhileExpression id c l) = dll c l $ T_WhileExpression id
|
||||
delve (T_UntilExpression id c l) = dll c l $ T_UntilExpression id
|
||||
delve (T_ForIn id v w l) = dll w l $ T_ForIn id v
|
||||
delve (T_SelectIn id v w l) = dll w l $ T_SelectIn id v
|
||||
delve (T_CaseExpression id word cases) = do
|
||||
newWord <- round word
|
||||
newCases <- mapM (\(c, t) -> do
|
||||
|
@ -134,6 +135,7 @@ analyze f g i t =
|
|||
c <- round t3
|
||||
return $ TA_Trinary id a b c
|
||||
delve (TA_Expansion id t) = d1 t $ TA_Expansion id
|
||||
delve (TA_Base id b t) = d1 t $ TA_Base id b
|
||||
delve t = return t
|
||||
|
||||
getId t = case t of
|
||||
|
@ -160,6 +162,7 @@ getId t = case t of
|
|||
T_While id -> id
|
||||
T_Until id -> id
|
||||
T_For id -> id
|
||||
T_Select id -> id
|
||||
T_Lbrace id -> id
|
||||
T_Rbrace id -> id
|
||||
T_Lparen id -> id
|
||||
|
@ -197,6 +200,7 @@ getId t = case t of
|
|||
T_WhileExpression id _ _ -> id
|
||||
T_UntilExpression id _ _ -> id
|
||||
T_ForIn id _ _ _ -> id
|
||||
T_SelectIn id _ _ _ -> id
|
||||
T_CaseExpression id _ _ -> id
|
||||
T_Function id _ _ -> id
|
||||
T_Arithmetic id _ -> id
|
||||
|
@ -217,6 +221,7 @@ getId t = case t of
|
|||
TA_Trinary id _ _ _ -> id
|
||||
TA_Expansion id _ -> id
|
||||
TA_Literal id _ -> id
|
||||
TA_Base id _ _ -> id
|
||||
T_ProcSub id _ _ -> id
|
||||
T_Glob id _ -> id
|
||||
T_ForArithmetic id _ _ _ _ -> id
|
||||
|
|
|
@ -38,7 +38,6 @@ checks = concat [
|
|||
|
||||
runAllAnalytics = checkList checks
|
||||
checkList l t m = foldl (\x f -> f t x) m l
|
||||
checkList l t m = foldl (\x f -> f t x) m l
|
||||
|
||||
runBasicAnalysis f t m = snd $ runState (doAnalysis f t) m
|
||||
basicChecks = [
|
||||
|
@ -58,6 +57,7 @@ basicChecks = [
|
|||
,checkForDecimals
|
||||
,checkDivBeforeMult
|
||||
,checkArithmeticDeref
|
||||
,checkArithmeticBadOctal
|
||||
,checkComparisonAgainstGlob
|
||||
,checkPrintfVar
|
||||
,checkCommarrays
|
||||
|
@ -211,7 +211,7 @@ checkPipePitfalls (T_Pipeline id commands) = do
|
|||
for [["grep"], ["sed"]] $ \id -> style id "You don't need grep | sed, sed can filter lines by itself."
|
||||
for [["grep"], ["awk"]] $ \id -> style id "You don't need grep | awk, awk can filter lines by itself."
|
||||
for [["ls"], ["?"]] $ \id -> warn id "Don't parse ls output; it mangles filenames."
|
||||
for [["ls"], ["grep"]] $ \id -> warn id "Don't use ls | grep. Use a for loop with a condition in it."
|
||||
for [["ls"], ["grep"]] $ \id -> warn id "Don't use ls | grep. Use a glob or a for loop with a condition."
|
||||
for [["ls"], ["xargs"]] $ \id -> warn id "Don't use ls | xargs. Use find -exec .. +"
|
||||
for [["find"], ["xargs"]]$ \id -> warn id "Don't use find | xargs cmd. find -exec cmd {} + handles whitespace."
|
||||
for [["?"], ["echo"]] $ \id -> info id "echo doesn't read from stdin, are you sure you should be piping to it?"
|
||||
|
@ -263,6 +263,7 @@ checkUndeclaredBash t@(T_Script id sb _) m =
|
|||
bashism (T_DollarDoubleQuoted id _) = warnMsg id "$\"..\""
|
||||
bashism (T_ForArithmetic id _ _ _ _) = warnMsg id "arithmetic for loops"
|
||||
bashism (T_Arithmetic id _) = warnMsg id "((..))"
|
||||
bashism (T_SelectIn id _ _ _) = warnMsg id "select loops"
|
||||
bashism _ = return()
|
||||
|
||||
prop_checkForInQuoted = verify checkForInQuoted "for f in \"$(ls)\"; do echo foo; done"
|
||||
|
@ -509,6 +510,12 @@ checkArithmeticDeref (TA_Expansion _ (T_DollarBraced id l)) | not . excepting $
|
|||
excepting s = (any (`elem` "/.:#%?*@") s) || (isDigit $ head s)
|
||||
checkArithmeticDeref _ = return ()
|
||||
|
||||
prop_checkArithmeticBadOctal1 = verify checkArithmeticBadOctal "(( 0192 ))"
|
||||
prop_checkArithmeticBadOctal2 = verifyNot checkArithmeticBadOctal "(( 0x192 ))"
|
||||
prop_checkArithmeticBadOctal3 = verifyNot checkArithmeticBadOctal "(( 1 ^ 0777 ))"
|
||||
checkArithmeticBadOctal (TA_Base id "0" (TA_Literal _ str)) | '9' `elem` str || '8' `elem` str =
|
||||
err id $ "Numbers with leading 0 are considered octal."
|
||||
checkArithmeticBadOctal _ = return ()
|
||||
|
||||
prop_checkComparisonAgainstGlob = verify checkComparisonAgainstGlob "[[ $cow == $bar ]]"
|
||||
prop_checkComparisonAgainstGlob2 = verifyNot checkComparisonAgainstGlob "[[ $cow == \"$bar\" ]]"
|
||||
|
@ -782,7 +789,8 @@ getModifiedVariablesWithType spacefulF t =
|
|||
else []
|
||||
|
||||
--Points to 'for' rather than variable
|
||||
T_ForIn id str words _ -> [(id, str, if any (isSpaceful spacefulF) words then Spaceful else Spaceless)]
|
||||
T_ForIn id str words _ -> [(id, str, if any (isSpaceful spacefulF) words || null words then Spaceful else Spaceless)]
|
||||
T_SelectIn id str words _ -> [(id, str, if any (isSpaceful spacefulF) words || null words then Spaceful else Spaceless)]
|
||||
_ -> []
|
||||
|
||||
isSpaceful :: (String -> Bool) -> Token -> Bool
|
||||
|
|
|
@ -343,6 +343,7 @@ prop_a7 = isOk readArithmeticContents "3*2**10"
|
|||
prop_a8 = isOk readArithmeticContents "3"
|
||||
prop_a9 = isOk readArithmeticContents "a^!-b"
|
||||
prop_aA = isOk readArithmeticContents "! $?"
|
||||
prop_aB = isOk readArithmeticContents "10#08 * 16#f"
|
||||
readArithmeticContents =
|
||||
readSequence
|
||||
where
|
||||
|
@ -381,9 +382,35 @@ readArithmeticContents =
|
|||
readNumber = do
|
||||
id <- getNextId
|
||||
num <- many1 $ oneOf "0123456789."
|
||||
return $ TA_Literal id num
|
||||
return $ TA_Literal id (num)
|
||||
|
||||
readArithTerm = readGroup <|> readExpansion <|> readNumber <|> readVar
|
||||
readBased = getArbitrary <|> getHex <|> getOct
|
||||
where
|
||||
getThing prefix litchars = try $ do
|
||||
id <- getNextId
|
||||
x <- prefix
|
||||
t <- readExpansion <|> (do
|
||||
i <- getNextId
|
||||
stuff <- many1 litchars
|
||||
return $ TA_Literal i stuff)
|
||||
return $ TA_Base id x t
|
||||
|
||||
getArbitrary = getThing arbitrary variableChars
|
||||
getHex = getThing hex hexDigit
|
||||
getOct = getThing oct digit
|
||||
|
||||
arbitrary = try $ do
|
||||
b <- many1 digit
|
||||
s <- char '#'
|
||||
return (b ++ [s])
|
||||
hex = try $ do
|
||||
z <- char '0'
|
||||
x <- oneOf "xX"
|
||||
return (z:x:[])
|
||||
oct = string "0"
|
||||
|
||||
readArithTerm = readBased <|> readArithTermUnit
|
||||
readArithTermUnit = readGroup <|> readExpansion <|> readNumber <|> readVar
|
||||
|
||||
readSequence = do
|
||||
spacing
|
||||
|
@ -1138,6 +1165,22 @@ readForClause = called "for loop" $ do
|
|||
values <- readInClause <|> (readSequentialSep >> return [])
|
||||
return $ \id group -> (return $ T_ForIn id name values group)
|
||||
|
||||
prop_readSelectClause1 = isOk readSelectClause "select foo in *; do echo $foo; done"
|
||||
prop_readSelectClause2 = isOk readSelectClause "select foo; do echo $foo; done"
|
||||
readSelectClause = called "select loop" $ do
|
||||
pos <- getPosition
|
||||
(T_Select id) <- g_Select
|
||||
spacing
|
||||
typ <- readRegular
|
||||
group <- readDoGroup pos
|
||||
typ id group
|
||||
where
|
||||
readRegular = do
|
||||
name <- readVariableName
|
||||
spacing
|
||||
values <- readInClause <|> (readSequentialSep >> return [])
|
||||
return $ \id group -> (return $ T_SelectIn id name values group)
|
||||
|
||||
readInClause = do
|
||||
g_In
|
||||
things <- (readCmdWord) `reluctantlyTill`
|
||||
|
@ -1232,7 +1275,7 @@ readPattern = (readNormalWord `thenSkip` spacing) `sepBy1` (char '|' `thenSkip`
|
|||
|
||||
readCompoundCommand = do
|
||||
id <- getNextId
|
||||
cmd <- choice [ readBraceGroup, readArithmeticExpression, readSubshell, readCondition, readWhileClause, readUntilClause, readIfClause, readForClause, readCaseClause, readFunctionDefinition]
|
||||
cmd <- choice [ readBraceGroup, readArithmeticExpression, readSubshell, readCondition, readWhileClause, readUntilClause, readIfClause, readForClause, readSelectClause, readCaseClause, readFunctionDefinition]
|
||||
spacing
|
||||
redirs <- many readIoRedirect
|
||||
when (not . null $ redirs) $ optional $ do
|
||||
|
@ -1334,6 +1377,7 @@ g_Esac = tryWordToken "esac" T_Esac
|
|||
g_While = tryWordToken "while" T_While
|
||||
g_Until = tryWordToken "until" T_Until
|
||||
g_For = tryWordToken "for" T_For
|
||||
g_Select = tryWordToken "select" T_Select
|
||||
g_In = tryWordToken "in" T_In
|
||||
g_Lbrace = tryWordToken "{" T_Lbrace
|
||||
g_Rbrace = tryWordToken "}" T_Rbrace
|
||||
|
|
Loading…
Reference in New Issue