Improve 'let' parsing, trigger unused var for ((a=1))
This commit is contained in:
parent
7551a241ad
commit
86999ded1f
|
@ -34,6 +34,7 @@ data CaseType = CaseBreak | CaseFallThrough | CaseContinue deriving (Show, Eq)
|
||||||
|
|
||||||
data Token =
|
data Token =
|
||||||
TA_Binary Id String Token Token
|
TA_Binary Id String Token Token
|
||||||
|
| TA_Assignment Id String Token Token
|
||||||
| TA_Expansion Id [Token]
|
| TA_Expansion Id [Token]
|
||||||
| TA_Index Id Token
|
| TA_Index Id Token
|
||||||
| TA_Sequence Id [Token]
|
| TA_Sequence Id [Token]
|
||||||
|
@ -250,6 +251,7 @@ analyze f g i =
|
||||||
delve (TC_Noary id typ token) = d1 token $ TC_Noary id typ
|
delve (TC_Noary id typ token) = d1 token $ TC_Noary id typ
|
||||||
|
|
||||||
delve (TA_Binary id op t1 t2) = d2 t1 t2 $ TA_Binary id op
|
delve (TA_Binary id op t1 t2) = d2 t1 t2 $ TA_Binary id op
|
||||||
|
delve (TA_Assignment id op t1 t2) = d2 t1 t2 $ TA_Assignment id op
|
||||||
delve (TA_Unary id op t1) = d1 t1 $ TA_Unary id op
|
delve (TA_Unary id op t1) = d1 t1 $ TA_Unary id op
|
||||||
delve (TA_Sequence id l) = dl l $ TA_Sequence id
|
delve (TA_Sequence id l) = dl l $ TA_Sequence id
|
||||||
delve (TA_Trinary id t1 t2 t3) = do
|
delve (TA_Trinary id t1 t2 t3) = do
|
||||||
|
@ -344,6 +346,7 @@ getId t = case t of
|
||||||
TC_Unary id _ _ _ -> id
|
TC_Unary id _ _ _ -> id
|
||||||
TC_Noary id _ _ -> id
|
TC_Noary id _ _ -> id
|
||||||
TA_Binary id _ _ _ -> id
|
TA_Binary id _ _ _ -> id
|
||||||
|
TA_Assignment id _ _ _ -> id
|
||||||
TA_Unary id _ _ -> id
|
TA_Unary id _ _ -> id
|
||||||
TA_Sequence id _ -> id
|
TA_Sequence id _ -> id
|
||||||
TA_Trinary id _ _ _ -> id
|
TA_Trinary id _ _ _ -> id
|
||||||
|
|
|
@ -2054,6 +2054,9 @@ prop_checkUnused26= verifyNotTree checkUnusedAssignments "declare -F foo"
|
||||||
prop_checkUnused27= verifyTree checkUnusedAssignments "var=3; [ var -eq 3 ]"
|
prop_checkUnused27= verifyTree checkUnusedAssignments "var=3; [ var -eq 3 ]"
|
||||||
prop_checkUnused28= verifyNotTree checkUnusedAssignments "var=3; [[ var -eq 3 ]]"
|
prop_checkUnused28= verifyNotTree checkUnusedAssignments "var=3; [[ var -eq 3 ]]"
|
||||||
prop_checkUnused29= verifyNotTree checkUnusedAssignments "var=(a b); declare -p var"
|
prop_checkUnused29= verifyNotTree checkUnusedAssignments "var=(a b); declare -p var"
|
||||||
|
prop_checkUnused30= verifyTree checkUnusedAssignments "let a=1"
|
||||||
|
prop_checkUnused31= verifyTree checkUnusedAssignments "let 'a=1'"
|
||||||
|
prop_checkUnused32= verifyTree checkUnusedAssignments "let a=b=c; echo $a"
|
||||||
checkUnusedAssignments params t = execWriter (mapM_ warnFor unused)
|
checkUnusedAssignments params t = execWriter (mapM_ warnFor unused)
|
||||||
where
|
where
|
||||||
flow = variableFlow params
|
flow = variableFlow params
|
||||||
|
@ -2742,7 +2745,7 @@ checkLoopVariableReassignment params token =
|
||||||
T_ForIn _ s _ _ -> return s
|
T_ForIn _ s _ _ -> return s
|
||||||
T_ForArithmetic _
|
T_ForArithmetic _
|
||||||
(TA_Sequence _
|
(TA_Sequence _
|
||||||
[TA_Binary _ "="
|
[TA_Assignment _ "="
|
||||||
(TA_Expansion _ [T_Literal _ var]) _])
|
(TA_Expansion _ [T_Literal _ var]) _])
|
||||||
_ _ _ -> return var
|
_ _ _ -> return var
|
||||||
_ -> fail "not loop"
|
_ -> fail "not loop"
|
||||||
|
|
|
@ -40,8 +40,6 @@ import qualified Data.Map as Map
|
||||||
import Test.QuickCheck.All (forAllProperties)
|
import Test.QuickCheck.All (forAllProperties)
|
||||||
import Test.QuickCheck.Test (quickCheckWithResult, stdArgs, maxSuccess)
|
import Test.QuickCheck.Test (quickCheckWithResult, stdArgs, maxSuccess)
|
||||||
|
|
||||||
import Debug.Trace
|
|
||||||
|
|
||||||
type Analysis = ReaderT Parameters (Writer [TokenComment]) ()
|
type Analysis = ReaderT Parameters (Writer [TokenComment]) ()
|
||||||
|
|
||||||
|
|
||||||
|
@ -272,7 +270,7 @@ getVariableFlow shell parents t =
|
||||||
assignFirst _ = False
|
assignFirst _ = False
|
||||||
|
|
||||||
setRead t =
|
setRead t =
|
||||||
let read = getReferencedVariables t
|
let read = getReferencedVariables parents t
|
||||||
in mapM_ (\v -> modify (Reference v:)) read
|
in mapM_ (\v -> modify (Reference v:)) read
|
||||||
|
|
||||||
setWritten t =
|
setWritten t =
|
||||||
|
@ -331,7 +329,7 @@ getModifiedVariables t =
|
||||||
TA_Unary _ "|++" var -> maybeToList $ do
|
TA_Unary _ "|++" var -> maybeToList $ do
|
||||||
name <- getLiteralString var
|
name <- getLiteralString var
|
||||||
return (t, t, name, DataString $ SourceFrom [t])
|
return (t, t, name, DataString $ SourceFrom [t])
|
||||||
TA_Binary _ op lhs rhs -> maybeToList $ do
|
TA_Assignment _ op lhs rhs -> maybeToList $ do
|
||||||
guard $ op `elem` ["=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="]
|
guard $ op `elem` ["=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="]
|
||||||
name <- getLiteralString lhs
|
name <- getLiteralString lhs
|
||||||
return (t, t, name, DataString $ SourceFrom [rhs])
|
return (t, t, name, DataString $ SourceFrom [rhs])
|
||||||
|
@ -476,12 +474,15 @@ getIndexReferences s = fromMaybe [] $ do
|
||||||
where
|
where
|
||||||
re = mkRegex "(\\[.*\\])"
|
re = mkRegex "(\\[.*\\])"
|
||||||
|
|
||||||
getReferencedVariables t =
|
getReferencedVariables parents t =
|
||||||
case t of
|
case t of
|
||||||
T_DollarBraced id l -> let str = bracedString t in
|
T_DollarBraced id l -> let str = bracedString t in
|
||||||
(t, t, getBracedReference str) :
|
(t, t, getBracedReference str) :
|
||||||
map (\x -> (l, l, x)) (getIndexReferences str)
|
map (\x -> (l, l, x)) (getIndexReferences str)
|
||||||
TA_Expansion id _ -> getIfReference t t
|
TA_Expansion id _ ->
|
||||||
|
if isArithmeticAssignment t
|
||||||
|
then []
|
||||||
|
else getIfReference t t
|
||||||
T_Assignment id mode str _ word ->
|
T_Assignment id mode str _ word ->
|
||||||
[(t, t, str) | mode == Append] ++ specialReferences str t word
|
[(t, t, str) | mode == Append] ++ specialReferences str t word
|
||||||
|
|
||||||
|
@ -518,6 +519,10 @@ getReferencedVariables t =
|
||||||
|
|
||||||
isDereferencing = (`elem` ["-eq", "-ne", "-lt", "-le", "-gt", "-ge"])
|
isDereferencing = (`elem` ["-eq", "-ne", "-lt", "-le", "-gt", "-ge"])
|
||||||
|
|
||||||
|
isArithmeticAssignment t = case getPath parents t of
|
||||||
|
this: TA_Assignment _ "=" _ _ :_ -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
dataTypeFrom defaultType v = (case v of T_Array {} -> DataArray; _ -> defaultType) $ SourceFrom [v]
|
dataTypeFrom defaultType v = (case v of T_Array {} -> DataArray; _ -> defaultType) $ SourceFrom [v]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -708,7 +708,9 @@ readArithmeticContents =
|
||||||
l <- readAssignment `sepBy` (char ',' >> spacing)
|
l <- readAssignment `sepBy` (char ',' >> spacing)
|
||||||
return $ TA_Sequence id l
|
return $ TA_Sequence id l
|
||||||
|
|
||||||
readAssignment = readTrinary `splitBy` ["=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="]
|
readAssignment = chainr1 readTrinary readAssignmentOp
|
||||||
|
readAssignmentOp = readComboOp ["=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="] TA_Assignment
|
||||||
|
|
||||||
readTrinary = do
|
readTrinary = do
|
||||||
x <- readLogicalOr
|
x <- readLogicalOr
|
||||||
do
|
do
|
||||||
|
@ -2214,13 +2216,29 @@ readTimeSuffix = do
|
||||||
lookAhead $ char '-'
|
lookAhead $ char '-'
|
||||||
readCmdWord
|
readCmdWord
|
||||||
|
|
||||||
-- Fixme: this is a hack that doesn't handle let '++c' or let a\>b
|
-- Fixme: this is a hack that doesn't handle let c='4'"5" or let a\>b
|
||||||
|
readLetSuffix :: Monad m => SCParser m [Token]
|
||||||
readLetSuffix = many1 (readIoRedirect <|> try readLetExpression <|> readCmdWord)
|
readLetSuffix = many1 (readIoRedirect <|> try readLetExpression <|> readCmdWord)
|
||||||
where
|
where
|
||||||
|
readLetExpression :: Monad m => SCParser m Token
|
||||||
readLetExpression = do
|
readLetExpression = do
|
||||||
startPos <- getPosition
|
startPos <- getPosition
|
||||||
expression <- readStringForParser readCmdWord
|
expression <- readStringForParser readCmdWord
|
||||||
subParse startPos readArithmeticContents expression
|
let (unQuoted, newPos) = kludgeAwayQuotes expression startPos
|
||||||
|
subParse newPos readArithmeticContents unQuoted
|
||||||
|
|
||||||
|
kludgeAwayQuotes :: String -> SourcePos -> (String, SourcePos)
|
||||||
|
kludgeAwayQuotes s p =
|
||||||
|
case s of
|
||||||
|
first:rest@(_:_) ->
|
||||||
|
let (last:backwards) = reverse rest
|
||||||
|
middle = reverse backwards
|
||||||
|
in
|
||||||
|
if first `elem` "'\"" && first == last
|
||||||
|
then (middle, updatePosChar p first)
|
||||||
|
else (s, p)
|
||||||
|
x -> (s, p)
|
||||||
|
|
||||||
|
|
||||||
-- bash allows a=(b), ksh allows $a=(b). dash allows neither. Let's warn.
|
-- bash allows a=(b), ksh allows $a=(b). dash allows neither. Let's warn.
|
||||||
readEvalSuffix = many1 (readIoRedirect <|> readCmdWord <|> evalFallback)
|
readEvalSuffix = many1 (readIoRedirect <|> readCmdWord <|> evalFallback)
|
||||||
|
|
Loading…
Reference in New Issue