AST.hs 12.8 KB
Newer Older
V
Vidar Holen 已提交
1
{-
2 3
    Copyright 2012-2015 Vidar Holen

V
Vidar Holen 已提交
4 5 6 7
    This file is part of ShellCheck.
    http://www.vidarholen.net/contents/shellcheck

    ShellCheck is free software: you can redistribute it and/or modify
V
Vidar Holen 已提交
8
    it under the terms of the GNU General Public License as published by
V
Vidar Holen 已提交
9 10 11 12 13 14
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ShellCheck is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
V
Vidar Holen 已提交
15
    GNU General Public License for more details.
V
Vidar Holen 已提交
16

V
Vidar Holen 已提交
17
    You should have received a copy of the GNU General Public License
V
Vidar Holen 已提交
18 19
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-}
V
Vidar Holen 已提交
20 21 22 23
module ShellCheck.AST where

import Control.Monad
import Control.Monad.Identity
24
import qualified ShellCheck.Regex as Re
V
Vidar Holen 已提交
25 26 27

data Id = Id Int deriving (Show, Eq, Ord)

28 29
data Quoted = Quoted | Unquoted deriving (Show, Eq)
data Dashed = Dashed | Undashed deriving (Show, Eq)
30
data AssignmentMode = Assign | Append deriving (Show, Eq)
31 32
data FunctionKeyword = FunctionKeyword Bool deriving (Show, Eq)
data FunctionParentheses = FunctionParentheses Bool deriving (Show, Eq)
33
data CaseType = CaseBreak | CaseFallThrough | CaseContinue deriving (Show, Eq)
34

V
Vidar Holen 已提交
35
data Token =
36
    TA_Binary Id String Token Token
37
    | TA_Assignment Id String Token Token
38
    | TA_Expansion Id [Token]
39
    | TA_Index Id Token
V
Vidar Holen 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52
    | TA_Sequence Id [Token]
    | TA_Trinary Id Token Token Token
    | TA_Unary Id String Token
    | TC_And Id ConditionType String Token Token
    | TC_Binary Id ConditionType String Token Token
    | TC_Group Id ConditionType Token
    | TC_Noary Id ConditionType Token
    | TC_Or Id ConditionType String Token Token
    | TC_Unary Id ConditionType String Token
    | T_AND_IF Id
    | T_AndIf Id (Token) (Token)
    | T_Arithmetic Id Token
    | T_Array Id [Token]
53
    | T_IndexedElement Id Token Token
54
    | T_Assignment Id AssignmentMode String (Maybe Token) Token
V
Vidar Holen 已提交
55 56 57 58
    | T_Backgrounded Id Token
    | T_Backticked Id [Token]
    | T_Bang Id
    | T_Banged Id Token
59
    | T_BraceExpansion Id [Token]
V
Vidar Holen 已提交
60 61 62
    | T_BraceGroup Id [Token]
    | T_CLOBBER Id
    | T_Case Id
63
    | T_CaseExpression Id Token [(CaseType, [Token], [Token])]
V
Vidar Holen 已提交
64 65 66 67 68 69 70 71
    | T_Condition Id ConditionType Token
    | T_DGREAT Id
    | T_DLESS Id
    | T_DLESSDASH Id
    | T_DSEMI Id
    | T_Do Id
    | T_DollarArithmetic Id Token
    | T_DollarBraced Id Token
72
    | T_DollarBracket Id Token
V
Vidar Holen 已提交
73 74 75
    | T_DollarDoubleQuoted Id [Token]
    | T_DollarExpansion Id [Token]
    | T_DollarSingleQuoted Id String
V
Vidar Holen 已提交
76
    | T_DollarBraceCommandExpansion Id [Token]
V
Vidar Holen 已提交
77 78 79 80 81 82 83 84 85 86 87
    | T_Done Id
    | T_DoubleQuoted Id [Token]
    | T_EOF Id
    | T_Elif Id
    | T_Else Id
    | T_Esac Id
    | T_Extglob Id String [Token]
    | T_FdRedirect Id String Token
    | T_Fi Id
    | T_For Id
    | T_ForArithmetic Id Token Token Token [Token]
