Parse variables and subexpressions in brace expansions

This commit is contained in:
Vidar Holen 2015-05-10 12:49:50 -07:00
parent 1d26c280d6
commit 6076f0b1da
3 changed files with 44 additions and 14 deletions

View File

@ -53,7 +53,7 @@ data Token =
| T_Backticked Id [Token] | T_Backticked Id [Token]
| T_Bang Id | T_Bang Id
| T_Banged Id Token | T_Banged Id Token
| T_BraceExpansion Id String | T_BraceExpansion Id [Token]
| T_BraceGroup Id [Token] | T_BraceGroup Id [Token]
| T_CLOBBER Id | T_CLOBBER Id
| T_Case Id | T_Case Id
@ -171,6 +171,7 @@ analyze f g i =
delve (T_DoubleQuoted id list) = dl list $ T_DoubleQuoted id delve (T_DoubleQuoted id list) = dl list $ T_DoubleQuoted id
delve (T_DollarDoubleQuoted id list) = dl list $ T_DollarDoubleQuoted id delve (T_DollarDoubleQuoted id list) = dl list $ T_DollarDoubleQuoted id
delve (T_DollarExpansion id list) = dl list $ T_DollarExpansion id delve (T_DollarExpansion id list) = dl list $ T_DollarExpansion id
delve (T_BraceExpansion id list) = dl list $ T_BraceExpansion id
delve (T_Backticked id list) = dl list $ T_Backticked id delve (T_Backticked id list) = dl list $ T_Backticked id
delve (T_DollarArithmetic id c) = d1 c $ T_DollarArithmetic id delve (T_DollarArithmetic id c) = d1 c $ T_DollarArithmetic id
delve (T_DollarBracket id c) = d1 c $ T_DollarBracket id delve (T_DollarBracket id c) = d1 c $ T_DollarBracket id

View File

@ -1280,8 +1280,18 @@ checkConstantNoary _ _ = return ()
prop_checkBraceExpansionVars1 = verify checkBraceExpansionVars "echo {1..$n}" prop_checkBraceExpansionVars1 = verify checkBraceExpansionVars "echo {1..$n}"
prop_checkBraceExpansionVars2 = verifyNot checkBraceExpansionVars "echo {1,3,$n}" prop_checkBraceExpansionVars2 = verifyNot checkBraceExpansionVars "echo {1,3,$n}"
checkBraceExpansionVars _ (T_BraceExpansion id s) | "..$" `isInfixOf` s = checkBraceExpansionVars _ (T_BraceExpansion id list) = mapM_ check list
where
check element =
when ("..$" `isInfixOf` toString element) $
warn id 2051 "Bash doesn't support variables in brace range expansions." warn id 2051 "Bash doesn't support variables in brace range expansions."
literalExt t =
case t of
T_DollarBraced {} -> return "$"
T_DollarExpansion {} -> return "$"
T_DollarArithmetic {} -> return "$"
otherwise -> return "-"
toString t = fromJust $ getLiteralStringExt literalExt t
checkBraceExpansionVars _ _ = return () checkBraceExpansionVars _ _ = return ()
prop_checkForDecimals = verify checkForDecimals "((3.14*c))" prop_checkForDecimals = verify checkForDecimals "((3.14*c))"
@ -2413,6 +2423,7 @@ prop_checkSpacefulness22= verifyNotTree checkSpacefulness "echo $\"$1\""
prop_checkSpacefulness23= verifyNotTree checkSpacefulness "a=(1); echo ${a[@]}" prop_checkSpacefulness23= verifyNotTree checkSpacefulness "a=(1); echo ${a[@]}"
prop_checkSpacefulness24= verifyTree checkSpacefulness "a='a b'; cat <<< $a" prop_checkSpacefulness24= verifyTree checkSpacefulness "a='a b'; cat <<< $a"
prop_checkSpacefulness25= verifyTree checkSpacefulness "a='s/[0-9]//g'; sed $a" prop_checkSpacefulness25= verifyTree checkSpacefulness "a='s/[0-9]//g'; sed $a"
prop_checkSpacefulness26= verifyTree checkSpacefulness "a='foo bar'; echo {1,2,$a}"
checkSpacefulness params t = checkSpacefulness params t =
doVariableFlowAnalysis readF writeF (Map.fromList defaults) (variableFlow params) doVariableFlowAnalysis readF writeF (Map.fromList defaults) (variableFlow params)

