Better support arrays in arithmetic contexts. Fixes #1074
This commit is contained in:
parent
8d5e3a80ae
commit
d16bf41c3d
|
@ -37,8 +37,8 @@ newtype Root = Root Token
|
||||||
data Token =
|
data Token =
|
||||||
TA_Binary Id String Token Token
|
TA_Binary Id String Token Token
|
||||||
| TA_Assignment Id String Token Token
|
| TA_Assignment Id String Token Token
|
||||||
|
| TA_Variable Id String [Token]
|
||||||
| TA_Expansion Id [Token]
|
| TA_Expansion Id [Token]
|
||||||
| TA_Index Id Token
|
|
||||||
| TA_Sequence Id [Token]
|
| TA_Sequence Id [Token]
|
||||||
| TA_Trinary Id Token Token Token
|
| TA_Trinary Id Token Token Token
|
||||||
| TA_Unary Id String Token
|
| TA_Unary Id String Token
|
||||||
|
@ -266,7 +266,7 @@ analyze f g i =
|
||||||
c <- round t3
|
c <- round t3
|
||||||
return $ TA_Trinary id a b c
|
return $ TA_Trinary id a b c
|
||||||
delve (TA_Expansion id t) = dl t $ TA_Expansion id
|
delve (TA_Expansion id t) = dl t $ TA_Expansion id
|
||||||
delve (TA_Index id t) = d1 t $ TA_Index id
|
delve (TA_Variable id str t) = dl t $ TA_Variable id str
|
||||||
delve (T_Annotation id anns t) = d1 t $ T_Annotation id anns
|
delve (T_Annotation id anns t) = d1 t $ T_Annotation id anns
|
||||||
delve (T_CoProc id var body) = d1 body $ T_CoProc id var
|
delve (T_CoProc id var body) = d1 body $ T_CoProc id var
|
||||||
delve (T_CoProcBody id t) = d1 t $ T_CoProcBody id
|
delve (T_CoProcBody id t) = d1 t $ T_CoProcBody id
|
||||||
|
@ -360,7 +360,6 @@ getId t = case t of
|
||||||
TA_Sequence id _ -> id
|
TA_Sequence id _ -> id
|
||||||
TA_Trinary id _ _ _ -> id
|
TA_Trinary id _ _ _ -> id
|
||||||
TA_Expansion id _ -> id
|
TA_Expansion id _ -> id
|
||||||
TA_Index id _ -> id
|
|
||||||
T_ProcSub id _ _ -> id
|
T_ProcSub id _ _ -> id
|
||||||
T_Glob id _ -> id
|
T_Glob id _ -> id
|
||||||
T_ForArithmetic id _ _ _ _ -> id
|
T_ForArithmetic id _ _ _ _ -> id
|
||||||
|
@ -374,6 +373,7 @@ getId t = case t of
|
||||||
T_Include id _ _ -> id
|
T_Include id _ _ -> id
|
||||||
T_UnparsedIndex id _ _ -> id
|
T_UnparsedIndex id _ _ -> id
|
||||||
TC_Empty id _ -> id
|
TC_Empty id _ -> id
|
||||||
|
TA_Variable id _ _ -> id
|
||||||
|
|
||||||
blank :: Monad m => Token -> m ()
|
blank :: Monad m => Token -> m ()
|
||||||
blank = const $ return ()
|
blank = const $ return ()
|
||||||
|
|
|
@ -1141,12 +1141,10 @@ checkArithmeticDeref params t@(TA_Expansion _ [b@(T_DollarBraced id _)]) =
|
||||||
T_Arithmetic {} -> return normalWarning
|
T_Arithmetic {} -> return normalWarning
|
||||||
T_DollarArithmetic {} -> return normalWarning
|
T_DollarArithmetic {} -> return normalWarning
|
||||||
T_ForArithmetic {} -> return normalWarning
|
T_ForArithmetic {} -> return normalWarning
|
||||||
TA_Index {} -> return indexWarning
|
|
||||||
T_SimpleCommand {} -> return noWarning
|
T_SimpleCommand {} -> return noWarning
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
normalWarning = style id 2004 "$/${} is unnecessary on arithmetic variables."
|
normalWarning = style id 2004 "$/${} is unnecessary on arithmetic variables."
|
||||||
indexWarning = style id 2149 "Remove $/${} for numeric index, or escape it for string."
|
|
||||||
noWarning = return ()
|
noWarning = return ()
|
||||||
checkArithmeticDeref _ _ = return ()
|
checkArithmeticDeref _ _ = return ()
|
||||||
|
|
||||||
|
@ -1825,6 +1823,7 @@ prop_checkUnused34= verifyNotTree checkUnusedAssignments "foo=1; (( t = foo ));
|
||||||
prop_checkUnused35= verifyNotTree checkUnusedAssignments "a=foo; b=2; echo ${a:b}"
|
prop_checkUnused35= verifyNotTree checkUnusedAssignments "a=foo; b=2; echo ${a:b}"
|
||||||
prop_checkUnused36= verifyNotTree checkUnusedAssignments "if [[ -v foo ]]; then true; fi"
|
prop_checkUnused36= verifyNotTree checkUnusedAssignments "if [[ -v foo ]]; then true; fi"
|
||||||
prop_checkUnused37= verifyNotTree checkUnusedAssignments "fd=2; exec {fd}>&-"
|
prop_checkUnused37= verifyNotTree checkUnusedAssignments "fd=2; exec {fd}>&-"
|
||||||
|
prop_checkUnused38= verifyTree checkUnusedAssignments "(( a=42 ))"
|
||||||
checkUnusedAssignments params t = execWriter (mapM_ warnFor unused)
|
checkUnusedAssignments params t = execWriter (mapM_ warnFor unused)
|
||||||
where
|
where
|
||||||
flow = variableFlow params
|
flow = variableFlow params
|
||||||
|
@ -1880,6 +1879,7 @@ prop_checkUnassignedReferences30= verifyNotTree checkUnassignedReferences "if [[
|
||||||
prop_checkUnassignedReferences31= verifyNotTree checkUnassignedReferences "X=1; if [[ -v foo[$X+42] ]]; then echo ${foo[$X+42]}; fi"
|
prop_checkUnassignedReferences31= verifyNotTree checkUnassignedReferences "X=1; if [[ -v foo[$X+42] ]]; then echo ${foo[$X+42]}; fi"
|
||||||
prop_checkUnassignedReferences32= verifyNotTree checkUnassignedReferences "if [[ -v \"foo[1]\" ]]; then echo ${foo[@]}; fi"
|
prop_checkUnassignedReferences32= verifyNotTree checkUnassignedReferences "if [[ -v \"foo[1]\" ]]; then echo ${foo[@]}; fi"
|
||||||
prop_checkUnassignedReferences33= verifyNotTree checkUnassignedReferences "f() { local -A foo; echo \"${foo[@]}\"; }"
|
prop_checkUnassignedReferences33= verifyNotTree checkUnassignedReferences "f() { local -A foo; echo \"${foo[@]}\"; }"
|
||||||
|
prop_checkUnassignedReferences34= verifyNotTree checkUnassignedReferences "declare -A foo; (( foo[bar] ))"
|
||||||
checkUnassignedReferences params t = warnings
|
checkUnassignedReferences params t = warnings
|
||||||
where
|
where
|
||||||
(readMap, writeMap) = execState (mapM tally $ variableFlow params) (Map.empty, Map.empty)
|
(readMap, writeMap) = execState (mapM tally $ variableFlow params) (Map.empty, Map.empty)
|
||||||
|
@ -2540,7 +2540,7 @@ checkLoopVariableReassignment params token =
|
||||||
T_ForArithmetic _
|
T_ForArithmetic _
|
||||||
(TA_Sequence _
|
(TA_Sequence _
|
||||||
[TA_Assignment _ "="
|
[TA_Assignment _ "="
|
||||||
(TA_Expansion _ [T_Literal _ var]) _])
|
(TA_Variable _ var _ ) _])
|
||||||
_ _ _ -> return var
|
_ _ _ -> return var
|
||||||
_ -> fail "not loop"
|
_ -> fail "not loop"
|
||||||
|
|
||||||
|
|
|
@ -444,15 +444,12 @@ getModifiedVariables t =
|
||||||
c@T_SimpleCommand {} ->
|
c@T_SimpleCommand {} ->
|
||||||
getModifiedVariableCommand c
|
getModifiedVariableCommand c
|
||||||
|
|
||||||
TA_Unary _ "++|" var -> maybeToList $ do
|
TA_Unary _ "++|" v@(TA_Variable _ name _) ->
|
||||||
name <- getLiteralString var
|
[(t, v, name, DataString $ SourceFrom [v])]
|
||||||
return (t, t, name, DataString $ SourceFrom [t])
|
TA_Unary _ "|++" v@(TA_Variable _ name _) ->
|
||||||
TA_Unary _ "|++" var -> maybeToList $ do
|
[(t, v, name, DataString $ SourceFrom [v])]
|
||||||
name <- getLiteralString var
|
TA_Assignment _ op (TA_Variable _ name _) rhs -> maybeToList $ do
|
||||||
return (t, t, name, DataString $ SourceFrom [t])
|
|
||||||
TA_Assignment _ op lhs rhs -> maybeToList $ do
|
|
||||||
guard $ op `elem` ["=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="]
|
guard $ op `elem` ["=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="]
|
||||||
name <- getLiteralString lhs
|
|
||||||
return (t, t, name, DataString $ SourceFrom [rhs])
|
return (t, t, name, DataString $ SourceFrom [rhs])
|
||||||
|
|
||||||
-- Count [[ -v foo ]] as an "assignment".
|
-- Count [[ -v foo ]] as an "assignment".
|
||||||
|
@ -634,10 +631,10 @@ getReferencedVariables parents t =
|
||||||
map (\x -> (l, l, x)) (
|
map (\x -> (l, l, x)) (
|
||||||
getIndexReferences str
|
getIndexReferences str
|
||||||
++ getOffsetReferences (getBracedModifier str))
|
++ getOffsetReferences (getBracedModifier str))
|
||||||
TA_Expansion id _ ->
|
TA_Variable id name _ ->
|
||||||
if isArithmeticAssignment t
|
if isArithmeticAssignment t
|
||||||
then []
|
then []
|
||||||
else getIfReference t t
|
else [(t, t, name)]
|
||||||
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
|
||||||
|
|
||||||
|
@ -664,7 +661,6 @@ getReferencedVariables parents t =
|
||||||
else []
|
else []
|
||||||
|
|
||||||
literalizer t = case t of
|
literalizer t = case t of
|
||||||
TA_Index {} -> return "" -- x[0] becomes a reference of x
|
|
||||||
T_Glob _ s -> return s -- Also when parsed as globs
|
T_Glob _ s -> return s -- Also when parsed as globs
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
|
|
|
@ -191,11 +191,9 @@ checkBashisms = ForShell [Sh, Dash] $ \t -> do
|
||||||
bashism (T_Glob id str) | "[^" `isInfixOf` str =
|
bashism (T_Glob id str) | "[^" `isInfixOf` str =
|
||||||
warnMsg id "^ in place of ! in glob bracket expressions is"
|
warnMsg id "^ in place of ! in glob bracket expressions is"
|
||||||
|
|
||||||
bashism t@(TA_Expansion id _) | isBashism =
|
bashism t@(TA_Variable id str _) | isBashVariable str =
|
||||||
warnMsg id $ fromJust str ++ " is"
|
warnMsg id $ str ++ " is"
|
||||||
where
|
|
||||||
str = getLiteralString t
|
|
||||||
isBashism = isJust str && isBashVariable (fromJust str)
|
|
||||||
bashism t@(T_DollarBraced id token) = do
|
bashism t@(T_DollarBraced id token) = do
|
||||||
mapM_ check expansion
|
mapM_ check expansion
|
||||||
when (isBashVariable var) $
|
when (isBashVariable var) $
|
||||||
|
|
|
@ -697,31 +697,35 @@ readArithmeticContents =
|
||||||
spacing1
|
spacing1
|
||||||
return (str, alt)
|
return (str, alt)
|
||||||
|
|
||||||
|
|
||||||
readArrayIndex = do
|
readArrayIndex = do
|
||||||
id <- getNextId
|
id <- getNextId
|
||||||
char '['
|
char '['
|
||||||
middle <- readArithmeticContents
|
pos <- getPosition
|
||||||
|
middle <- readStringForParser readArithmeticContents
|
||||||
char ']'
|
char ']'
|
||||||
return $ TA_Index id middle
|
return $ T_UnparsedIndex id pos middle
|
||||||
|
|
||||||
literal s = do
|
literal s = do
|
||||||
id <- getNextId
|
id <- getNextId
|
||||||
string s
|
string s
|
||||||
return $ T_Literal id s
|
return $ T_Literal id s
|
||||||
|
|
||||||
readArithmeticLiteral =
|
readVariable = do
|
||||||
readArrayIndex <|> literal "#"
|
id <- getNextId
|
||||||
|
name <- readVariableName
|
||||||
|
indices <- many readArrayIndex
|
||||||
|
spacing
|
||||||
|
return $ TA_Variable id name indices
|
||||||
|
|
||||||
readExpansion = do
|
readExpansion = do
|
||||||
id <- getNextId
|
id <- getNextId
|
||||||
pieces <- many1 $ choice [
|
pieces <- many1 $ choice [
|
||||||
readArithmeticLiteral,
|
|
||||||
readSingleQuoted,
|
readSingleQuoted,
|
||||||
readDoubleQuoted,
|
readDoubleQuoted,
|
||||||
readNormalDollar,
|
readNormalDollar,
|
||||||
readBraced,
|
readBraced,
|
||||||
readUnquotedBackTicked,
|
readUnquotedBackTicked,
|
||||||
|
literal "#",
|
||||||
readNormalLiteral "+-*/=%^,]?:"
|
readNormalLiteral "+-*/=%^,]?:"
|
||||||
]
|
]
|
||||||
spacing
|
spacing
|
||||||
|
@ -734,7 +738,7 @@ readArithmeticContents =
|
||||||
spacing
|
spacing
|
||||||
return s
|
return s
|
||||||
|
|
||||||
readArithTerm = readGroup <|> readExpansion
|
readArithTerm = readGroup <|> readVariable <|> readExpansion
|
||||||
|
|
||||||
readSequence = do
|
readSequence = do
|
||||||
spacing
|
spacing
|
||||||
|
@ -2819,10 +2823,7 @@ readScriptFile = do
|
||||||
|
|
||||||
readUtf8Bom = called "Byte Order Mark" $ string "\xFEFF"
|
readUtf8Bom = called "Byte Order Mark" $ string "\xFEFF"
|
||||||
|
|
||||||
readScript = do
|
readScript = readScriptFile
|
||||||
script <- readScriptFile
|
|
||||||
reparseIndices script
|
|
||||||
|
|
||||||
|
|
||||||
-- Interactively run a parser in ghci:
|
-- Interactively run a parser in ghci:
|
||||||
-- debugParse readScript "echo 'hello world'"
|
-- debugParse readScript "echo 'hello world'"
|
||||||
|
@ -2945,6 +2946,9 @@ reparseIndices root =
|
||||||
return $ T_Array id2 newWords
|
return $ T_Array id2 newWords
|
||||||
x -> return x
|
x -> return x
|
||||||
return $ T_Assignment id mode name newIndices newValue
|
return $ T_Assignment id mode name newIndices newValue
|
||||||
|
f (TA_Variable id name indices) = do
|
||||||
|
newIndices <- mapM (fixAssignmentIndex name) indices
|
||||||
|
return $ TA_Variable id name newIndices
|
||||||
f t = return t
|
f t = return t
|
||||||
|
|
||||||
fixIndexElement name word =
|
fixIndexElement name word =
|
||||||
|
@ -2952,13 +2956,13 @@ reparseIndices root =
|
||||||
T_IndexedElement id indices value -> do
|
T_IndexedElement id indices value -> do
|
||||||
new <- mapM (fixAssignmentIndex name) indices
|
new <- mapM (fixAssignmentIndex name) indices
|
||||||
return $ T_IndexedElement id new value
|
return $ T_IndexedElement id new value
|
||||||
otherwise -> return word
|
_ -> return word
|
||||||
|
|
||||||
fixAssignmentIndex name word =
|
fixAssignmentIndex name word =
|
||||||
case word of
|
case word of
|
||||||
T_UnparsedIndex id pos src -> do
|
T_UnparsedIndex id pos src ->
|
||||||
parsed name pos src
|
parsed name pos src
|
||||||
otherwise -> return word
|
_ -> return word
|
||||||
|
|
||||||
parsed name pos src =
|
parsed name pos src =
|
||||||
if isAssociative name
|
if isAssociative name
|
||||||
|
|
Loading…
Reference in New Issue