V
Vidar Holen 已提交
88
    | T_ForIn Id String [Token] [Token]
89
    | T_Function Id FunctionKeyword FunctionParentheses String Token
V
Vidar Holen 已提交
90 91 92
    | T_GREATAND Id
    | T_Glob Id String
    | T_Greater Id
93
    | T_HereDoc Id Dashed Quoted String [Token]
V
Vidar Holen 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    | T_HereString Id Token
    | T_If Id
    | T_IfExpression Id [([Token],[Token])] [Token]
    | T_In  Id
    | T_IoFile Id Token Token
    | T_LESSAND Id
    | T_LESSGREAT Id
    | T_Lbrace Id
    | T_Less Id
    | T_Literal Id String
    | T_Lparen Id
    | T_NEWLINE Id
    | T_NormalWord Id [Token]
    | T_OR_IF Id
    | T_OrIf Id (Token) (Token)
V
Vidar Holen 已提交
109
    | T_Pipeline Id [Token] [Token] -- [Pipe separators] [Commands]
V
Vidar Holen 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    | T_ProcSub Id String [Token]
    | T_Rbrace Id
    | T_Redirecting Id [Token] Token
    | T_Rparen Id
    | T_Script Id String [Token]
    | T_Select Id
    | T_SelectIn Id String [Token] [Token]
    | T_Semi Id
    | T_SimpleCommand Id [Token] [Token]
    | T_SingleQuoted Id String
    | T_Subshell Id [Token]
    | T_Then Id
    | T_Until Id
    | T_UntilExpression Id [Token] [Token]
    | T_While Id
    | T_WhileExpression Id [Token] [Token]
126
    | T_Annotation Id [Annotation] Token
V
Vidar Holen 已提交
127
    | T_Pipe Id String
V
Vidar Holen 已提交
128
    | T_CoProc Id (Maybe String) Token
129
    | T_CoProcBody Id Token
130
    | T_Include Id Token Token -- . & source: SimpleCommand T_Script
V
Vidar Holen 已提交
131
    | T_BatsTest Id Token Token
V
Vidar Holen 已提交
132 133
    deriving (Show)

134 135 136 137 138
data Annotation =
    DisableComment Integer
    | SourceOverride String
    | ShellOverride String
    deriving (Show, Eq)
V
Vidar Holen 已提交
139 140
data ConditionType = DoubleBracket | SingleBracket deriving (Show, Eq)

141 142 143 144
-- This is an abomination.
tokenEquals :: Token -> Token -> Bool
tokenEquals a b = kludge a == kludge b
    where kludge s = Re.subRegex (Re.mkRegex "\\(Id [0-9]+\\)") (show s) "(Id 0)"
145

146 147
instance Eq Token where
    (==) = tokenEquals
V
Vidar Holen 已提交
148 149

analyze :: Monad m => (Token -> m ()) -> (Token -> m ()) -> (Token -> Token) -> Token -> m Token
V
Vidar Holen 已提交
150 151
analyze f g i =
    round
V
Vidar Holen 已提交
152 153 154 155 156 157 158 159
  where
    round t = do
        f t
        newT <- delve t
        g t
        return . i $ newT
    roundAll = mapM round

160 161 162 163 164
    roundMaybe Nothing = return Nothing
    roundMaybe (Just v) = do
        s <- round v
        return (Just s)

V
Vidar Holen 已提交
165 166 167 168 169 170
    dl l v = do
        x <- roundAll l
        return $ v x
    dll l m v = do
        x <- roundAll l
        y <- roundAll m
V
Vidar Holen 已提交
171
        return $ v x y
