parent
2ff69b20df
commit
fa2e096aa0
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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'}''')
|
||||
|
|
Loading…
Reference in New Issue