AST.hs 12.3 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 37
    TA_Binary Id String Token Token
    | TA_Expansion Id [Token]
38
    | TA_Index Id Token
V
Vidar Holen 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51
    | 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]
52
    | T_IndexedElement Id Token Token
53
    | T_Assignment Id AssignmentMode String (Maybe Token) Token
V
Vidar Holen 已提交
54 55 56 57
    | T_Backgrounded Id Token
    | T_Backticked Id [Token]
    | T_Bang Id
    | T_Banged Id Token
58
    | T_BraceExpansion Id [Token]
V
Vidar Holen 已提交
59 60 61
    | T_BraceGroup Id [Token]
    | T_CLOBBER Id
    | T_Case Id
62
    | T_CaseExpression Id Token [(CaseType, [Token], [Token])]
V
Vidar Holen 已提交
63 64 65 66 67 68 69 70
    | 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
71
    | T_DollarBracket Id Token
V
Vidar Holen 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85
    | T_DollarDoubleQuoted Id [Token]
    | T_DollarExpansion Id [Token]
    | T_DollarSingleQuoted Id String
    | 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 已提交
86
    | T_ForIn Id String [Token] [Token]
87
    | T_Function Id FunctionKeyword FunctionParentheses String Token
V
Vidar Holen 已提交
88 89 90
    | T_GREATAND Id
    | T_Glob Id String
    | T_Greater Id
91
    | T_HereDoc Id Dashed Quoted String [Token]
V
Vidar Holen 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    | 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 已提交
107
    | T_Pipeline Id [Token] [Token] -- [Pipe separators] [Commands]
V
Vidar Holen 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    | 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]
124
    | T_Annotation Id [Annotation] Token
V
Vidar Holen 已提交
125
    | T_Pipe Id String
V
Vidar Holen 已提交
126
    | T_CoProc Id (Maybe String) Token
127
    | T_CoProcBody Id Token
128
    | T_Include Id Token Token -- . & source: SimpleCommand T_Script
V
Vidar Holen 已提交
129 130
    deriving (Show)

131
data Annotation = DisableComment Integer deriving (Show, Eq)
V
Vidar Holen 已提交
132 133
data ConditionType = DoubleBracket | SingleBracket deriving (Show, Eq)

134 135 136 137
-- 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)"
138

139 140
instance Eq Token where
    (==) = tokenEquals
V
Vidar Holen 已提交
141 142

analyze :: Monad m => (Token -> m ()) -> (Token -> m ()) -> (Token -> Token) -> Token -> m Token
V
Vidar Holen 已提交
143 144
analyze f g i =
    round
V
Vidar Holen 已提交
145 146 147 148 149 150 151 152
  where
    round t = do
        f t
        newT <- delve t
        g t
        return . i $ newT
    roundAll = mapM round

153 154 155 156 157
    roundMaybe Nothing = return Nothing
    roundMaybe (Just v) = do
        s <- round v
        return (Just s)

V
Vidar Holen 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    dl l v = do
        x <- roundAll l
        return $ v x
    dll l m v = do
        x <- roundAll l
        y <- roundAll m
        return $ v x m
    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
175
    delve (T_DollarDoubleQuoted id list) = dl list $ T_DollarDoubleQuoted id
V
Vidar Holen 已提交
176
    delve (T_DollarExpansion id list) = dl list $ T_DollarExpansion id
177
    delve (T_BraceExpansion id list) = dl list $ T_BraceExpansion id
178
    delve (T_Backticked id list) = dl list $ T_Backticked id
V
Vidar Holen 已提交
179
    delve (T_DollarArithmetic id c) = d1 c $ T_DollarArithmetic id
180
    delve (T_DollarBracket id c) = d1 c $ T_DollarBracket id
V
Vidar Holen 已提交
181 182 183
    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
184 185 186 187
    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 已提交
188
    delve (T_Array id t) = dl t $ T_Array id
189
    delve (T_IndexedElement id t1 t2) = d2 t1 t2 $ T_IndexedElement id
V
Vidar Holen 已提交
190 191 192 193 194
    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 已提交
195
    delve (T_Pipeline id l1 l2) = dll l1 l2 $ T_Pipeline id
V
Vidar Holen 已提交
196 197 198 199 200
    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
201
    delve (T_ProcSub id typ l) = dl l $ T_ProcSub id typ
V
Vidar Holen 已提交
202 203 204 205 206 207 208 209 210 211 212 213
    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 已提交
214
    delve (T_ForIn id v w l) = dll w l $ T_ForIn id v
