diff --git a/llvm/utils/lit/lit/BooleanExpression.py b/llvm/utils/lit/lit/BooleanExpression.py --- a/llvm/utils/lit/lit/BooleanExpression.py +++ b/llvm/utils/lit/lit/BooleanExpression.py @@ -9,13 +9,19 @@ # and_expr :: not_expr ('&&' not_expr)* # not_expr :: '!' not_expr # '(' or_expr ')' + # match_expr + # match_expr :: regex # identifier + # regex match_expr + # identifier match_expr # identifier :: [-+=._a-zA-Z0-9]+ + # regex :: '{{' any-regex '}}' # Evaluates `string` as a boolean expression. # Returns True or False. Throws a ValueError on syntax error. # # Variables in `variables` are true. + # Regexes that match any variable in `variables` are true. # Substrings of `triple` are true. # 'true' is true. # All other identifiers are false. @@ -41,7 +47,7 @@ END = object() # Tokenization pattern. - Pattern = re.compile(r'\A\s*([()]|[-+=._a-zA-Z0-9]+|&&|\|\||!)\s*(.*)\Z') + Pattern = re.compile(r'\A\s*([()]|&&|\|\||!|(?:[-+=._a-zA-Z0-9]+|\{\{.+?\}\})+)\s*(.*)\Z') @staticmethod def tokenize(string): @@ -86,6 +92,18 @@ return False return True + def parseMATCH(self): + regex = '' + for part in filter(None, re.split(r'(\{\{.+?\}\})', self.token)): + if part.startswith('{{'): + assert part.endswith('}}') + regex += part[2:-2] + else: + regex += re.escape(part) + regex = re.compile(regex) + self.value = self.token in self.triple or any(regex.fullmatch(var) for var in self.variables) + self.token = next(self.tokens) + def parseNOT(self): if self.accept('!'): self.parseNOT() @@ -97,9 +115,7 @@ raise ValueError("expected: '!' or '(' or identifier\nhave: %s" % self.quote(self.token)) else: - self.value = (self.token in self.variables or - self.token in self.triple) - self.token = next(self.tokens) + self.parseMATCH() def parseAND(self): self.parseNOT() @@ -143,12 +159,20 @@ self.assertTrue(BooleanExpression.evaluate('under_score', variables)) self.assertTrue(BooleanExpression.evaluate('e=quals', variables)) self.assertTrue(BooleanExpression.evaluate('d1g1ts', variables)) + self.assertTrue(BooleanExpression.evaluate('{{its.+}}', variables)) + self.assertTrue(BooleanExpression.evaluate('{{false-[lo]+-true}}', variables)) + self.assertTrue(BooleanExpression.evaluate('{{(true|false)-lol-(true|false)}}', variables)) + self.assertTrue(BooleanExpression.evaluate('d1g{{[0-9]}}ts', variables)) + self.assertTrue(BooleanExpression.evaluate('d1g{{[0-9]}}t{{[a-z]}}', variables)) + self.assertTrue(BooleanExpression.evaluate('{{d}}1g{{[0-9]}}t{{[a-z]}}', variables)) + self.assertTrue(BooleanExpression.evaluate('d1{{(g|1)+}}ts', variables)) self.assertFalse(BooleanExpression.evaluate('false', variables)) self.assertFalse(BooleanExpression.evaluate('True', variables)) self.assertFalse(BooleanExpression.evaluate('true-ish', variables)) self.assertFalse(BooleanExpression.evaluate('not_true', variables)) self.assertFalse(BooleanExpression.evaluate('tru', variables)) + self.assertFalse(BooleanExpression.evaluate('{{its-true.+}}', variables)) def test_triple(self): triple = 'arch-vendor-os' @@ -248,5 +272,13 @@ "have: ')'\n" + "in expression: '( )'") + self.checkException("abc{{def", + "couldn't parse text: '{{def'\n" + + "in expression: 'abc{{def'") + + self.checkException("{{}}", + "couldn't parse text: '{{}}'\n" + + "in expression: '{{}}'") + if __name__ == '__main__': unittest.main()