diff options
author | Xavier Claessens <xavier.claessens@collabora.com> | 2018-07-17 13:54:56 -0400 |
---|---|---|
committer | Xavier Claessens <xavier.claessens@collabora.com> | 2018-10-04 20:14:37 -0400 |
commit | fa2e096aa00175b12dd3fa9e9adf4879637ee83e (patch) | |
tree | 9cc3bae5a841335486ac701aa3cd58f0588d585a | |
parent | 2ff69b20df0864182fdf2b146d29dc67d0cb9a5b (diff) | |
download | meson-fa2e096aa00175b12dd3fa9e9adf4879637ee83e.zip meson-fa2e096aa00175b12dd3fa9e9adf4879637ee83e.tar.gz meson-fa2e096aa00175b12dd3fa9e9adf4879637ee83e.tar.bz2 |
Interpreter: Add "in" and "not in" operators
Closes: #3600
-rw-r--r-- | mesonbuild/interpreter.py | 9 | ||||
-rw-r--r-- | mesonbuild/interpreterbase.py | 19 | ||||
-rw-r--r-- | mesonbuild/mparser.py | 11 | ||||
-rw-r--r-- | test cases/common/17 comparison/meson.build | 15 |
4 files changed, 43 insertions, 11 deletions
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c05b92a..2e4faa1 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -29,6 +29,7 @@ from .interpreterbase import check_stringlist, flatten, noPosargs, noKwargs, str from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs +from .interpreterbase import ObjectHolder from .modules import ModuleReturnValue import os, shutil, uuid @@ -57,14 +58,6 @@ def stringifyUserArguments(args): raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.') -class ObjectHolder: - def __init__(self, obj, subproject=None): - self.held_object = obj - self.subproject = subproject - - def __repr__(self): - return '<Holder: {!r}>'.format(self.held_object) - class FeatureOptionHolder(InterpreterObject, ObjectHolder): def __init__(self, env, option): InterpreterObject.__init__(self) diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 1c74eeb..22bb95b 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -21,6 +21,14 @@ from . import environment, dependencies import os, copy, re, types from functools import wraps +class ObjectHolder: + def __init__(self, obj, subproject=None): + self.held_object = obj + self.subproject = subproject + + def __repr__(self): + return '<Holder: {!r}>'.format(self.held_object) + # Decorators for method calls. def check_stringlist(a, msg='Arguments must be strings.'): @@ -487,6 +495,13 @@ class InterpreterBase: return False return True + def evaluate_in(self, val1, val2): + if not isinstance(val1, (str, int, float, ObjectHolder)): + raise InvalidArguments('lvalue of "in" operator must be a string, integer, float, or object') + if not isinstance(val2, (list, dict)): + raise InvalidArguments('rvalue of "in" operator must be an array or a dict') + return val1 in val2 + def evaluate_comparison(self, node): val1 = self.evaluate_statement(node.left) if is_disabler(val1): @@ -494,6 +509,10 @@ class InterpreterBase: val2 = self.evaluate_statement(node.right) if is_disabler(val2): return val2 + if node.ctype == 'in': + return self.evaluate_in(val1, val2) + elif node.ctype == 'notin': + return not self.evaluate_in(val1, val2) valid = self.validate_comparison_types(val1, val2) # Ordering comparisons of different types isn't allowed since PR #1810 # (0.41.0). Since PR #2884 we also warn about equality comparisons of diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 9af6dac..429f014 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -90,8 +90,9 @@ class Lexer: def __init__(self, code): self.code = code self.keywords = {'true', 'false', 'if', 'else', 'elif', - 'endif', 'and', 'or', 'not', 'foreach', 'endforeach'} - self.future_keywords = {'continue', 'break', 'in', 'return'} + 'endif', 'and', 'or', 'not', 'foreach', 'endforeach', + 'in'} + self.future_keywords = {'continue', 'break', 'return'} self.token_specification = [ # Need to be sorted longest to shortest. ('ignore', re.compile(r'[ \t]')), @@ -436,7 +437,9 @@ comparison_map = {'equal': '==', 'lt': '<', 'le': '<=', 'gt': '>', - 'ge': '>=' + 'ge': '>=', + 'in': 'in', + 'notin': 'not in', } # Recursive descent parser for Meson's definition language. @@ -543,6 +546,8 @@ class Parser: for nodename, operator_type in comparison_map.items(): if self.accept(nodename): return ComparisonNode(operator_type, left, self.e5()) + if self.accept('not') and self.accept('in'): + return ComparisonNode('notin', left, self.e5()) return left def e5(self): diff --git a/test cases/common/17 comparison/meson.build b/test cases/common/17 comparison/meson.build index fb641ed..bba0168 100644 --- a/test cases/common/17 comparison/meson.build +++ b/test cases/common/17 comparison/meson.build @@ -137,3 +137,18 @@ assert(2 != 'st', 'not equal') assert(not ([] == 'st'), 'not equal') assert(not ([] == 1), 'not equal') assert(not (2 == 'st'), 'not equal') + +# "in" and "not in" operators + +assert(1 in [1, 2], '''1 should be in [1, 2]''') +assert(3 not in [1, 2], '''3 shouldn't be in [1, 2]''') +assert(not (3 in [1, 2]), '''3 shouldn't be in [1, 2]''') + +assert('b' in ['a', 'b'], ''''b' should be in ['a', 'b']''') +assert('c' not in ['a', 'b'], ''''c' shouldn't be in ['a', 'b']''') + +assert(exe1 in [exe1, exe2], ''''exe1 should be in [exe1, exe2]''') +assert(exe3 not in [exe1, exe2], ''''exe3 shouldn't be in [exe1, exe2]''') + +assert('a' in {'a': 'b'}, '''1 should be in {'a': 'b'}''') +assert('b' not in {'a': 'b'}, '''1 should be in {'a': 'b'}''') |