Improve heredoc delimiter handling.

This commit is contained in:
Vidar Holen 2016-12-11 10:09:13 -08:00
parent 46e47dad45
commit 0a381be37b
1 changed files with 9 additions and 17 deletions

View File

@ -1534,40 +1534,32 @@ prop_readHereDoc8 = isOk readScript "cat <<foo>>bar\netc\nfoo"
prop_readHereDoc9 = isOk readScript "if true; then cat << foo; fi\nbar\nfoo\n" prop_readHereDoc9 = isOk readScript "if true; then cat << foo; fi\nbar\nfoo\n"
prop_readHereDoc10= isOk readScript "if true; then cat << foo << bar; fi\nfoo\nbar\n" prop_readHereDoc10= isOk readScript "if true; then cat << foo << bar; fi\nfoo\nbar\n"
prop_readHereDoc11= isOk readScript "cat << foo $(\nfoo\n)lol\nfoo\n" prop_readHereDoc11= isOk readScript "cat << foo $(\nfoo\n)lol\nfoo\n"
prop_readHereDoc12= isOk readScript "cat << foo|cat\nbar\nfoo"
readHereDoc = called "here document" $ do readHereDoc = called "here document" $ do
fid <- getNextId fid <- getNextId
pos <- getPosition pos <- getPosition
try $ string "<<" try $ string "<<"
dashed <- (char '-' >> return Dashed) <|> return Undashed dashed <- (char '-' >> return Dashed) <|> return Undashed
tokenPosition <- getPosition
sp <- spacing sp <- spacing
optional $ do optional $ do
try . lookAhead $ char '(' try . lookAhead $ char '('
let message = "Shells are space sensitive. Use '< <(cmd)', not '<<" ++ sp ++ "(cmd)'." let message = "Shells are space sensitive. Use '< <(cmd)', not '<<" ++ sp ++ "(cmd)'."
parseProblemAt pos ErrorC 1038 message parseProblemAt pos ErrorC 1038 message
hid <- getNextId hid <- getNextId
(quoted, endToken) <- (quoted, endToken) <- readToken
liftM (\ x -> (Quoted, stripLiteral x)) readDoubleQuotedLiteral
<|> liftM (\ x -> (Quoted, x)) readSingleQuotedLiteral
<|> (readToken >>= (\x -> return (Unquoted, x)))
-- add empty tokens for now, read the rest in readPendingHereDocs -- add empty tokens for now, read the rest in readPendingHereDocs
let doc = T_HereDoc hid dashed quoted endToken [] let doc = T_HereDoc hid dashed quoted endToken []
addPendingHereDoc doc addPendingHereDoc doc
return doc return doc
where where
stripLiteral (T_Literal _ x) = x quotes = "\"'\\"
stripLiteral (T_SingleQuoted _ x) = x -- Fun fact: bash considers << foo"" quoted, but not << <("foo").
-- Instead of replicating this, just read a token and strip quotes.
readToken = readToken = do
liftM concat $ many1 (escaped <|> quoted <|> normal) str <- readStringForParser readNormalWord
where return (if any (`elem` quotes) str then Quoted else Unquoted,
quoted = liftM stripLiteral readDoubleQuotedLiteral <|> readSingleQuotedLiteral filter (not . (`elem` quotes)) str)
normal = anyChar `reluctantlyTill1` (whitespace <|> oneOf "<>;&)'\"\\")
escaped = do -- surely the user must be doing something wrong at this point
char '\\'
c <- anyChar
return [c]
readPendingHereDocs = do readPendingHereDocs = do