V
Vidar Holen 已提交
172 173 174 175 176 177 178 179 180 181
    d1 t v = do
        x <- round t
        return $ v x
    d2 t1 t2 v = do
        x <- round t1
        y <- round t2
        return $ v x y

    delve (T_NormalWord id list) = dl list $ T_NormalWord id
    delve (T_DoubleQuoted id list) = dl list $ T_DoubleQuoted id
182
    delve (T_DollarDoubleQuoted id list) = dl list $ T_DollarDoubleQuoted id
V
Vidar Holen 已提交
183
    delve (T_DollarExpansion id list) = dl list $ T_DollarExpansion id
V
Vidar Holen 已提交
184
    delve (T_DollarBraceCommandExpansion id list) = dl list $ T_DollarBraceCommandExpansion id
185
    delve (T_BraceExpansion id list) = dl list $ T_BraceExpansion id
186
    delve (T_Backticked id list) = dl list $ T_Backticked id
V
Vidar Holen 已提交
187
    delve (T_DollarArithmetic id c) = d1 c $ T_DollarArithmetic id
188
    delve (T_DollarBracket id c) = d1 c $ T_DollarBracket id
V
Vidar Holen 已提交
189 190 191
    delve (T_IoFile id op file) = d2 op file $ T_IoFile id
    delve (T_HereString id word) = d1 word $ T_HereString id
    delve (T_FdRedirect id v t) = d1 t $ T_FdRedirect id v
192 193 194 195
    delve (T_Assignment id mode var index value) = do
        a <- roundMaybe index
        b <- round value
        return $ T_Assignment id mode var a b
V
Vidar Holen 已提交
196
    delve (T_Array id t) = dl t $ T_Array id
197
    delve (T_IndexedElement id t1 t2) = d2 t1 t2 $ T_IndexedElement id
V
Vidar Holen 已提交
198 199 200 201 202
    delve (T_Redirecting id redirs cmd) = do
        a <- roundAll redirs
        b <- round cmd
        return $ T_Redirecting id a b
    delve (T_SimpleCommand id vars cmds) = dll vars cmds $ T_SimpleCommand id
V
Vidar Holen 已提交
203
    delve (T_Pipeline id l1 l2) = dll l1 l2 $ T_Pipeline id
V
Vidar Holen 已提交
204 205 206 207 208
    delve (T_Banged id l) = d1 l $ T_Banged id
    delve (T_AndIf id t u) = d2 t u $ T_AndIf id
    delve (T_OrIf id t u) = d2 t u $ T_OrIf id
    delve (T_Backgrounded id l) = d1 l $ T_Backgrounded id
    delve (T_Subshell id l) = dl l $ T_Subshell id
209
    delve (T_ProcSub id typ l) = dl l $ T_ProcSub id typ
V
Vidar Holen 已提交
210 211 212 213 214 215 216 217 218 219 220 221
    delve (T_Arithmetic id c) = d1 c $ T_Arithmetic id
    delve (T_IfExpression id conditions elses) = do
        newConds <- mapM (\(c, t) -> do
                            x <- mapM round c
                            y <- mapM round t
                            return (x,y)
                    ) conditions
        newElses <- roundAll elses
        return $ T_IfExpression id newConds newElses
    delve (T_BraceGroup id l) = dl l $ T_BraceGroup id
    delve (T_WhileExpression id c l) = dll c l $ T_WhileExpression id
    delve (T_UntilExpression id c l) = dll c l $ T_UntilExpression id
V
Vidar Holen 已提交
222
    delve (T_ForIn id v w l) = dll w l $ T_ForIn id v
223
    delve (T_SelectIn id v w l) = dll w l $ T_SelectIn id v
V
Vidar Holen 已提交
224 225
    delve (T_CaseExpression id word cases) = do
        newWord <- round word
226
        newCases <- mapM (\(o, c, t) -> do
V
Vidar Holen 已提交
227 228
                            x <- mapM round c
                            y <- mapM round t
229
                            return (o, x,y)
V
Vidar Holen 已提交
230 231 232
                        ) cases
        return $ T_CaseExpression id newWord newCases

