From a816e1c1fa2f70440e82b96eb027588c60de918b Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 17 Jul 2018 16:47:41 -0400 Subject: [PATCH] Interpreter: Add 'continue' and 'break' keywords Closes: #3601 --- mesonbuild/interpreterbase.py | 24 ++++++++++++++++++++++-- mesonbuild/mparser.py | 14 ++++++++++++-- test cases/common/64 foreach/meson.build | 13 +++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 22bb95bd4..c0064ab0d 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -300,6 +300,12 @@ class InvalidArguments(InterpreterException): class SubdirDoneRequest(BaseException): pass +class ContinueRequest(BaseException): + pass + +class BreakRequest(BaseException): + pass + class InterpreterObject: def __init__(self): self.methods = {} @@ -453,6 +459,10 @@ class InterpreterBase: return self.evaluate_indexing(cur) elif isinstance(cur, mparser.TernaryNode): return self.evaluate_ternary(cur) + elif isinstance(cur, mparser.ContinueNode): + raise ContinueRequest() + elif isinstance(cur, mparser.BreakNode): + raise BreakRequest() elif self.is_elementary_type(cur): return cur else: @@ -641,7 +651,12 @@ The result of this is undefined and will become a hard error in a future Meson r return items for item in items: self.set_variable(varname, item) - self.evaluate_codeblock(node.block) + try: + self.evaluate_codeblock(node.block) + except ContinueRequest: + continue + except BreakRequest: + break elif isinstance(items, dict): if len(node.varnames) != 2: raise InvalidArguments('Foreach on dict unpacks key and value') @@ -650,7 +665,12 @@ The result of this is undefined and will become a hard error in a future Meson r for key, value in items.items(): self.set_variable(node.varnames[0].value, key) self.set_variable(node.varnames[1].value, value) - self.evaluate_codeblock(node.block) + try: + self.evaluate_codeblock(node.block) + except ContinueRequest: + continue + except BreakRequest: + break else: raise InvalidArguments('Items of foreach loop must be an array or a dict') diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 429f0146a..be5c807c4 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -91,8 +91,8 @@ class Lexer: self.code = code self.keywords = {'true', 'false', 'if', 'else', 'elif', 'endif', 'and', 'or', 'not', 'foreach', 'endforeach', - 'in'} - self.future_keywords = {'continue', 'break', 'return'} + 'in', 'continue', 'break'} + self.future_keywords = {'return'} self.token_specification = [ # Need to be sorted longest to shortest. ('ignore', re.compile(r'[ \t]')), @@ -243,6 +243,12 @@ class StringNode(ElementaryNode): def __str__(self): return "String node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno) +class ContinueNode(ElementaryNode): + pass + +class BreakNode(ElementaryNode): + pass + class ArrayNode: def __init__(self, args): self.subdir = args.subdir @@ -759,6 +765,10 @@ class Parser: block = self.foreachblock() self.block_expect('endforeach', block_start) return block + if self.accept('continue'): + return ContinueNode(self.current) + if self.accept('break'): + return BreakNode(self.current) return self.statement() def codeblock(self): diff --git a/test cases/common/64 foreach/meson.build b/test cases/common/64 foreach/meson.build index e633de887..7084e8003 100644 --- a/test cases/common/64 foreach/meson.build +++ b/test cases/common/64 foreach/meson.build @@ -18,3 +18,16 @@ foreach i : tests # we definitely don't want that. tests = ['test4', 'prog4', 'prog4.c'] endforeach + +items = ['a', 'continue', 'b', 'break', 'c'] +result = [] +foreach i : items + if i == 'continue' + continue + elif i == 'break' + break + endif + result += i +endforeach + +assert(result == ['a', 'b'], 'Continue or break in foreach failed')