diff options
Diffstat (limited to 'mesonbuild/interpreter')
-rw-r--r-- | mesonbuild/interpreter/__init__.py | 4 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreter.py | 2 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/__init__.py | 4 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/array.py | 103 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/dict.py | 87 |
5 files changed, 200 insertions, 0 deletions
diff --git a/mesonbuild/interpreter/__init__.py b/mesonbuild/interpreter/__init__.py index c93dbc9..2269837 100644 --- a/mesonbuild/interpreter/__init__.py +++ b/mesonbuild/interpreter/__init__.py @@ -35,7 +35,9 @@ __all__ = [ 'ExternalProgramHolder', 'extract_required_kwarg', + 'ArrayHolder', 'BooleanHolder', + 'DictHolder', 'IntegerHolder', 'StringHolder', ] @@ -49,7 +51,9 @@ from .interpreterobjects import (ExecutableHolder, BuildTargetHolder, CustomTarg extract_required_kwarg) from .primitives import ( + ArrayHolder, BooleanHolder, + DictHolder, IntegerHolder, StringHolder, ) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index b2774f6..f0b650b 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -386,6 +386,8 @@ class Interpreter(InterpreterBase, HoldableObject): ''' self.holder_map.update({ # Primitives + list: P_OBJ.ArrayHolder, + dict: P_OBJ.DictHolder, int: P_OBJ.IntegerHolder, bool: P_OBJ.BooleanHolder, str: P_OBJ.StringHolder, diff --git a/mesonbuild/interpreter/primitives/__init__.py b/mesonbuild/interpreter/primitives/__init__.py index d6c0795..d876f56 100644 --- a/mesonbuild/interpreter/primitives/__init__.py +++ b/mesonbuild/interpreter/primitives/__init__.py @@ -2,13 +2,17 @@ # SPDX-license-identifier: Apache-2.0 __all__ = [ + 'ArrayHolder', 'BooleanHolder', + 'DictHolder', 'IntegerHolder', 'StringHolder', 'MesonVersionString', 'MesonVersionStringHolder', ] +from .array import ArrayHolder from .boolean import BooleanHolder +from .dict import DictHolder from .integer import IntegerHolder from .string import StringHolder, MesonVersionString, MesonVersionStringHolder diff --git a/mesonbuild/interpreter/primitives/array.py b/mesonbuild/interpreter/primitives/array.py new file mode 100644 index 0000000..566dff9 --- /dev/null +++ b/mesonbuild/interpreter/primitives/array.py @@ -0,0 +1,103 @@ +# Copyright 2021 The Meson development team +# SPDX-license-identifier: Apache-2.0 + +import typing as T + +from ...interpreterbase import ( + ObjectHolder, + IterableObject, + MesonOperator, + typed_operator, + noKwargs, + noPosargs, + noArgsFlattening, + typed_pos_args, + + TYPE_var, + TYPE_kwargs, + + InvalidArguments, +) + +if T.TYPE_CHECKING: + # Object holders need the actual interpreter + from ...interpreter import Interpreter + +class ArrayHolder(ObjectHolder[T.List[TYPE_var]], IterableObject): + def __init__(self, obj: T.List[TYPE_var], interpreter: 'Interpreter') -> None: + super().__init__(obj, interpreter) + self.methods.update({ + 'contains': self.contains_method, + 'length': self.length_method, + 'get': self.get_method, + }) + + + self.trivial_operators.update({ + MesonOperator.EQUALS: (list, lambda x: self.held_object == x), + MesonOperator.NOT_EQUALS: (list, lambda x: self.held_object != x), + MesonOperator.IN: (object, lambda x: x in self.held_object), + MesonOperator.NOT_IN: (object, lambda x: x not in self.held_object), + }) + + # Use actual methods for functions that require additional checks + self.operators.update({ + MesonOperator.PLUS: self.op_plus, + MesonOperator.INDEX: self.op_index, + }) + + def display_name(self) -> str: + return 'array' + + def iter_tuple_size(self) -> None: + return None + + def iter_self(self) -> T.Iterator[TYPE_var]: + return iter(self.held_object) + + def size(self) -> int: + return len(self.held_object) + + @noArgsFlattening + @noKwargs + @typed_pos_args('array.contains', object) + def contains_method(self, args: T.Tuple[object], kwargs: TYPE_kwargs) -> bool: + def check_contains(el: T.List[TYPE_var]) -> bool: + for element in el: + if isinstance(element, list): + found = check_contains(element) + if found: + return True + if element == args[0]: + return True + return False + return check_contains(self.held_object) + + @noKwargs + @noPosargs + def length_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int: + return len(self.held_object) + + @noArgsFlattening + @noKwargs + @typed_pos_args('array.get', int, optargs=[object]) + def get_method(self, args: T.Tuple[int, T.Optional[TYPE_var]], kwargs: TYPE_kwargs) -> TYPE_var: + index = args[0] + if index < -len(self.held_object) or index >= len(self.held_object): + if args[1] is None: + raise InvalidArguments(f'Array index {index} is out of bounds for array of size {len(self.held_object)}.') + return args[1] + return self.held_object[index] + + @typed_operator(MesonOperator.PLUS, object) + def op_plus(self, other: TYPE_var) -> T.List[TYPE_var]: + if not isinstance(other, list): + other = [other] + return self.held_object + other + + @typed_operator(MesonOperator.INDEX, int) + def op_index(self, other: int) -> TYPE_var: + try: + return self.held_object[other] + except IndexError: + raise InvalidArguments(f'Index {other} out of bounds of array of size {len(self.held_object)}.') diff --git a/mesonbuild/interpreter/primitives/dict.py b/mesonbuild/interpreter/primitives/dict.py new file mode 100644 index 0000000..24f4d21 --- /dev/null +++ b/mesonbuild/interpreter/primitives/dict.py @@ -0,0 +1,87 @@ +# Copyright 2021 The Meson development team +# SPDX-license-identifier: Apache-2.0 + +import typing as T + +from ...interpreterbase import ( + ObjectHolder, + IterableObject, + MesonOperator, + typed_operator, + noKwargs, + noPosargs, + noArgsFlattening, + typed_pos_args, + + TYPE_var, + TYPE_kwargs, + + InvalidArguments, +) + +if T.TYPE_CHECKING: + # Object holders need the actual interpreter + from ...interpreter import Interpreter + +class DictHolder(ObjectHolder[T.Dict[str, TYPE_var]], IterableObject): + def __init__(self, obj: T.Dict[str, TYPE_var], interpreter: 'Interpreter') -> None: + super().__init__(obj, interpreter) + self.methods.update({ + 'has_key': self.has_key_method, + 'keys': self.keys_method, + 'get': self.get_method, + }) + + self.trivial_operators.update({ + # Arithmetic + MesonOperator.PLUS: (dict, lambda x: {**self.held_object, **x}), + + # Comparison + MesonOperator.EQUALS: (dict, lambda x: self.held_object == x), + MesonOperator.NOT_EQUALS: (dict, lambda x: self.held_object != x), + MesonOperator.IN: (str, lambda x: x in self.held_object), + MesonOperator.NOT_IN: (str, lambda x: x not in self.held_object), + }) + + # Use actual methods for functions that require additional checks + self.operators.update({ + MesonOperator.INDEX: self.op_index, + }) + + def display_name(self) -> str: + return 'dict' + + def iter_tuple_size(self) -> int: + return 2 + + def iter_self(self) -> T.Iterator[T.Tuple[str, TYPE_var]]: + return iter(self.held_object.items()) + + def size(self) -> int: + return len(self.held_object) + + @noKwargs + @typed_pos_args('dict.has_key', str) + def has_key_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool: + return args[0] in self.held_object + + @noKwargs + @noPosargs + def keys_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[str]: + return sorted(self.held_object) + + @noArgsFlattening + @noKwargs + @typed_pos_args('dict.get', str, optargs=[object]) + def get_method(self, args: T.Tuple[str, T.Optional[TYPE_var]], kwargs: TYPE_kwargs) -> TYPE_var: + if args[0] in self.held_object: + return self.held_object[args[0]] + if args[1] is not None: + return args[1] + raise InvalidArguments(f'Key {args[0]!r} is not in the dictionary.') + + @typed_operator(MesonOperator.INDEX, str) + def op_index(self, other: str) -> TYPE_var: + if other not in self.held_object: + raise InvalidArguments(f'Key {other} is not in the dictionary.') + return self.held_object[other] |