V
Vidar Holen 已提交
233 234 235 236 237 238 239
    delve (T_ForArithmetic id a b c group) = do
        x <- round a
        y <- round b
        z <- round c
        list <- mapM round group
        return $ T_ForArithmetic id x y z list

V
Vidar Holen 已提交
240
    delve (T_Script id s l) = dl l $ T_Script id s
241
    delve (T_Function id a b name body) = d1 body $ T_Function id a b name
V
Vidar Holen 已提交
242
    delve (T_Condition id typ token) = d1 token $ T_Condition id typ
V
Vidar Holen 已提交
243
    delve (T_Extglob id str l) = dl l $ T_Extglob id str
V
Vidar Holen 已提交
244
    delve (T_DollarBraced id op) = d1 op $ T_DollarBraced id
245
    delve (T_HereDoc id d q str l) = dl l $ T_HereDoc id d q str
V
Vidar Holen 已提交
246

V
Vidar Holen 已提交
247 248 249 250 251 252 253 254
    delve (TC_And id typ str t1 t2) = d2 t1 t2 $ TC_And id typ str
    delve (TC_Or id typ str t1 t2) = d2 t1 t2 $ TC_Or id typ str
    delve (TC_Group id typ token) = d1 token $ TC_Group id typ
    delve (TC_Binary id typ op lhs rhs) = d2 lhs rhs $ TC_Binary id typ op
    delve (TC_Unary id typ op token) = d1 token $ TC_Unary id typ op
    delve (TC_Noary id typ token) = d1 token $ TC_Noary id typ

    delve (TA_Binary id op t1 t2) = d2 t1 t2 $ TA_Binary id op
255
    delve (TA_Assignment id op t1 t2) = d2 t1 t2 $ TA_Assignment id op
V
Vidar Holen 已提交
256 257 258 259 260 261 262
    delve (TA_Unary id op t1) = d1 t1 $ TA_Unary id op
    delve (TA_Sequence id l) = dl l $ TA_Sequence id
    delve (TA_Trinary id t1 t2 t3) = do
        a <- round t1
        b <- round t2
        c <- round t3
        return $ TA_Trinary id a b c
263
    delve (TA_Expansion id t) = dl t $ TA_Expansion id
264
    delve (TA_Index id t) = d1 t $ TA_Index id
265
    delve (T_Annotation id anns t) = d1 t $ T_Annotation id anns
V
Vidar Holen 已提交
266
    delve (T_CoProc id var body) = d1 body $ T_CoProc id var
267
    delve (T_CoProcBody id t) = d1 t $ T_CoProcBody id
268
    delve (T_Include id includer script) = d2 includer script $ T_Include id
V
Vidar Holen 已提交
269
    delve (T_BatsTest id name t) = d2 name t $ T_BatsTest id
V
Vidar Holen 已提交
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    delve t = return t

getId t = case t of
        T_AND_IF id  -> id
        T_OR_IF id  -> id
        T_DSEMI id  -> id
        T_Semi id  -> id
        T_DLESS id  -> id
        T_DGREAT id  -> id
        T_LESSAND id  -> id
        T_GREATAND id  -> id
        T_LESSGREAT id  -> id
        T_DLESSDASH id  -> id
        T_CLOBBER id  -> id
        T_If id  -> id
        T_Then id  -> id
        T_Else id  -> id
        T_Elif id  -> id
        T_Fi id  -> id
        T_Do id  -> id
        T_Done id  -> id
        T_Case id  -> id
        T_Esac id  -> id
        T_While id  -> id
        T_Until id  -> id
        T_For id  -> id
296
        T_Select id  -> id
V
Vidar Holen 已提交
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
        T_Lbrace id  -> id
        T_Rbrace id  -> id
        T_Lparen id  -> id
        T_Rparen id  -> id
        T_Bang id  -> id
        T_In  id  -> id
        T_NEWLINE id  -> id
        T_EOF id  -> id
        T_Less id  -> id
        T_Greater id  -> id
        T_SingleQuoted id _  -> id
        T_Literal id _  -> id
        T_NormalWord id _  -> id
        T_DoubleQuoted id _  -> id
        T_DollarExpansion id _  -> id
        T_DollarBraced id _  -> id
        T_DollarArithmetic id _  -> id
        T_BraceExpansion id _  -> id
