diff --git a/Shpell/Analytics.hs b/Shpell/Analytics.hs index 577937a..4f22d30 100644 --- a/Shpell/Analytics.hs +++ b/Shpell/Analytics.hs @@ -24,7 +24,7 @@ basicChecks = [ ,checkUnquotedExpansions ,checkRedirectToSame ,checkShorthandIf - ,checkForInDollarStar + ,checkDollarStar ,checkUnquotedDollarAt ,checkStderrRedirect ] @@ -34,7 +34,6 @@ addNoteFor id note = modifyMap $ Map.adjust (\(Metadata pos notes) -> Metadata p willSplit x = case x of - T_DollarVariable _ _ -> True T_DollarBraced _ _ -> True T_DollarExpansion _ _ -> True T_BraceExpansion _ s -> True @@ -53,7 +52,6 @@ simplify = doTransform makeSimple deadSimple (T_NormalWord _ l) = [concat (concatMap (deadSimple) l)] deadSimple (T_DoubleQuoted _ l) = ["\"" ++(concat (concatMap (deadSimple) l)) ++ "\""] deadSimple (T_SingleQuoted _ s) = [s] -deadSimple (T_DollarVariable _ _) = ["${VAR}"] deadSimple (T_DollarBraced _ _) = ["${VAR}"] deadSimple (T_DollarArithmetic _ _) = ["${VAR}"] deadSimple (T_DollarExpansion _ _) = ["${VAR}"] @@ -82,7 +80,7 @@ checkUuoc (T_Pipeline _ (T_Redirecting _ _ f@(T_SimpleCommand id _ _):_:_)) = checkUuoc _ = return () -isMagicInQuotes (T_DollarVariable _ "@") = True +isMagicInQuotes (T_DollarBraced _ s) | '@' `elem` s = True isMagicInQuotes _ = False prop_checkForInQuoted = verify checkForInQuoted "for f in \"$(ls)\"; do echo foo; done" @@ -109,7 +107,6 @@ checkMissingForQuotes (T_ForIn _ f words cmds) = where markUnquoted f (T_NormalWord _ l) = mapM_ mu l markUnquoted _ _ = return () - mu (T_DollarVariable id s) | s == f = warning id mu (T_DollarBraced id s) | s == f = warning id mu _ = return () warning id = addNoteFor id $ Note WarningC $ "Variables that could contain spaces should be quoted" @@ -150,15 +147,15 @@ checkShorthandIf (T_AndIf id _ (T_OrIf _ _ _)) = checkShorthandIf _ = return () -prop_checkForInDollarStar = verify checkForInDollarStar "for f in $*; do ..; done" -checkForInDollarStar (T_ForIn _ var [T_NormalWord _ [(T_DollarVariable id "*")]] _) = - addNoteFor id $ Note WarningC $ "Use 'for " ++ var ++ " in \"$@\"; ..' if you want to loop over arguments." -checkForInDollarStar _ = return () +prop_checkDollarStar = verify checkDollarStar "for f in $*; do ..; done" +checkDollarStar (T_NormalWord _ [(T_DollarBraced id "*")]) = + addNoteFor id $ Note WarningC $ "Use \"$@\" (with quotes) to prevent whitespace problems" +checkDollarStar _ = return () prop_checkUnquotedDollarAt = verify checkUnquotedDollarAt "ls $@" prop_checkUnquotedDollarAt2 = verifyNot checkUnquotedDollarAt "ls \"$@\"" -checkUnquotedDollarAt (T_NormalWord _ [T_DollarVariable id "@"]) = +checkUnquotedDollarAt (T_NormalWord _ [T_DollarBraced id "@"]) = addNoteFor id $ Note ErrorC $ "Add double quotes around $@, otherwise it's just like $* and breaks on spaces" checkUnquotedDollarAt _ = return () @@ -236,12 +233,12 @@ exportParamToLiteral (T_NormalWord _ ((T_Literal id s):_)) = where prefix = takeWhile (/= '=') s exportParamToLiteral _ = [] -getBracedReference s = s -- TODO +-- TODO: +getBracedReference s = takeWhile (\x -> not $ x `elem` ":[#%/^,") $ dropWhile (== '#') s getReferencedVariables t = case t of T_DollarBraced id str -> map (\x -> (id, x)) $ [getBracedReference str] - T_DollarVariable id str -> [(id, str)] T_Arithmetic _ _ -> [] -- TODO _ -> [] diff --git a/Shpell/Parser.hs b/Shpell/Parser.hs index 76ddbaa..83b0c89 100644 --- a/Shpell/Parser.hs +++ b/Shpell/Parser.hs @@ -146,7 +146,7 @@ acceptButWarn parser level note = do ) -- Horrifying AST -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 String | T_DollarVariable Id String | T_DollarArithmetic Id String | 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 String | T_Script 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_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 String | T_DollarArithmetic Id String | 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 String | T_Script Id [Token] deriving (Show) analyzeScopes f g i = mapM (analyze f g i) @@ -518,7 +518,7 @@ readDollarVariable = do id <- getNextId let singleCharred p = do n <- p - return (T_DollarVariable id [n]) `attempting` do + return (T_DollarBraced id [n]) `attempting` do pos <- getPosition num <- lookAhead $ many1 p parseNoteAt pos ErrorC $ "$" ++ (n:num) ++ " is equivalent to ${" ++ [n] ++ "}"++ num @@ -528,7 +528,7 @@ readDollarVariable = do let regular = do name <- readVariableName - return $ T_DollarVariable id (name) + return $ T_DollarBraced id (name) try $ char '$' >> (positional <|> special <|> regular)