Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 565 lines (476 sloc) 16.347 kb
cafdc4b9 »
2010-10-06 Parse non-quoted here-docs
1 {-# LANGUAGE PatternGuards #-}
e7bd7a96 »
2010-03-22 Split Parse.hs into the files
2 module Parse where
3 import AST
167ab1ed »
2010-02-19 Initial
4 import Data.List
64503934 »
2010-02-21 Add parameter expansion
5 import Data.Maybe
486ce55e »
2010-02-27 Parse reserved words
6 import Control.Monad
ec29ecf6 »
2010-06-14 Introduce locations
7 import Control.Applicative hiding (many,(<|>),optional)
89f9ba05 »
2010-03-04 Add Parsec.hs
8 import Parsec hiding (token,tokens)
167ab1ed »
2010-02-19 Initial
9
89f9ba05 »
2010-03-04 Add Parsec.hs
10 singleQuoted :: Parser WordPart
11 singleQuoted = dontSkipLineConts $ do
167ab1ed »
2010-02-19 Initial
12 squote
13 text <- many nonQuote
14 squote
15 return $ SQuoted text
16 where
17 squote = char '\''
18 nonQuote = satisfy (/= '\'')
19
89f9ba05 »
2010-03-04 Add Parsec.hs
20 bareWord :: String -> Parser WordPart
64503934 »
2010-02-21 Add parameter expansion
21 bareWord terminators = do
167ab1ed »
2010-02-19 Initial
22 word <- many1 ordinarySymbol
23 return $ Bare word
24 where
64503934 »
2010-02-21 Add parameter expansion
25 ordinarySymbol = noneOf terminators
167ab1ed »
2010-02-19 Initial
26
89f9ba05 »
2010-03-04 Add Parsec.hs
27 escaped :: Parser WordPart
f89a7a60 »
2010-03-21 Parse backquotes
28 escaped = try $ do
167ab1ed »
2010-02-19 Initial
29 char '\\'
30 c <- anyChar
f89a7a60 »
2010-03-21 Parse backquotes
31 bq <- asks insideBackQuotes
32 -- if we are inside backquotes, quoted backquotes have special meaning
33 -- (nesting)
34 if c == '`' && bq
35 then parserFail ""
36 else return $ Escaped c
167ab1ed »
2010-02-19 Initial
37
89f9ba05 »
2010-03-04 Add Parsec.hs
38 doubleQuoted :: Parser WordPart
167ab1ed »
2010-02-19 Initial
39 doubleQuoted = do
40 dQuote
f89a7a60 »
2010-03-21 Parse backquotes
41 parts <- many $ escaped <|> bare_word <|> substitution <|> backquoted
167ab1ed »
2010-02-19 Initial
42 dQuote
43 return $ DQuoted parts
44 where
45 dQuote = char '"'
5840c5f5 »
2010-02-21 Backslash treatment
46 escapables = "$`\"\\\n"
47 escaped = try $ do
167ab1ed »
2010-02-19 Initial
48 char '\\'
b9b2933b »
2010-06-14 Applicative style
49 Escaped <$> oneOf escapables
5840c5f5 »
2010-02-21 Backslash treatment
50 bare_word = do
51 w <- many1 ordinary_symbol
52 return $ Bare w
53 where
54 ordinary_symbol = noneOf "$`\\\"" <|>
1bf4b1d0 »
2010-10-19 Fix escaped quote parsing inside double-quoted string
55 try (do char '\\'; lookAhead (noneOf escapables); return '\\')
167ab1ed »
2010-02-19 Initial
56
f89a7a60 »
2010-03-21 Parse backquotes
57 backquoted = do
58 RS { insideBackQuotes = alreadyInsideBackQuotes
59 , insideEscapedBackQuotes = alreadyInsideEscapedBackQuotes }
60 <- ask
61 if not alreadyInsideBackQuotes
62 then enterBackQuotes backQuotes
63 else -- if already inside backquotes,
64 -- try to parse escaped backquotes
65 if not alreadyInsideEscapedBackQuotes
66 then enterEscapedBackQuotes escapedBackQuotes
67 else parserFail ""
68 where
ec29ecf6 »
2010-06-14 Introduce locations
69 backQuotes = recordPos $ do
f89a7a60 »
2010-03-21 Parse backquotes
70 char '`'
71 cmd <- list
72 char '`'
73 return $ CommandSubst cmd
ec29ecf6 »
2010-06-14 Introduce locations
74 escapedBackQuotes = recordPos $ do
f89a7a60 »
2010-03-21 Parse backquotes
75 string "\\`"
76 cmd <- list
77 string "\\`"
78 return $ CommandSubst cmd
79
89f9ba05 »
2010-03-04 Add Parsec.hs
80 word :: String -> Bool -> Parser Word
64503934 »
2010-02-21 Add parameter expansion
81 word terminators acceptEmpty = do
82 (if acceptEmpty then many else many1) $
f89a7a60 »
2010-03-21 Parse backquotes
83 escaped <|> singleQuoted <|> doubleQuoted <|> substitution <|> backquoted <|> bareWord terminators
167ab1ed »
2010-02-19 Initial
84
4a692eb6 »
2010-06-15 Move here-docs handling from Parsec.hs to Parse.hs
85 --- Here-docs ---
86
87 -- newline needs special treatment because it may be followed by a here-doc
88 -- this parser needs to be used everywhere where newline is needed, except
89 -- 'lineConts'
90 -- todo: more efficient string concatenation
e4706020 »
2010-10-13 Add error clarifiers
91 newline = "newline" `definedAs` do
4a692eb6 »
2010-06-15 Move here-docs handling from Parsec.hs to Parse.hs
92 char '\n'
93 -- check if we need to parse any here-docs
8ba19950 »
2010-06-15 Modify here-doc parsing
94 mapM_ readHereDoc . reverse =<< pendingHereDocs
4a692eb6 »
2010-06-15 Move here-docs handling from Parsec.hs to Parse.hs
95 return '\n'
cafdc4b9 »
2010-10-06 Parse non-quoted here-docs
96
97 readHereDoc (delim,i,isQuoted) = rememberHereDoc i . joinWordParts =<< hereDocLine `manyTill` delim_nl
4a692eb6 »
2010-06-15 Move here-docs handling from Parsec.hs to Parse.hs
98 where
cafdc4b9 »
2010-10-06 Parse non-quoted here-docs
99 delim_nl = string $ delim ++ "\n"
100 hereDocLine
101 | HereDocQuoted <- isQuoted = SQuoted <$> sline
102 | HereDocNotQuoted <- isQuoted = DQuoted <$> dline
103 -- line of quoted here-doc
104 sline = (\s n -> s ++ [n]) <$> many (satisfy (/= '\n')) <*> char '\n'
105 -- line of non-quoted here-doc
106 dline = (\s n -> s ++ [Bare [n]])
107 <$> many (escaped <|> bare_word <|> substitution <|> backquoted)
108 <*> char '\n'
4a692eb6 »
2010-06-15 Move here-docs handling from Parsec.hs to Parse.hs
109 where
cafdc4b9 »
2010-10-06 Parse non-quoted here-docs
110 escapables = "$`\\\n"
111 escaped = try $ do
112 char '\\'
113 Escaped <$> oneOf escapables
114 bare_word = do
115 w <- many1 ordinary_symbol
116 return $ Bare w
117 where
118 ordinary_symbol = noneOf "$`\\\n" <|>
1bf4b1d0 »
2010-10-19 Fix escaped quote parsing inside double-quoted string
119 try (do char '\\'; lookAhead (noneOf escapables); return '\\')
cafdc4b9 »
2010-10-06 Parse non-quoted here-docs
120
121 -- If several contiguous strings in a word are of the same type,
122 -- join them
123 joinWordParts :: Word -> Word
124 joinWordParts (Bare x : Bare y : rest) = joinWordParts $ Bare (x ++ y) : rest
125 joinWordParts (SQuoted x : SQuoted y : rest) = joinWordParts $ SQuoted (x ++ y) : rest
126 joinWordParts (DQuoted x : DQuoted y : rest) = joinWordParts $ DQuoted (x ++ y) : rest
127 joinWordParts (DQuoted x : rest) = DQuoted (joinWordParts x) : joinWordParts rest
128 joinWordParts (x : xs) = x : joinWordParts xs
129 joinWordParts [] = []
4a692eb6 »
2010-06-15 Move here-docs handling from Parsec.hs to Parse.hs
130
167ab1ed »
2010-02-19 Initial
131 --- Operators ---
132
89f9ba05 »
2010-03-04 Add Parsec.hs
133 operator :: Parser String
cc18da28 »
2010-02-28 Whitespace treatment
134 operator = token $ do
93c50a58 »
2010-06-14 Introduce special parser for newline
135 choice $ newline_str : map (try.string) operatorList
136 where newline_str = (:[]) <$> newline
167ab1ed »
2010-02-19 Initial
137
451dbc04 »
2010-02-28 Parsing utilities
138 theOperator op = try $ do
139 op' <- operator
140 guard $ op' == op
141 return op
142
93c50a58 »
2010-06-14 Introduce special parser for newline
143 -- we don't include \n to the operatorList because \n has its own special parser
144 operatorList = ["(",")","&&","||",";;","<<",">>","<&",">&","<>","<<-",">|","<",">","&",";","|"]
145 opFirstLetters = '\n' : (nub . map head) operatorList
167ab1ed »
2010-02-19 Initial
146
147 --- Comments ---
148
89f9ba05 »
2010-03-04 Add Parsec.hs
149 comment :: Parser ()
e4706020 »
2010-10-13 Add error clarifiers
150 comment = "comment" `definedAs` do
167ab1ed »
2010-02-19 Initial
151 char '#'
152 many $ satisfy (/= '\n')
153 return ()
154
89f9ba05 »
2010-03-04 Add Parsec.hs
155 whiteSpace :: Parser ()
9214c785 »
2010-03-20 Add tab to whitespace
156 whiteSpace = do many1 $ comment <|> (oneOf " \t" >> return ());
167ab1ed »
2010-02-19 Initial
157 return ()
158
159 --- Substitutions ---
64503934 »
2010-02-21 Add parameter expansion
160 -- Parameter expansion, command substitution or arithmetic expansion
89f9ba05 »
2010-03-04 Add Parsec.hs
161 substitution :: Parser WordPart
ec29ecf6 »
2010-06-14 Introduce locations
162 substitution = recordPos $
163 char '$' *>
164 (ParSubst <$> parameterSubst <|> CommandSubst <$> commandSubst)
167ab1ed »
2010-02-19 Initial
165
4cd9bc12 »
2010-02-20 Implement 'name'
166 -- A word consisting solely of underscores, digits, and alphabetics from the
4117844f »
2010-10-02 Space issues
167 -- portable character set. The first character of a name is not a digit.
9ae32e5e »
2010-03-20 Introduce "Name" type synonym
168 name :: Parser Name
4e05a2e1 »
2010-03-21 Bugfix: make a distinction between name and token_name
169 name = do
4cd9bc12 »
2010-02-20 Implement 'name'
170 first <- underscore <|> letter
171 rest <- many $ underscore <|> letter <|> digit
172 return $ first:rest
173 where
174 -- portable character set
175 letter = satisfy $ \x -> (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z')
176 underscore = char '_'
177
4e05a2e1 »
2010-03-21 Bugfix: make a distinction between name and token_name
178 token_name :: Parser Name
179 token_name = token name
180
89f9ba05 »
2010-03-04 Add Parsec.hs
181 parameterSubst :: Parser ParSubstExpr
64503934 »
2010-02-21 Add parameter expansion
182 parameterSubst = do
183 braced <|> unbraced <?> "parameter substitution"
167ab1ed »
2010-02-19 Initial
184 where
185 lbrace = char '{'
186 rbrace = char '}'
64503934 »
2010-02-21 Add parameter expansion
187
188 braced = between lbrace rbrace $
4117844f »
2010-10-02 Space issues
189 try string_length <|>
190 try parameter_check <|>
64503934 »
2010-02-21 Add parameter expansion
191 try parameter_substr <|>
b9b2933b »
2010-06-14 Applicative style
192 try (flip ParSubstExpr NoModifier <$> parameter)
64503934 »
2010-02-21 Add parameter expansion
193
4117844f »
2010-10-02 Space issues
194 parameter = do special <|> positional <|> Var <$> name
64503934 »
2010-02-21 Add parameter expansion
195
196 word_arg = word "}'\"`$\\" True
197
198 parameter_check = do
199 par <- parameter
200 colon <- optionMaybe $ char ':'
201 op <- oneOf "-+=?"
202 w <- word_arg
4117844f »
2010-10-02 Space issues
203
64503934 »
2010-02-21 Add parameter expansion
204 let mod = case op of
205 '-' -> UseDefault
206 '=' -> AssignDefault
207 '+' -> UseAlternative
208 '?' -> Assert
4117844f »
2010-10-02 Space issues
209
64503934 »
2010-02-21 Add parameter expansion
210 let checkType = if isJust colon then CheckUnsetAndNull else CheckUnset
211
212 return $ ParSubstExpr par (mod w checkType)
213
214 parameter_substr = do
215 par <- parameter
216 op <- choice $ map (try.string) ["%%","%","##","#"]
217 w <- word_arg
218
219 let mod = case op of
220 "%" -> Remove w Smallest Suffix
221 "%%" -> Remove w Largest Suffix
222 "#" -> Remove w Smallest Prefix
223 "##" -> Remove w Largest Prefix
224 return $ ParSubstExpr par mod
225
226 string_length = do
227 char '#'
228 par <- parameter
229 return $ ParSubstExpr par StringLength
230
231 unbraced = do
232 par <- special -- should be the first to capture 0
233 <|> simple_positional
b9b2933b »
2010-06-14 Applicative style
234 <|> Var <$> name
64503934 »
2010-02-21 Add parameter expansion
235 return $ ParSubstExpr par NoModifier
4117844f »
2010-10-02 Space issues
236
b9b2933b »
2010-06-14 Applicative style
237 variable = Var <$> name <?> "variable"
64503934 »
2010-02-21 Add parameter expansion
238
239 simple_positional = do
240 d <- digit
241 return $ Positional $ read [d]
242
b9b2933b »
2010-06-14 Applicative style
243 positional = Positional <$> number
4117844f »
2010-10-02 Space issues
244
b9b2933b »
2010-06-14 Applicative style
245 special = Special <$> oneOf "@*#?-$!0"
167ab1ed »
2010-02-19 Initial
246
9552ddff »
2010-03-20 Parse command substitutions
247 commandSubst :: Parser CompoundList
248 commandSubst = between (char '(') (char ')') compoundList
249
167ab1ed »
2010-02-19 Initial
250 --- Tokens ---
cc18da28 »
2010-02-28 Whitespace treatment
251
89f9ba05 »
2010-03-04 Add Parsec.hs
252 token :: Parser a -> Parser a
cc18da28 »
2010-02-28 Whitespace treatment
253 token p = do optional whiteSpace; x <- p; optional whiteSpace; return x
254
255 separated p = do
256 optional whiteSpace
257 sepEndBy p (optional whiteSpace)
258
259 separated1 p = do
260 optional whiteSpace
261 sepEndBy1 p (optional whiteSpace)
262
263 token_word = token $ word ("'\"`$\\\n# " ++ opFirstLetters) False
ba4ea0f3 »
2010-02-23 Redirection parsing
264
265 --- Syntax ---
89f9ba05 »
2010-03-04 Add Parsec.hs
266 redirOp :: Parser RedirectionOp
ba4ea0f3 »
2010-02-23 Redirection parsing
267 redirOp = do
268 op <- choice $ map (try.string) ["<<-",">>","<&",">&","<>","<<",">|","<",">"]
269 return $ case op of
270 "<" -> RedirectInput
271 ">" -> RedirectOutput NoClobber
272 ">|" -> RedirectOutput Clobber
6211fe42 »
2010-06-15 First approximation of heredoc parsing (fixme)
273 "<<" -> HereDoc NoStrip undefined
274 "<<-"-> HereDoc Strip undefined
ba4ea0f3 »
2010-02-23 Redirection parsing
275 ">>" -> AppendOutput
276 "<&" -> DupInput
277 ">&" -> DupOutput
278 "<>" -> ReadWrite
279
89f9ba05 »
2010-03-04 Add Parsec.hs
280 redirection :: Parser Redirection
330d0f6a »
2010-10-19 Rearrange try's in simpleCommand and fix bug with command starting wi…
281 redirection = try $ do
ba4ea0f3 »
2010-02-23 Redirection parsing
282 mbFd <- optionMaybe number
283 op <- redirOp
ff34eef1 »
2010-06-15 Correctly parse quoted here-doc delimeters
284 w <- case op of
285 HereDoc {} -> hereDocDelim
286 _ -> token_word
ba4ea0f3 »
2010-02-23 Redirection parsing
287
288 let fd = case mbFd of
289 Just fd -> fd
290 Nothing -> case op of
291 RedirectOutput _ -> 1
292 AppendOutput -> 1
293 DupOutput -> 1
294 RedirectInput -> 0
6211fe42 »
2010-06-15 First approximation of heredoc parsing (fixme)
295 HereDoc _ _ -> 0
ba4ea0f3 »
2010-02-23 Redirection parsing
296 DupInput -> 0
297 ReadWrite -> 0
298
6211fe42 »
2010-06-15 First approximation of heredoc parsing (fixme)
299 op' <- case op of
300 HereDoc strip _ -> do
16027a5a »
2010-10-02 Detect quoted here-docs
301 i <- enqueueHereDoc (unquote w) (isQuoted w)
6211fe42 »
2010-06-15 First approximation of heredoc parsing (fixme)
302 return $ HereDoc strip i
303 _ -> return op
304
305 return $ Redirection fd op' w
306 where
16027a5a »
2010-10-02 Detect quoted here-docs
307 isQuoted [Bare {}] = HereDocNotQuoted
308 isQuoted _ = HereDocQuoted
309
6211fe42 »
2010-06-15 First approximation of heredoc parsing (fixme)
310 unquote = concatMap unquote1
4117844f »
2010-10-02 Space issues
311
6211fe42 »
2010-06-15 First approximation of heredoc parsing (fixme)
312 unquote1 (Bare s) = s
313 unquote1 (SQuoted s) = s
314 unquote1 (DQuoted w) = unquote w
315 unquote1 (Escaped c) = [c]
7055c295 »
2010-09-27 Fix spelling
316 unquote1 x = error $ "Got unexpected thingy in here-doc delimiter: " ++ show x
4117844f »
2010-10-02 Space issues
317
ff34eef1 »
2010-06-15 Correctly parse quoted here-doc delimeters
318 hereDocDelim = token $ many1 $
319 escaped <|> singleQuoted <|> doubleQuoted <|> bareWord "'\"\\\n# "
4117844f »
2010-10-02 Space issues
320
ff34eef1 »
2010-06-15 Correctly parse quoted here-doc delimeters
321 doubleQuoted :: Parser WordPart
322 doubleQuoted = do
323 dQuote
324 parts <- many $ escaped <|> bare_word
325 dQuote
326 return $ DQuoted parts
327 where
328 dQuote = char '"'
329 escapables = "$`\"\\\n"
330 escaped = try $ do
331 char '\\'
332 Escaped <$> oneOf escapables
333 bare_word = do
334 w <- many1 ordinary_symbol
335 return $ Bare w
336 where
337 ordinary_symbol = noneOf "\\\"" <|>
1bf4b1d0 »
2010-10-19 Fix escaped quote parsing inside double-quoted string
338 try (do char '\\'; lookAhead (noneOf escapables); return '\\')
ff34eef1 »
2010-06-15 Correctly parse quoted here-doc delimeters
339
167ab1ed »
2010-02-19 Initial
340
330d0f6a »
2010-10-19 Rearrange try's in simpleCommand and fix bug with command starting wi…
341 assignment = try $ do
f608f868 »
2010-02-27 Parse commands
342 var <- name
343 char '='
344 value <- token_word
345 return $ Assignment var value
346
bd9e291f »
2010-03-20 function support
347 ifNotReserved :: Parser a -> Parser a
348 ifNotReserved p = try $ do
349 r <- optionMaybe reservedWord
350 case r of
351 Just _ -> parserFail "unexpected reserved word"
352 Nothing -> p
353
0053c98b »
2010-03-11 Don't accept reserved words as simple commands
354 simpleCommand = ifNotReserved $ do
330d0f6a »
2010-10-19 Rearrange try's in simpleCommand and fix bug with command starting wi…
355 cmd_prefix <- separated $ add_assignment <$> assignment <|> add_redirection <$> redirection
b9b2933b »
2010-06-14 Applicative style
356 cmd_word <- maybeToList <$> optionMaybe (add_word <$> token_word)
330d0f6a »
2010-10-19 Rearrange try's in simpleCommand and fix bug with command starting wi…
357 cmd_suffix <- separated $ add_redirection <$> redirection <|> add_word <$> token_word
f608f868 »
2010-02-27 Parse commands
358
359 let (as,rs,ws) = foldr ($) ([],[],[]) (cmd_prefix ++ cmd_word ++ cmd_suffix)
360
bc580d6e »
2010-02-28 Don't accept empty command
361 case (as,rs,ws) of
362 ([],[],[]) -> parserFail "Empty command"
363 _ -> return $ SimpleCommand as rs ws
f608f868 »
2010-02-27 Parse commands
364
365 where
366 add_assignment a (as,rs,ws) = (a:as,rs,ws)
367 add_redirection r (as,rs,ws) = (as,r:rs,ws)
368 add_word w (as,rs,ws) = (as,rs,w:ws)
369
486ce55e »
2010-02-27 Parse reserved words
370 reservedWords = ["!", "{", "}", "case", "do", "done", "elif", "else", "esac",
371 "fi", "for", "if", "in", "then", "until", "while"]
372
e4706020 »
2010-10-13 Add error clarifiers
373 reservedWord = ("reserved word" `definedAs`) . try $ do
486ce55e »
2010-02-27 Parse reserved words
374 [Bare x] <- token_word
375 guard $ x `elem` reservedWords
376 return $ x
e4706020 »
2010-10-13 Add error clarifiers
377 theReservedWord w = (("reserved word \"" ++ w ++ "\"") `definedAs`) $ try $ do
81ec9fdc »
2010-02-28 theReservedWord: don't consume input when failed
378 w' <- reservedWord
451dbc04 »
2010-02-28 Parsing utilities
379 guard $ w == w'
380 return w
486ce55e »
2010-02-27 Parse reserved words
381
93c50a58 »
2010-06-14 Introduce special parser for newline
382 linebreak = separated newline
383 newline_list = separated1 $ newline
6c1c2b2c »
2010-03-13 Parse for loops
384 sequential_sep = (theOperator ";" >> linebreak) <|> newline_list
709b3f59 »
2010-02-28 Parse pipeline
385
386 pipeline = do
387 bang <- do optionMaybe (theReservedWord "!")
388 ps <- pipe_sequence
389 let status = if isJust bang then Inverted else Straight
390 return $ Pipeline status ps
391 where
392 pipe_sequence = do
393 sepBy1 command (do theOperator "|"; linebreak)
394
bd9e291f »
2010-03-20 function support
395 functionDefinition :: Parser FunctionDefinition
396 functionDefinition = ifNotReserved $ do
4e05a2e1 »
2010-03-21 Bugfix: make a distinction between name and token_name
397 fname <- token_name
bd9e291f »
2010-03-20 function support
398 string "()"
399 linebreak
1d17e292 »
2010-03-21 Compound commands can end with redirections
400 (body,redirs) <- compoundCommand
401 return $ FunctionDefinition fname body redirs
bd9e291f »
2010-03-20 function support
402
1d17e292 »
2010-03-21 Compound commands can end with redirections
403 command :: Parser Command
381a4de3 »
2010-10-16 Remove some unnecessary 'try's
404 command = ComFunction <$> functionDefinition
b9b2933b »
2010-06-14 Applicative style
405 <|> (uncurry ComCompound) <$> compoundCommand
406 <|> ComSimple <$> simpleCommand
4117844f »
2010-10-02 Space issues
407
709b3f59 »
2010-02-28 Parse pipeline
408
2c502186 »
2010-02-28 Parse and-or list
409 andOrList = do
410 p <- pipeline
411 op <- optionMaybe $ theOperator "&&" <|> theOperator "||"
412 case op of
413 Nothing -> return $ First p
414 Just op -> do
415 linebreak
416 rest <- andOrList
417 let opCon = case op of
418 "&&" -> And
419 "||" -> Or
420 return $ opCon p rest
421
d9610840 »
2010-03-19 Rework lists and compound lists
422 list :: Parser CompoundList
423 list = do
936608d6 »
2010-03-19 Permit newlines in the beginning of compound list
424 linebreak
ea5c5024 »
2010-02-28 Parse compound list
425 aol <- andOrList
d9610840 »
2010-03-19 Rework lists and compound lists
426 mode <- optionMaybe $
427 (do theOperator ";"; linebreak; return Seq) <|>
428 (do theOperator "&"; linebreak; return Async) <|>
429 (do newline_list; return Seq)
430 -- if there is separator, try to parse list further
431 -- if there is no, finish
432 case mode of
433 Just mode -> do
434 rest <- optionMaybe list
435 return $ (aol,mode) : (concat.maybeToList) rest
436 Nothing -> return [(aol,Seq)]
437
438 compoundList = list
ea5c5024 »
2010-02-28 Parse compound list
439
1d17e292 »
2010-03-21 Compound commands can end with redirections
440 compoundCommand :: Parser (CompoundCommand, [Redirection])
441 compoundCommand = do
442 cmd <- choice
443 [ braceGroup
444 , subShell
445 , forClause
446 , ifClause
447 , whileClause
448 , untilClause
449 , caseClause
450 ]
451 redirs <- many redirection
452 return (cmd, redirs)
ba451488 »
2010-03-11 Parse brace groups
453
b9b2933b »
2010-06-14 Applicative style
454 braceGroup = BraceGroup <$> between (theReservedWord "{") (theReservedWord "}") compoundList
ba451488 »
2010-03-11 Parse brace groups
455
b9b2933b »
2010-06-14 Applicative style
456 subShell = SubShell <$> between (theOperator "(") (theOperator ")") compoundList
e18fc935 »
2010-03-12 Subshell parsing
457
6c1c2b2c »
2010-03-13 Parse for loops
458 doGroup = between (theReservedWord "do") (theReservedWord "done") compoundList
459
460 forClause = do
461 theReservedWord "for"
4e05a2e1 »
2010-03-21 Bugfix: make a distinction between name and token_name
462 var <- token_name
6c1c2b2c »
2010-03-13 Parse for loops
463 linebreak
464 words <- optionMaybe wordlist
465 do_group <- doGroup
466 let list = case words of
467 Just ws -> ForWords ws
468 Nothing -> ForPositional
469 return $ For var list do_group
470 where
471 wordlist = do
472 theReservedWord "in"
473 ws <- many token_word
474 sequential_sep
475 return ws
476
4bf0092f »
2010-03-19 Parse while loops
477 whileClause = do
478 theReservedWord "while"
479 l <- compoundList
480 cmds <- doGroup
481 return $ While l cmds
482
a13fe60b »
2010-03-19 Parse until loops
483 untilClause = do
484 theReservedWord "until"
485 l <- compoundList
486 cmds <- doGroup
487 return $ Until l cmds
488
e8ce0ad9 »
2010-03-14 Parse if clause
489 ifClause = do
490 theReservedWord "if"
491 cond <- compoundList
492 theReservedWord "then"
493 then_part <- compoundList
494 elif_parts <- many elif_part
495 mb_else_part <- optionMaybe else_part
496 theReservedWord "fi"
497 return $ If ((cond,then_part):elif_parts) mb_else_part
498
499 where
500 elif_part = do
501 theReservedWord "elif"
502 cond <- compoundList
503 theReservedWord "then"
504 then_part <- compoundList
505 return (cond, then_part)
506
507 else_part = do
508 theReservedWord "else"
509 compoundList
510
645ca164 »
2010-03-20 Parse case clause
511 caseClause = do
512 theReservedWord "case"
513 w <- token_word
514 linebreak
515 theReservedWord "in"
516 linebreak
517 cl <- case_list
518
519 return $ Case w cl
4117844f »
2010-10-02 Space issues
520
645ca164 »
2010-03-20 Parse case clause
521 where
522 -- case_item:
523 -- returns Left () if it parsed "esac",
524 -- returns Right (item, True) if it has parsed item with DSEMI
525 -- returns Right (item, False) if it has parsed item without DSEMI
526 pattern :: Parser [Word]
527 pattern = sepBy1 token_word (char '|')
528
529 case_item :: Parser (Either () (([Word],CompoundList), Bool))
530 case_item = do
531 openParen <- optionMaybe (theOperator "(")
532 let esac = case openParen of
533 -- if there was opening paren, don't recognise esac as reserved word
534 Nothing -> do theReservedWord "esac"; return $ Left ()
535 Just _ -> parserFail ""
536
537 item = do
538 pat <- pattern
539 theOperator ")"
540 linebreak
541 cl <- optionMaybe compoundList
542 dsemi <- optionMaybe (theOperator ";;")
543 linebreak
544 return $ Right ((pat,concat $ maybeToList cl),isJust dsemi)
545
546 esac <|> item
547
548 case_list = do
549 ci <- case_item
550 case ci of
551 Left _ -> return []
b9b2933b »
2010-06-14 Applicative style
552 Right (pat,True) -> (pat:) <$> case_list
645ca164 »
2010-03-20 Parse case clause
553 Right (pat,False) -> do theReservedWord "esac"; return [pat]
554
e7bd7a96 »
2010-03-22 Split Parse.hs into the files
555 program = do
556 l <- list
557 eof
558 return l
1e514cd1 »
2010-02-23 Refactoring: add number parser
559
560 --- Misc ---
561
562 number = do
563 n <- many1 digit
564 return $ read n
Something went wrong with that request. Please try again.