View File

@ -237,6 +237,12 @@ attempting rest branch =
orFail parser errorAction = orFail parser errorAction =
try parser <|> (errorAction >>= fail) try parser <|> (errorAction >>= fail)
-- Construct a node with a parser, e.g. T_Literal `withParser` (readGenericLiteral ",")
withParser node parser = do
id <- getNextId
contents <- parser
return $ node id contents
wasIncluded p = option False (p >> return True) wasIncluded p = option False (p >> return True)
acceptButWarn parser level code note = acceptButWarn parser level code note =
@ -1045,16 +1051,29 @@ readGenericEscaped = do
prop_readBraced = isOk readBraced "{1..4}" prop_readBraced = isOk readBraced "{1..4}"
prop_readBraced2 = isOk readBraced "{foo,bar,\"baz lol\"}" prop_readBraced2 = isOk readBraced "{foo,bar,\"baz lol\"}"
readBraced = try $ do prop_readBraced3 = isOk readBraced "{1,\\},2}"
let strip (T_Literal _ s) = return ("\"" ++ s ++ "\"") prop_readBraced4 = isOk readBraced "{1,{2,3}}"
id <- getNextId prop_readBraced5 = isOk readBraced "{JP{,E}G,jp{,e}g}"
prop_readBraced6 = isOk readBraced "{foo,bar,$((${var}))}"
readBraced = try braceExpansion
where
braceExpansion =
T_BraceExpansion `withParser` do
char '{' char '{'
str <- many1 ((readDoubleQuotedLiteral >>= strip) <|> readGenericLiteral1 (oneOf "}\"" <|> whitespace)) elements <- bracedElement `sepBy1` char ','
char '}' char '}'
let result = concat str return elements
unless (',' `elem` result || ".." `isInfixOf` result) $ bracedElement =
fail "Not a brace expression" T_NormalWord `withParser` do
return $ T_BraceExpansion id result many $ choice [
braceExpansion,
readDollarExpression,
readSingleQuoted,
readDoubleQuoted,
braceLiteral
]
braceLiteral =
T_Literal `withParser` readGenericLiteral1 (oneOf "{}\"$'," <|> whitespace)
readNormalDollar = readDollarExpression <|> readDollarDoubleQuote <|> readDollarSingleQuote <|> readDollarLonely readNormalDollar = readDollarExpression <|> readDollarDoubleQuote <|> readDollarSingleQuote <|> readDollarLonely
readDoubleQuotedDollar = readDollarExpression <|> readDollarLonely readDoubleQuotedDollar = readDollarExpression <|> readDollarLonely
@ -1078,7 +1097,6 @@ readDollarDoubleQuote = do
doubleQuote <?> "end of translated double quoted string" doubleQuote <?> "end of translated double quoted string"
return $ T_DollarDoubleQuoted id x return $ T_DollarDoubleQuoted id x
prop_readDollarArithmetic = isOk readDollarArithmetic "$(( 3 * 4 +5))" prop_readDollarArithmetic = isOk readDollarArithmetic "$(( 3 * 4 +5))"
prop_readDollarArithmetic2 = isOk readDollarArithmetic "$(((3*4)+(1*2+(3-1))))" prop_readDollarArithmetic2 = isOk readDollarArithmetic "$(((3*4)+(1*2+(3-1))))"
readDollarArithmetic = called "$((..)) expression" $ do readDollarArithmetic = called "$((..)) expression" $ do