215
    delve (T_SelectIn id v w l) = dll w l $ T_SelectIn id v
V
Vidar Holen 已提交
216 217
    delve (T_CaseExpression id word cases) = do
        newWord <- round word
218
        newCases <- mapM (\(o, c, t) -> do
V
Vidar Holen 已提交
219 220
                            x <- mapM round c
                            y <- mapM round t
221
                            return (o, x,y)
V
Vidar Holen 已提交
222 223 224
                        ) cases
        return $ T_CaseExpression id newWord newCases

V
Vidar Holen 已提交
225 226 227 228 229 230 231
    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 已提交
232
    delve (T_Script id s l) = dl l $ T_Script id s
233
    delve (T_Function id a b name body) = d1 body $ T_Function id a b name
V
Vidar Holen 已提交
234
    delve (T_Condition id typ token) = d1 token $ T_Condition id typ
V
Vidar Holen 已提交
235
    delve (T_Extglob id str l) = dl l $ T_Extglob id str
V
Vidar Holen 已提交
236
    delve (T_DollarBraced id op) = d1 op $ T_DollarBraced id
237
    delve (T_HereDoc id d q str l) = dl l $ T_HereDoc id d q str
V
Vidar Holen 已提交
238

V
Vidar Holen 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
    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
    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
254
    delve (TA_Expansion id t) = dl t $ TA_Expansion id
255
    delve (TA_Index id t) = d1 t $ TA_Index id
256
    delve (T_Annotation id anns t) = d1 t $ T_Annotation id anns
V
Vidar Holen 已提交
257
    delve (T_CoProc id var body) = d1 body $ T_CoProc id var
258
    delve (T_CoProcBody id t) = d1 t $ T_CoProcBody id
259
    delve (T_Include id includer script) = d2 includer script $ T_Include id
V
Vidar Holen 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
    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
286
        T_Select id  -> id
V
Vidar Holen 已提交
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
        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
        T_IoFile id _ _  -> id
306
        T_HereDoc id _ _ _ _ -> id
V
Vidar Holen 已提交
307 308
        T_HereString id _  -> id
        T_FdRedirect id _ _  -> id
309
        T_Assignment id _ _ _ _  -> id
V
Vidar Holen 已提交
310
        T_Array id _  -> id
311
        T_IndexedElement id _ _  -> id
V
Vidar Holen 已提交
312 313
        T_Redirecting id _ _  -> id
        T_SimpleCommand id _ _  -> id
V
Vidar Holen 已提交
314
        T_Pipeline id _ _  -> id
V
Vidar Holen 已提交
315 316 317 318 319 320 321 322 323
        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 已提交
324
        T_ForIn id _ _ _  -> id
325
        T_SelectIn id _ _ _  -> id
V
Vidar Holen 已提交
326
        T_CaseExpression id _ _ -> id
327
        T_Function id _ _ _ _  -> id
V
Vidar Holen 已提交
328
        T_Arithmetic id _  -> id
V
Vidar Holen 已提交
329
        T_Script id _ _  -> id
V
Vidar Holen 已提交
330
        T_Condition id _ _  -> id
V
Vidar Holen 已提交
331
        T_Extglob id _ _ -> id
V
Vidar Holen 已提交
332
        T_Backticked id _ -> id
V
Vidar Holen 已提交
333 334 335 336 337 338 339 340 341 342 343
        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
        TA_Unary id _ _  -> id
        TA_Sequence id _  -> id
        TA_Trinary id _ _ _  -> id
        TA_Expansion id _  -> id
344
        TA_Index id _  -> id
345
        T_ProcSub id _ _ -> id
346
        T_Glob id _ -> id
V
Vidar Holen 已提交
347
        T_ForArithmetic id _ _ _ _ -> id
348 349
        T_DollarSingleQuoted id _ -> id
        T_DollarDoubleQuoted id _ -> id
350
        T_DollarBracket id _ -> id
351
        T_Annotation id _ _ -> id
V
Vidar Holen 已提交
352
        T_Pipe id _ -> id
V
Vidar Holen 已提交
353
        T_CoProc id _ _ -> id
354
        T_CoProcBody id _ -> id
355
        T_Include id _ _ -> id
V
Vidar Holen 已提交
356 357 358

blank :: Monad m => Token -> m ()
blank = const $ return ()
V
Vidar Holen 已提交
359 360 361
doAnalysis f = analyze f blank id
doStackAnalysis startToken endToken = analyze startToken endToken id
doTransform i = runIdentity . analyze blank blank i
V
Vidar Holen 已提交
362