Skip to content

Commit 2bc7117

Browse files
committed
[llvm-lit] Initial draft of curly brace implementation
This is a draft of the parsing implementation to support curly brace syntax in lit's internal shell.
1 parent 7c4c72b commit 2bc7117

File tree

3 files changed

+37
-6
lines changed

3 files changed

+37
-6
lines changed

llvm/utils/lit/lit/ShCommands.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,15 @@ def toShell(self, file, pipefail=False):
9292

9393

9494
class Seq:
95-
def __init__(self, lhs, op, rhs):
95+
def __init__(self, lhs, op, rhs, seq_type):
9696
assert op in (";", "&", "||", "&&")
9797
self.op = op
9898
self.lhs = lhs
9999
self.rhs = rhs
100+
self.type = seq_type
100101

101102
def __repr__(self):
102-
return "Seq(%r, %r, %r)" % (self.lhs, self.op, self.rhs)
103+
return "Seq(%r, %r, %r, %r)" % (self.lhs, self.op, self.rhs, self.type)
103104

104105
def __eq__(self, other):
105106
if not isinstance(other, Seq):

llvm/utils/lit/lit/ShUtil.py

+33-3
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,11 @@ def lex_one_token(self):
157157
lex_one_token - Lex a single 'sh' token."""
158158

159159
c = self.eat()
160+
if c == "{" or c == "}":
161+
return (c,)
160162
if c == ";":
163+
if self.maybe_eat("}") or (self.maybe_eat(" ") and self.maybe_eat("}")):
164+
return("}",)
161165
return (c,)
162166
if c == "|":
163167
if self.maybe_eat("|"):
@@ -200,6 +204,8 @@ def __init__(self, data, win32Escapes=False, pipefail=False):
200204
self.data = data
201205
self.pipefail = pipefail
202206
self.tokens = ShLexer(data, win32Escapes=win32Escapes).lex()
207+
self.brace_stack = []
208+
self.brace_dict = {'{': '}'}
203209

204210
def lex(self):
205211
for item in self.tokens:
@@ -255,18 +261,42 @@ def parse_pipeline(self):
255261
self.lex()
256262
commands.append(self.parse_command())
257263
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])
258278

259-
def parse(self):
260-
lhs = self.parse_pipeline()
279+
else:
280+
lhs = self.parse_pipeline()
261281

262282
while self.look():
263283
operator = self.lex()
264284
assert isinstance(operator, tuple) and len(operator) == 1
265285

286+
if operator == self.brace_dict[self.brace_stack.peek()]:
287+
break
288+
266289
if not self.look():
267290
raise ValueError("missing argument to operator %r" % operator[0])
268291

269292
# 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())
271301

272302
return lhs

llvm/utils/lit/lit/TestRunner.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ def executeScriptInternal(
10561056
ln = command
10571057
try:
10581058
cmds.append(
1059-
ShUtil.ShParser(ln, litConfig.isWindows, test.config.pipefail).parse()
1059+
ShUtil.ShParser(ln, litConfig.isWindows, test.config.pipefail).parse(None)
10601060
)
10611061
except:
10621062
raise ScriptFatal(

0 commit comments

Comments
 (0)