V
Vidar Holen 已提交
315
        T_DollarBraceCommandExpansion id _  -> id
V
Vidar Holen 已提交
316
        T_IoFile id _ _  -> id
317
        T_HereDoc id _ _ _ _ -> id
V
Vidar Holen 已提交
318 319
        T_HereString id _  -> id
        T_FdRedirect id _ _  -> id
320
        T_Assignment id _ _ _ _  -> id
V
Vidar Holen 已提交
321
        T_Array id _  -> id
322
        T_IndexedElement id _ _  -> id
V
Vidar Holen 已提交
323 324
        T_Redirecting id _ _  -> id
        T_SimpleCommand id _ _  -> id
V
Vidar Holen 已提交
325
        T_Pipeline id _ _  -> id
V
Vidar Holen 已提交
326 327 328 329 330 331 332 333 334
        T_Banged id _  -> id
        T_AndIf id _ _ -> id
        T_OrIf id _ _ -> id
        T_Backgrounded id _  -> id
        T_IfExpression id _ _  -> id
        T_Subshell id _  -> id
        T_BraceGroup id _  -> id
        T_WhileExpression id _ _  -> id
        T_UntilExpression id _ _  -> id
V
Vidar Holen 已提交
335
        T_ForIn id _ _ _  -> id
336
        T_SelectIn id _ _ _  -> id
V
Vidar Holen 已提交
337
        T_CaseExpression id _ _ -> id
338
        T_Function id _ _ _ _  -> id
V
Vidar Holen 已提交
339
        T_Arithmetic id _  -> id
V
Vidar Holen 已提交
340
        T_Script id _ _  -> id
V
Vidar Holen 已提交
341
        T_Condition id _ _  -> id
V
Vidar Holen 已提交
342
        T_Extglob id _ _ -> id
V
Vidar Holen 已提交
343
        T_Backticked id _ -> id
V
Vidar Holen 已提交
344 345 346 347 348 349 350
        TC_And id _ _ _ _  -> id
        TC_Or id _ _ _ _  -> id
        TC_Group id _ _  -> id
        TC_Binary id _ _ _ _  -> id
        TC_Unary id _ _ _  -> id
        TC_Noary id _ _  -> id
        TA_Binary id _ _ _  -> id
351
        TA_Assignment id _ _ _  -> id
V
Vidar Holen 已提交
352 353 354 355
        TA_Unary id _ _  -> id
        TA_Sequence id _  -> id
        TA_Trinary id _ _ _  -> id
        TA_Expansion id _  -> id
356
        TA_Index id _  -> id
357
        T_ProcSub id _ _ -> id
358
        T_Glob id _ -> id
V
Vidar Holen 已提交
359
        T_ForArithmetic id _ _ _ _ -> id
360 361
        T_DollarSingleQuoted id _ -> id
        T_DollarDoubleQuoted id _ -> id
362
        T_DollarBracket id _ -> id
363
        T_Annotation id _ _ -> id
V
Vidar Holen 已提交
364
        T_Pipe id _ -> id
V
Vidar Holen 已提交
365
        T_CoProc id _ _ -> id
366
        T_CoProcBody id _ -> id
367
        T_Include id _ _ -> id
V
Vidar Holen 已提交
368
        T_BatsTest id _ _ -> id
V
Vidar Holen 已提交
369 370 371

blank :: Monad m => Token -> m ()
blank = const $ return ()
V
Vidar Holen 已提交
372 373 374
doAnalysis f = analyze f blank id
doStackAnalysis startToken endToken = analyze startToken endToken id
doTransform i = runIdentity . analyze blank blank i
V
Vidar Holen 已提交
375