More lenient line feed handling in test expressions.

This commit is contained in:
Vidar Holen 2014-11-08 15:35:06 -08:00
parent 93140e31a0
commit e909c8ac42
1 changed files with 53 additions and 40 deletions

View File

@ -61,7 +61,7 @@ unicodeDoubleQuoteChars = "\x201C\x201D\x2033\x2036"
prop_spacing = isOk spacing " \\\n # Comment" prop_spacing = isOk spacing " \\\n # Comment"
spacing = do spacing = do
x <- many (many1 linewhitespace <|> try (string "\\\n")) x <- many (many1 linewhitespace <|> try (string "\\\n" >> return ""))
optional readComment optional readComment
return $ concat x return $ concat x
@ -270,12 +270,22 @@ readConditionContents single =
parseProblemAt pos WarningC 1009 "Use 'if cmd; then ..' to check exit code, or 'if [[ $(cmd) == .. ]]' to check output.") parseProblemAt pos WarningC 1009 "Use 'if cmd; then ..' to check exit code, or 'if [[ $(cmd) == .. ]]' to check output.")
where where
spacingOrLf = condSpacing True
condSpacing required = do
pos <- getPosition
space <- allspacing
when (required && null space) $
parseProblemAt pos ErrorC 1035 "You are missing a required space here."
when (single && '\n' `elem` space) $
parseProblemAt pos ErrorC 1080 "When breaking lines in [ ], you need \\ before the linefeed."
return space
typ = if single then SingleBracket else DoubleBracket typ = if single then SingleBracket else DoubleBracket
readCondBinaryOp = try $ do readCondBinaryOp = try $ do
optional guardArithmetic optional guardArithmetic
id <- getNextId id <- getNextId
op <- choice (map tryOp ["==", "!=", "<=", ">=", "=~", ">", "<", "=", "\\<=", "\\>=", "\\<", "\\>"]) <|> otherOp op <- choice (map tryOp ["==", "!=", "<=", ">=", "=~", ">", "<", "=", "\\<=", "\\>=", "\\<", "\\>"]) <|> otherOp
hardCondSpacing spacingOrLf
return op return op
where where
tryOp s = try $ do tryOp s = try $ do
@ -308,7 +318,7 @@ readConditionContents single =
readCondUnaryOp = try $ do readCondUnaryOp = try $ do
id <- getNextId id <- getNextId
s <- readOp s <- readOp
hardCondSpacing spacingOrLf
return $ TC_Unary id typ s return $ TC_Unary id typ s
readOp = try $ do readOp = try $ do
@ -337,19 +347,20 @@ readConditionContents single =
readCondAndOp = do readCondAndOp = do
id <- getNextId id <- getNextId
x <- try (string "&&" <|> string "-a") x <- try (readAndOrOp "&&" False <|> readAndOrOp "-a" True)
softCondSpacing
skipLineFeeds
return $ TC_And id typ x return $ TC_And id typ x
readCondOrOp = do readCondOrOp = do
optional guardArithmetic optional guardArithmetic
id <- getNextId id <- getNextId
x <- try (string "||" <|> string "-o") x <- try (readAndOrOp "||" False <|> readAndOrOp "-o" True)
softCondSpacing
skipLineFeeds
return $ TC_Or id typ x return $ TC_Or id typ x
readAndOrOp op requiresSpacing = do
x <- string op
condSpacing requiresSpacing
return x
readCondNoaryOrBinary = do readCondNoaryOrBinary = do
id <- getNextId id <- getNextId
x <- readCondWord `attempting` (do x <- readCondWord `attempting` (do
@ -373,16 +384,21 @@ readConditionContents single =
id <- getNextId id <- getNextId
pos <- getPosition pos <- getPosition
lparen <- try $ string "(" <|> string "\\(" lparen <- try $ string "(" <|> string "\\("
when (single && lparen == "(") $ parseProblemAt pos ErrorC 1028 "In [..] you have to escape (). Use [[..]] instead." when (single && lparen == "(") $
when (not single && lparen == "\\(") $ parseProblemAt pos ErrorC 1029 "In [[..]] you shouldn't escape ()." parseProblemAt pos ErrorC 1028 "In [..] you have to escape (). Use [[..]] instead."
if single then hardCondSpacing else disregard spacing when (not single && lparen == "\\(") $
parseProblemAt pos ErrorC 1029 "In [[..]] you shouldn't escape ()."
condSpacing single
x <- readCondContents x <- readCondContents
cpos <- getPosition cpos <- getPosition
rparen <- string ")" <|> string "\\)" rparen <- string ")" <|> string "\\)"
if single then hardCondSpacing else disregard spacing condSpacing single
when (single && rparen == ")") $ parseProblemAt cpos ErrorC 1030 "In [..] you have to escape (). Use [[..]] instead." when (single && rparen == ")") $
when (not single && rparen == "\\)") $ parseProblemAt cpos ErrorC 1031 "In [[..]] you shouldn't escape ()." parseProblemAt cpos ErrorC 1030 "In [..] you have to escape (). Use [[..]] instead."
when (isEscaped lparen `xor` isEscaped rparen) $ parseProblemAt pos ErrorC 1032 "Did you just escape one half of () but not the other?" when (not single && rparen == "\\)") $
parseProblemAt cpos ErrorC 1031 "In [[..]] you shouldn't escape ()."
when (isEscaped lparen `xor` isEscaped rparen) $
parseProblemAt pos ErrorC 1032 "Did you just escape one half of () but not the other?"
return $ TC_Group id typ x return $ TC_Group id typ x
where where
isEscaped ('\\':_) = True isEscaped ('\\':_) = True
@ -426,21 +442,15 @@ readConditionContents single =
str <- string "|" str <- string "|"
return $ T_Literal id str return $ T_Literal id str
skipLineFeeds = do
pos <- getPosition
spacing <- allspacing
when (single && '\n' `elem` spacing) $
parseProblemAt pos ErrorC 1080 "In [ ] you need \\ before line feeds."
readCondTerm = do readCondTerm = do
term <- readCondNot <|> readCondExpr term <- readCondNot <|> readCondExpr
skipLineFeeds condSpacing False
return term return term
readCondNot = do readCondNot = do
id <- getNextId id <- getNextId
char '!' char '!'
softCondSpacing spacingOrLf
expr <- readCondExpr expr <- readCondExpr
return $ TC_Unary id typ "!" expr return $ TC_Unary id typ "!" expr
@ -452,7 +462,6 @@ readConditionContents single =
readCondContents = readCondOr readCondContents = readCondOr
prop_a1 = isOk readArithmeticContents " n++ + ++c" prop_a1 = isOk readArithmeticContents " n++ + ++c"
prop_a2 = isOk readArithmeticContents "$N*4-(3,2)" prop_a2 = isOk readArithmeticContents "$N*4-(3,2)"
prop_a3 = isOk readArithmeticContents "n|=2<<1" prop_a3 = isOk readArithmeticContents "n|=2<<1"
@ -613,7 +622,9 @@ prop_readCondition6 = isOk readCondition "[[ $c =~ ^[yY]$ ]]"
prop_readCondition7 = isOk readCondition "[[ ${line} =~ ^[[:space:]]*# ]]" prop_readCondition7 = isOk readCondition "[[ ${line} =~ ^[[:space:]]*# ]]"
prop_readCondition8 = isOk readCondition "[[ $l =~ ogg|flac ]]" prop_readCondition8 = isOk readCondition "[[ $l =~ ogg|flac ]]"
prop_readCondition9 = isOk readCondition "[ foo -a -f bar ]" prop_readCondition9 = isOk readCondition "[ foo -a -f bar ]"
prop_readCondition10= isOk readCondition "[[ a == b \n || c == d ]]" prop_readCondition10= isOk readCondition "[[\na == b\n||\nc == d ]]"
prop_readCondition10a= isOk readCondition "[[\na == b ||\nc == d ]]"
prop_readCondition10b= isOk readCondition "[[ a == b\n||\nc == d ]]"
prop_readCondition11= isOk readCondition "[[ a == b ||\n c == d ]]" prop_readCondition11= isOk readCondition "[[ a == b ||\n c == d ]]"
prop_readCondition12= isWarning readCondition "[ a == b \n -o c == d ]" prop_readCondition12= isWarning readCondition "[ a == b \n -o c == d ]"
prop_readCondition13= isOk readCondition "[[ foo =~ ^fo{1,3}$ ]]" prop_readCondition13= isOk readCondition "[[ foo =~ ^fo{1,3}$ ]]"
@ -622,9 +633,17 @@ readCondition = called "test expression" $ do
id <- getNextId id <- getNextId
open <- try (string "[[") <|> string "[" open <- try (string "[[") <|> string "["
let single = open == "[" let single = open == "["
condSpacingMsg False $ if single
then "You need spaces after the opening [ and before the closing ]." pos <- getPosition
else "You need spaces after the opening [[ and before the closing ]]." space <- allspacing
when (null space) $
parseProblemAt pos ErrorC 1035 $ "You need a space after the " ++
if single
then "[ and before the ]."
else "[[ and before the ]]."
when (single && '\n' `elem` space) $
parseProblemAt pos ErrorC 1080 "You need \\ before line feeds to break lines in [ ]."
condition <- readConditionContents single condition <- readConditionContents single
cpos <- getPosition cpos <- getPosition
@ -635,14 +654,6 @@ readCondition = called "test expression" $ do
many readCmdWord -- Read and throw away remainders to get then/do warnings. Fixme? many readCmdWord -- Read and throw away remainders to get then/do warnings. Fixme?
return $ T_Condition id (if single then SingleBracket else DoubleBracket) condition return $ T_Condition id (if single then SingleBracket else DoubleBracket) condition
hardCondSpacing = condSpacingMsg False "You need a space here."
softCondSpacing = condSpacingMsg True "You need a space here."
condSpacingMsg soft msg = do
pos <- getPosition
space <- spacing
when (null space) $ (if soft then parseNoteAt else parseProblemAt) pos ErrorC 1035 msg
readAnnotationPrefix = do readAnnotationPrefix = do
char '#' char '#'
many linewhitespace many linewhitespace
@ -1954,10 +1965,12 @@ g_Rparen = tryToken ")" T_Rparen
g_Bang = do g_Bang = do
id <- getNextId id <- getNextId
char '!' char '!'
softCondSpacing void spacing1 <|> do
pos <- getPosition
parseProblemAt pos ErrorC 1035
"You are missing a required space after the !."
return $ T_Bang id return $ T_Bang id
g_Semi = do g_Semi = do
notFollowedBy2 g_DSEMI notFollowedBy2 g_DSEMI
tryToken ";" T_Semi tryToken ";" T_Semi