@@ -157,7 +157,11 @@ def lex_one_token(self):
157
157
lex_one_token - Lex a single 'sh' token."""
158
158
159
159
c = self .eat ()
160
+ if c == "{" or c == "}" :
161
+ return (c ,)
160
162
if c == ";" :
163
+ if self .maybe_eat ("}" ) or (self .maybe_eat (" " ) and self .maybe_eat ("}" )):
164
+ return ("}" ,)
161
165
return (c ,)
162
166
if c == "|" :
163
167
if self .maybe_eat ("|" ):
@@ -200,6 +204,8 @@ def __init__(self, data, win32Escapes=False, pipefail=False):
200
204
self .data = data
201
205
self .pipefail = pipefail
202
206
self .tokens = ShLexer (data , win32Escapes = win32Escapes ).lex ()
207
+ self .brace_stack = []
208
+ self .brace_dict = {'{' : '}' }
203
209
204
210
def lex (self ):
205
211
for item in self .tokens :
@@ -255,18 +261,42 @@ def parse_pipeline(self):
255
261
self .lex ()
256
262
commands .append (self .parse_command ())
257
263
return Pipeline (commands , negate , self .pipefail )
264
+
265
+
266
+ # {echo foo; echo bar;} && echo hello
267
+ # echo hello && {echo foo; echo bar}
268
+
269
+ def parse (self , seq_type ):
270
+ lhs = None
271
+ if isinstance (self .look (), tuple ):
272
+ brace = self .lex ()
273
+ self .brace_stack .append (brace )
274
+ if brace [0 ] == '{' :
275
+ lhs = self .parse (('{' , '}' ))
276
+ else :
277
+ raise ValueError ("syntax error near unexpected token %r" % brace [0 ])
258
278
259
- def parse ( self ) :
260
- lhs = self .parse_pipeline ()
279
+ else :
280
+ lhs = self .parse_pipeline ()
261
281
262
282
while self .look ():
263
283
operator = self .lex ()
264
284
assert isinstance (operator , tuple ) and len (operator ) == 1
265
285
286
+ if operator == self .brace_dict [self .brace_stack .peek ()]:
287
+ break
288
+
266
289
if not self .look ():
267
290
raise ValueError ("missing argument to operator %r" % operator [0 ])
268
291
269
292
# FIXME: Operator precedence!!
270
- lhs = Seq (lhs , operator [0 ], self .parse_pipeline ())
293
+ if isinstance (self .look (), tuple ):
294
+ lhs = self .parse (('{' , '}' ))
295
+ else :
296
+ lhs = Seq (lhs , operator [0 ], self .parse_pipeline (), seq_type )
297
+ seq_type = None
298
+
299
+ if not stack .empty ():
300
+ raise ValueError ("missing token to %r" % stack .peek ())
271
301
272
302
return lhs
0 commit comments