commit
32a53f21b5
|
@ -37,9 +37,9 @@ import Control.Monad
|
||||||
|
|
||||||
import Test.QuickCheck.All
|
import Test.QuickCheck.All
|
||||||
|
|
||||||
tokenToPosition map (TokenComment id c) = fromMaybe fail $ do
|
tokenToPosition startMap (TokenComment id c) = fromMaybe fail $ do
|
||||||
position <- Map.lookup id map
|
span <- Map.lookup id startMap
|
||||||
return $ PositionedComment position position c
|
return $ PositionedComment (fst span) (snd span) c
|
||||||
where
|
where
|
||||||
fail = error "Internal shellcheck error: id doesn't exist. Please report!"
|
fail = error "Internal shellcheck error: id doesn't exist. Please report!"
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ data ParseSpec = ParseSpec {
|
||||||
|
|
||||||
data ParseResult = ParseResult {
|
data ParseResult = ParseResult {
|
||||||
prComments :: [PositionedComment],
|
prComments :: [PositionedComment],
|
||||||
prTokenPositions :: Map.Map Id Position,
|
prTokenPositions :: Map.Map Id (Position, Position),
|
||||||
prRoot :: Maybe Token
|
prRoot :: Maybe Token
|
||||||
} deriving (Show, Eq)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ data HereDocContext =
|
||||||
|
|
||||||
data UserState = UserState {
|
data UserState = UserState {
|
||||||
lastId :: Id,
|
lastId :: Id,
|
||||||
positionMap :: Map.Map Id SourcePos,
|
positionMap :: Map.Map Id (SourcePos, SourcePos),
|
||||||
parseNotes :: [ParseNote],
|
parseNotes :: [ParseNote],
|
||||||
hereDocMap :: Map.Map Id [Token],
|
hereDocMap :: Map.Map Id [Token],
|
||||||
pendingHereDocs :: [HereDocContext]
|
pendingHereDocs :: [HereDocContext]
|
||||||
|
@ -175,7 +175,7 @@ getLastId = lastId <$> getState
|
||||||
getNextIdAt sourcepos = do
|
getNextIdAt sourcepos = do
|
||||||
state <- getState
|
state <- getState
|
||||||
let newId = incId (lastId state)
|
let newId = incId (lastId state)
|
||||||
let newMap = Map.insert newId sourcepos (positionMap state)
|
let newMap = Map.insert newId (sourcepos, sourcepos) (positionMap state)
|
||||||
putState $ state {
|
putState $ state {
|
||||||
lastId = newId,
|
lastId = newId,
|
||||||
positionMap = newMap
|
positionMap = newMap
|
||||||
|
@ -185,8 +185,25 @@ getNextIdAt sourcepos = do
|
||||||
|
|
||||||
getNextId :: Monad m => SCParser m Id
|
getNextId :: Monad m => SCParser m Id
|
||||||
getNextId = do
|
getNextId = do
|
||||||
pos <- getPosition
|
start <- startSpan
|
||||||
getNextIdAt pos
|
id <- endSpan start
|
||||||
|
return id
|
||||||
|
|
||||||
|
data IncompleteInterval = IncompleteInterval SourcePos
|
||||||
|
|
||||||
|
startSpan = IncompleteInterval <$> getPosition
|
||||||
|
|
||||||
|
endSpan (IncompleteInterval start) = do
|
||||||
|
id <- getNextIdAt start
|
||||||
|
endPos <- getPosition
|
||||||
|
state <- getState
|
||||||
|
let setEndPos (start, _) = Just (start, endPos)
|
||||||
|
let newMap = Map.update setEndPos id (positionMap state)
|
||||||
|
putState $ state {
|
||||||
|
lastId = id,
|
||||||
|
positionMap = newMap
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
|
||||||
addToHereDocMap id list = do
|
addToHereDocMap id list = do
|
||||||
state <- getState
|
state <- getState
|
||||||
|
@ -318,9 +335,9 @@ parseProblemAt pos = parseProblemAtWithEnd pos pos
|
||||||
parseProblemAtId :: Monad m => Id -> Severity -> Integer -> String -> SCParser m ()
|
parseProblemAtId :: Monad m => Id -> Severity -> Integer -> String -> SCParser m ()
|
||||||
parseProblemAtId id level code msg = do
|
parseProblemAtId id level code msg = do
|
||||||
map <- getMap
|
map <- getMap
|
||||||
let pos = Map.findWithDefault
|
let (start, end) = Map.findWithDefault
|
||||||
(error "Internal error (no position for id). Please report.") id map
|
(error "Internal error (no position for id). Please report.") id map
|
||||||
parseProblemAt pos level code msg
|
parseProblemAtWithEnd start end level code msg
|
||||||
|
|
||||||
-- Store non-parse problems inside
|
-- Store non-parse problems inside
|
||||||
|
|
||||||
|
@ -1069,7 +1086,7 @@ prop_readSingleQuoted6 = isOk readSimpleCommand "foo='bar cow 'arg"
|
||||||
prop_readSingleQuoted7 = isOk readSingleQuoted "'foo\x201C\&bar'"
|
prop_readSingleQuoted7 = isOk readSingleQuoted "'foo\x201C\&bar'"
|
||||||
prop_readSingleQuoted8 = isWarning readSingleQuoted "'foo\x2018\&bar'"
|
prop_readSingleQuoted8 = isWarning readSingleQuoted "'foo\x2018\&bar'"
|
||||||
readSingleQuoted = called "single quoted string" $ do
|
readSingleQuoted = called "single quoted string" $ do
|
||||||
id <- getNextId
|
start <- startSpan
|
||||||
startPos <- getPosition
|
startPos <- getPosition
|
||||||
singleQuote
|
singleQuote
|
||||||
s <- many readSingleQuotedPart
|
s <- many readSingleQuotedPart
|
||||||
|
@ -1087,6 +1104,7 @@ readSingleQuoted = called "single quoted string" $ do
|
||||||
when ('\n' `elem` string && not ("\n" `isPrefixOf` string)) $
|
when ('\n' `elem` string && not ("\n" `isPrefixOf` string)) $
|
||||||
suggestForgotClosingQuote startPos endPos "single quoted string"
|
suggestForgotClosingQuote startPos endPos "single quoted string"
|
||||||
|
|
||||||
|
id <- endSpan start
|
||||||
return (T_SingleQuoted id string)
|
return (T_SingleQuoted id string)
|
||||||
|
|
||||||
readSingleQuotedLiteral = do
|
readSingleQuotedLiteral = do
|
||||||
|
@ -1522,10 +1540,11 @@ prop_readDollarBraced2 = isOk readDollarBraced "${foo/'{cow}'}"
|
||||||
prop_readDollarBraced3 = isOk readDollarBraced "${foo%%$(echo cow\\})}"
|
prop_readDollarBraced3 = isOk readDollarBraced "${foo%%$(echo cow\\})}"
|
||||||
prop_readDollarBraced4 = isOk readDollarBraced "${foo#\\}}"
|
prop_readDollarBraced4 = isOk readDollarBraced "${foo#\\}}"
|
||||||
readDollarBraced = called "parameter expansion" $ do
|
readDollarBraced = called "parameter expansion" $ do
|
||||||
id <- getNextId
|
start <- startSpan
|
||||||
try (string "${")
|
try (string "${")
|
||||||
word <- readDollarBracedWord
|
word <- readDollarBracedWord
|
||||||
char '}'
|
char '}'
|
||||||
|
id <- endSpan start
|
||||||
return $ T_DollarBraced id word
|
return $ T_DollarBraced id word
|
||||||
|
|
||||||
prop_readDollarExpansion1= isOk readDollarExpansion "$(echo foo; ls\n)"
|
prop_readDollarExpansion1= isOk readDollarExpansion "$(echo foo; ls\n)"
|
||||||
|
@ -1544,14 +1563,16 @@ prop_readDollarVariable3 = isWarning (readDollarVariable >> anyChar) "$10"
|
||||||
prop_readDollarVariable4 = isWarning (readDollarVariable >> string "[@]") "$arr[@]"
|
prop_readDollarVariable4 = isWarning (readDollarVariable >> string "[@]") "$arr[@]"
|
||||||
prop_readDollarVariable5 = isWarning (readDollarVariable >> string "[f") "$arr[f"
|
prop_readDollarVariable5 = isWarning (readDollarVariable >> string "[f") "$arr[f"
|
||||||
|
|
||||||
|
readDollarVariable :: Monad m => SCParser m Token
|
||||||
readDollarVariable = do
|
readDollarVariable = do
|
||||||
id <- getNextId
|
start <- startSpan
|
||||||
pos <- getPosition
|
pos <- getPosition
|
||||||
|
|
||||||
let singleCharred p = do
|
let singleCharred p = do
|
||||||
n <- p
|
n <- p
|
||||||
value <- wrap [n]
|
value <- wrap [n]
|
||||||
return (T_DollarBraced id value)
|
id <- endSpan start
|
||||||
|
return $ (T_DollarBraced id value)
|
||||||
|
|
||||||
let positional = do
|
let positional = do
|
||||||
value <- singleCharred digit
|
value <- singleCharred digit
|
||||||
|
@ -1564,6 +1585,7 @@ readDollarVariable = do
|
||||||
let regular = do
|
let regular = do
|
||||||
name <- readVariableName
|
name <- readVariableName
|
||||||
value <- wrap name
|
value <- wrap name
|
||||||
|
id <- endSpan start
|
||||||
return (T_DollarBraced id value) `attempting` do
|
return (T_DollarBraced id value) `attempting` do
|
||||||
lookAhead $ char '['
|
lookAhead $ char '['
|
||||||
parseNoteAt pos ErrorC 1087 "Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet)."
|
parseNoteAt pos ErrorC 1087 "Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet)."
|
||||||
|
@ -1644,7 +1666,7 @@ readPendingHereDocs = do
|
||||||
swapContext ctx $
|
swapContext ctx $
|
||||||
do
|
do
|
||||||
docPos <- getPosition
|
docPos <- getPosition
|
||||||
tokenPos <- Map.findWithDefault (error "Missing ID") id <$> getMap
|
(tokenPos, _) <- Map.findWithDefault (error "Missing ID") id <$> getMap
|
||||||
(terminated, wasWarned, lines) <- readDocLines dashed endToken
|
(terminated, wasWarned, lines) <- readDocLines dashed endToken
|
||||||
let hereData = unlines lines
|
let hereData = unlines lines
|
||||||
unless terminated $ do
|
unless terminated $ do
|
||||||
|
@ -2910,11 +2932,15 @@ debugParseScript string =
|
||||||
result {
|
result {
|
||||||
-- Remove the noisiest parts
|
-- Remove the noisiest parts
|
||||||
prTokenPositions = Map.fromList [
|
prTokenPositions = Map.fromList [
|
||||||
(Id 0, Position {
|
(Id 0, (Position {
|
||||||
posFile = "removed for clarity",
|
posFile = "removed for clarity",
|
||||||
posLine = -1,
|
posLine = -1,
|
||||||
posColumn = -1
|
posColumn = -1
|
||||||
})]
|
}, Position {
|
||||||
|
posFile = "removed for clarity",
|
||||||
|
posLine = -1,
|
||||||
|
posColumn = -1
|
||||||
|
}))]
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
result = runIdentity $
|
result = runIdentity $
|
||||||
|
@ -3001,7 +3027,7 @@ parseShell env name contents = do
|
||||||
Right (script, userstate) ->
|
Right (script, userstate) ->
|
||||||
return ParseResult {
|
return ParseResult {
|
||||||
prComments = map toPositionedComment $ nub $ parseNotes userstate ++ parseProblems state,
|
prComments = map toPositionedComment $ nub $ parseNotes userstate ++ parseProblems state,
|
||||||
prTokenPositions = Map.map posToPos (positionMap userstate),
|
prTokenPositions = Map.map startEndPosToPos (positionMap userstate),
|
||||||
prRoot = Just $
|
prRoot = Just $
|
||||||
reattachHereDocs script (hereDocMap userstate)
|
reattachHereDocs script (hereDocMap userstate)
|
||||||
}
|
}
|
||||||
|
@ -3082,6 +3108,9 @@ posToPos sp = Position {
|
||||||
posColumn = fromIntegral $ sourceColumn sp
|
posColumn = fromIntegral $ sourceColumn sp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startEndPosToPos :: (SourcePos, SourcePos) -> (Position, Position)
|
||||||
|
startEndPosToPos (s, e) = (posToPos s, posToPos e)
|
||||||
|
|
||||||
-- TODO: Clean up crusty old code that this is layered on top of
|
-- TODO: Clean up crusty old code that this is layered on top of
|
||||||
parseScript :: Monad m =>
|
parseScript :: Monad m =>
|
||||||
SystemInterface m -> ParseSpec -> m ParseResult
|
SystemInterface m -> ParseSpec -> m ParseResult
|
||||||
|
|
Loading…
Reference in New Issue