diff options
Diffstat (limited to 'mesonbuild/interpreter')
-rw-r--r-- | mesonbuild/interpreter/compiler.py | 82 | ||||
-rw-r--r-- | mesonbuild/interpreter/dependencyfallbacks.py | 16 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreter.py | 92 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreterobjects.py | 168 | ||||
-rw-r--r-- | mesonbuild/interpreter/kwargs.py | 2 | ||||
-rw-r--r-- | mesonbuild/interpreter/mesonmain.py | 67 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/array.py | 37 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/boolean.py | 26 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/dict.py | 43 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/integer.py | 53 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/range.py | 7 | ||||
-rw-r--r-- | mesonbuild/interpreter/primitives/string.py | 79 | ||||
-rw-r--r-- | mesonbuild/interpreter/type_checking.py | 25 |
13 files changed, 335 insertions, 362 deletions
diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py index 8aeac8a..57e9499 100644 --- a/mesonbuild/interpreter/compiler.py +++ b/mesonbuild/interpreter/compiler.py @@ -19,7 +19,7 @@ from ..compilers import SUFFIX_TO_LANG, RunResult from ..compilers.compilers import CompileCheckMode from ..interpreterbase import (ObjectHolder, noPosargs, noKwargs, FeatureNew, FeatureNewKwargs, disablerIfNotFound, - InterpreterException) + InterpreterException, InterpreterObject) from ..interpreterbase.decorators import ContainerTypeInfo, typed_kwargs, KwargInfo, typed_pos_args from ..options import OptionKey from .interpreterobjects import (extract_required_kwarg, extract_search_dirs) @@ -110,29 +110,28 @@ class _TestMode(enum.Enum): class TryRunResultHolder(ObjectHolder['RunResult']): def __init__(self, res: 'RunResult', interpreter: 'Interpreter'): super().__init__(res, interpreter) - self.methods.update({'returncode': self.returncode_method, - 'compiled': self.compiled_method, - 'stdout': self.stdout_method, - 'stderr': self.stderr_method, - }) @noPosargs @noKwargs + @InterpreterObject.method('returncode') def returncode_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> int: return self.held_object.returncode @noPosargs @noKwargs + @InterpreterObject.method('compiled') def compiled_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: return self.held_object.compiled @noPosargs @noKwargs + @InterpreterObject.method('stdout') def stdout_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.held_object.stdout @noPosargs @noKwargs + @InterpreterObject.method('stderr') def stderr_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.held_object.stderr @@ -190,40 +189,6 @@ class CompilerHolder(ObjectHolder['Compiler']): def __init__(self, compiler: 'Compiler', interpreter: 'Interpreter'): super().__init__(compiler, interpreter) self.environment = self.env - self.methods.update({'compiles': self.compiles_method, - 'links': self.links_method, - 'get_id': self.get_id_method, - 'get_linker_id': self.get_linker_id_method, - 'compute_int': self.compute_int_method, - 'sizeof': self.sizeof_method, - 'get_define': self.get_define_method, - 'has_define': self.has_define_method, - 'check_header': self.check_header_method, - 'has_header': self.has_header_method, - 'has_header_symbol': self.has_header_symbol_method, - 'run': self.run_method, - 'has_function': self.has_function_method, - 'has_member': self.has_member_method, - 'has_members': self.has_members_method, - 'has_type': self.has_type_method, - 'alignment': self.alignment_method, - 'version': self.version_method, - 'cmd_array': self.cmd_array_method, - 'find_library': self.find_library_method, - 'has_argument': self.has_argument_method, - 'has_function_attribute': self.has_func_attribute_method, - 'get_supported_function_attributes': self.get_supported_function_attributes_method, - 'has_multi_arguments': self.has_multi_arguments_method, - 'get_supported_arguments': self.get_supported_arguments_method, - 'first_supported_argument': self.first_supported_argument_method, - 'has_link_argument': self.has_link_argument_method, - 'has_multi_link_arguments': self.has_multi_link_arguments_method, - 'get_supported_link_arguments': self.get_supported_link_arguments_method, - 'first_supported_link_argument': self.first_supported_link_argument_method, - 'symbols_have_underscore_prefix': self.symbols_have_underscore_prefix_method, - 'get_argument_syntax': self.get_argument_syntax_method, - 'preprocess': self.preprocess_method, - }) @property def compiler(self) -> 'Compiler': @@ -254,11 +219,13 @@ class CompilerHolder(ObjectHolder['Compiler']): @noPosargs @noKwargs + @InterpreterObject.method('version') def version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.compiler.version @noPosargs @noKwargs + @InterpreterObject.method('cmd_array') def cmd_array_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> T.List[str]: return self.compiler.exelist @@ -289,6 +256,7 @@ class CompilerHolder(ObjectHolder['Compiler']): _ARGS_KW, _DEPENDENCIES_KW, ) + @InterpreterObject.method('alignment') def alignment_method(self, args: T.Tuple[str], kwargs: 'AlignmentKw') -> int: typename = args[0] deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=self.compiler.is_cross) @@ -302,6 +270,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.run', (str, mesonlib.File)) @typed_kwargs('compiler.run', *_COMPILES_KWS) + @InterpreterObject.method('run') def run_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> 'RunResult': if self.compiler.language not in {'d', 'c', 'cpp', 'objc', 'objcpp', 'fortran'}: FeatureNew.single_use(f'compiler.run for {self.compiler.get_display_language()} language', @@ -338,17 +307,20 @@ class CompilerHolder(ObjectHolder['Compiler']): @noPosargs @noKwargs + @InterpreterObject.method('get_id') def get_id_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.compiler.get_id() @noPosargs @noKwargs @FeatureNew('compiler.get_linker_id', '0.53.0') + @InterpreterObject.method('get_linker_id') def get_linker_id_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.compiler.get_linker_id() @noPosargs @noKwargs + @InterpreterObject.method('symbols_have_underscore_prefix') def symbols_have_underscore_prefix_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: ''' Check if the compiler prefixes _ (underscore) to global C symbols @@ -358,6 +330,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.has_member', str, str) @typed_kwargs('compiler.has_member', _HAS_REQUIRED_KW, *_COMMON_KWS) + @InterpreterObject.method('has_member') def has_member_method(self, args: T.Tuple[str, str], kwargs: 'HasKW') -> bool: typename, membername = args disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False) @@ -383,6 +356,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.has_members', str, varargs=str, min_varargs=1) @typed_kwargs('compiler.has_members', _HAS_REQUIRED_KW, *_COMMON_KWS) + @InterpreterObject.method('has_members') def has_members_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'HasKW') -> bool: typename, membernames = args members = mlog.bold(', '.join([f'"{m}"' for m in membernames])) @@ -410,6 +384,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.has_function', str) @typed_kwargs('compiler.has_function', _HAS_REQUIRED_KW, *_COMMON_KWS) + @InterpreterObject.method('has_function') def has_function_method(self, args: T.Tuple[str], kwargs: 'HasKW') -> bool: funcname = args[0] disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False) @@ -433,6 +408,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.has_type', str) @typed_kwargs('compiler.has_type', _HAS_REQUIRED_KW, *_COMMON_KWS) + @InterpreterObject.method('has_type') def has_type_method(self, args: T.Tuple[str], kwargs: 'HasKW') -> bool: typename = args[0] disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False) @@ -462,6 +438,7 @@ class CompilerHolder(ObjectHolder['Compiler']): KwargInfo('guess', (int, NoneType)), *_COMMON_KWS, ) + @InterpreterObject.method('compute_int') def compute_int_method(self, args: T.Tuple[str], kwargs: 'ComputeIntKW') -> int: expression = args[0] extra_args = functools.partial(self._determine_args, kwargs) @@ -475,6 +452,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.sizeof', str) @typed_kwargs('compiler.sizeof', *_COMMON_KWS) + @InterpreterObject.method('sizeof') def sizeof_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> int: element = args[0] extra_args = functools.partial(self._determine_args, kwargs) @@ -489,6 +467,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @FeatureNew('compiler.get_define', '0.40.0') @typed_pos_args('compiler.get_define', str) @typed_kwargs('compiler.get_define', *_COMMON_KWS) + @InterpreterObject.method('get_define') def get_define_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> str: element = args[0] extra_args = functools.partial(self._determine_args, kwargs) @@ -504,6 +483,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @FeatureNew('compiler.has_define', '1.3.0') @typed_pos_args('compiler.has_define', str) @typed_kwargs('compiler.has_define', *_COMMON_KWS) + @InterpreterObject.method('has_define') def has_define_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> bool: define_name = args[0] extra_args = functools.partial(self._determine_args, kwargs) @@ -519,6 +499,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.compiles', (str, mesonlib.File)) @typed_kwargs('compiler.compiles', *_COMPILES_KWS) + @InterpreterObject.method('compiles') def compiles_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> bool: code = args[0] testname = kwargs['name'] @@ -555,6 +536,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.links', (str, mesonlib.File)) @typed_kwargs('compiler.links', *_COMPILES_KWS) + @InterpreterObject.method('links') def links_method(self, args: T.Tuple['mesonlib.FileOrString'], kwargs: 'CompileKW') -> bool: code = args[0] testname = kwargs['name'] @@ -606,6 +588,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @FeatureNew('compiler.check_header', '0.47.0') @typed_pos_args('compiler.check_header', str) @typed_kwargs('compiler.check_header', *_HEADER_KWS) + @InterpreterObject.method('check_header') def check_header_method(self, args: T.Tuple[str], kwargs: 'HeaderKW') -> bool: hname = args[0] disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False) @@ -648,11 +631,13 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.has_header', str) @typed_kwargs('compiler.has_header', *_HEADER_KWS) + @InterpreterObject.method('has_header') def has_header_method(self, args: T.Tuple[str], kwargs: 'HeaderKW') -> bool: return self._has_header_impl(args[0], kwargs) @typed_pos_args('compiler.has_header_symbol', str, str) @typed_kwargs('compiler.has_header_symbol', *_HEADER_KWS) + @InterpreterObject.method('has_header_symbol') def has_header_symbol_method(self, args: T.Tuple[str, str], kwargs: 'HeaderKW') -> bool: hname, symbol = args disabled, required, feature = extract_required_kwarg(kwargs, self.subproject, default=False) @@ -692,6 +677,7 @@ class CompilerHolder(ObjectHolder['Compiler']): KwargInfo('dirs', ContainerTypeInfo(list, str), listify=True, default=[]), *(k.evolve(name=f'header_{k.name}') for k in _HEADER_KWS) ) + @InterpreterObject.method('find_library') def find_library_method(self, args: T.Tuple[str], kwargs: 'FindLibraryKW') -> 'dependencies.ExternalLibrary': # TODO add dependencies support? libname = args[0] @@ -772,12 +758,14 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_pos_args('compiler.has_argument', str) @typed_kwargs('compiler.has_argument', _HAS_REQUIRED_KW) + @InterpreterObject.method('has_argument') def has_argument_method(self, args: T.Tuple[str], kwargs: 'HasArgumentKW') -> bool: return self._has_argument_impl([args[0]], kwargs=kwargs) @typed_pos_args('compiler.has_multi_arguments', varargs=str) @typed_kwargs('compiler.has_multi_arguments', _HAS_REQUIRED_KW) @FeatureNew('compiler.has_multi_arguments', '0.37.0') + @InterpreterObject.method('has_multi_arguments') def has_multi_arguments_method(self, args: T.Tuple[T.List[str]], kwargs: 'HasArgumentKW') -> bool: return self._has_argument_impl(args[0], kwargs=kwargs) @@ -788,6 +776,7 @@ class CompilerHolder(ObjectHolder['Compiler']): KwargInfo('checked', str, default='off', since='0.59.0', validator=in_set_validator({'warn', 'require', 'off'})), ) + @InterpreterObject.method('get_supported_arguments') def get_supported_arguments_method(self, args: T.Tuple[T.List[str]], kwargs: 'GetSupportedArgumentKw') -> T.List[str]: supported_args: T.List[str] = [] checked = kwargs['checked'] @@ -805,6 +794,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @noKwargs @typed_pos_args('compiler.first_supported_argument', varargs=str) + @InterpreterObject.method('first_supported_argument') def first_supported_argument_method(self, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[str]: for arg in args[0]: if self._has_argument_impl([arg]): @@ -816,18 +806,21 @@ class CompilerHolder(ObjectHolder['Compiler']): @FeatureNew('compiler.has_link_argument', '0.46.0') @typed_pos_args('compiler.has_link_argument', str) @typed_kwargs('compiler.has_link_argument', _HAS_REQUIRED_KW) + @InterpreterObject.method('has_link_argument') def has_link_argument_method(self, args: T.Tuple[str], kwargs: 'HasArgumentKW') -> bool: return self._has_argument_impl([args[0]], mode=_TestMode.LINKER, kwargs=kwargs) @FeatureNew('compiler.has_multi_link_argument', '0.46.0') @typed_pos_args('compiler.has_multi_link_argument', varargs=str) @typed_kwargs('compiler.has_multi_link_argument', _HAS_REQUIRED_KW) + @InterpreterObject.method('has_multi_link_arguments') def has_multi_link_arguments_method(self, args: T.Tuple[T.List[str]], kwargs: 'HasArgumentKW') -> bool: return self._has_argument_impl(args[0], mode=_TestMode.LINKER, kwargs=kwargs) @FeatureNew('compiler.get_supported_link_arguments', '0.46.0') @noKwargs @typed_pos_args('compiler.get_supported_link_arguments', varargs=str) + @InterpreterObject.method('get_supported_link_arguments') def get_supported_link_arguments_method(self, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[str]: supported_args: T.List[str] = [] for arg in args[0]: @@ -835,9 +828,10 @@ class CompilerHolder(ObjectHolder['Compiler']): supported_args.append(arg) return supported_args - @FeatureNew('compiler.first_supported_link_argument_method', '0.46.0') + @FeatureNew('compiler.first_supported_link_argument', '0.46.0') @noKwargs @typed_pos_args('compiler.first_supported_link_argument', varargs=str) + @InterpreterObject.method('first_supported_link_argument') def first_supported_link_argument_method(self, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[str]: for arg in args[0]: if self._has_argument_impl([arg], mode=_TestMode.LINKER): @@ -871,18 +865,21 @@ class CompilerHolder(ObjectHolder['Compiler']): @FeatureNew('compiler.has_function_attribute', '0.48.0') @typed_pos_args('compiler.has_function_attribute', str) @typed_kwargs('compiler.has_function_attribute', _HAS_REQUIRED_KW) + @InterpreterObject.method('has_function_attribute') def has_func_attribute_method(self, args: T.Tuple[str], kwargs: 'HasArgumentKW') -> bool: return self._has_function_attribute_impl(args[0], kwargs) @FeatureNew('compiler.get_supported_function_attributes', '0.48.0') @noKwargs @typed_pos_args('compiler.get_supported_function_attributes', varargs=str) + @InterpreterObject.method('get_supported_function_attributes') def get_supported_function_attributes_method(self, args: T.Tuple[T.List[str]], kwargs: 'TYPE_kwargs') -> T.List[str]: return [a for a in args[0] if self._has_function_attribute_impl(a)] - @FeatureNew('compiler.get_argument_syntax_method', '0.49.0') + @FeatureNew('compiler.get_argument_syntax', '0.49.0') @noPosargs @noKwargs + @InterpreterObject.method('get_argument_syntax') def get_argument_syntax_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.compiler.get_argument_syntax() @@ -897,6 +894,7 @@ class CompilerHolder(ObjectHolder['Compiler']): _DEPENDENCIES_KW.evolve(since='1.1.0'), _DEPENDS_KW.evolve(since='1.4.0'), ) + @InterpreterObject.method('preprocess') def preprocess_method(self, args: T.Tuple[T.List['mesonlib.FileOrString']], kwargs: 'PreprocessKW') -> T.List[build.CustomTargetIndex]: compiler = self.compiler.get_preprocessor() _sources: T.List[mesonlib.File] = self.interpreter.source_strings_to_files(args[0]) diff --git a/mesonbuild/interpreter/dependencyfallbacks.py b/mesonbuild/interpreter/dependencyfallbacks.py index 0ebfe3b..f415026 100644 --- a/mesonbuild/interpreter/dependencyfallbacks.py +++ b/mesonbuild/interpreter/dependencyfallbacks.py @@ -4,14 +4,12 @@ from __future__ import annotations -import copy - from .interpreterobjects import extract_required_kwarg from .. import mlog from .. import dependencies from .. import build from ..wrap import WrapMode -from ..mesonlib import extract_as_list, stringlistify, version_compare_many, listify +from ..mesonlib import extract_as_list, stringlistify, version_compare_many from ..options import OptionKey from ..dependencies import Dependency, DependencyException, NotFoundDependency from ..interpreterbase import (MesonInterpreterObject, FeatureNew, @@ -124,21 +122,17 @@ class DependencyFallbacksHolder(MesonInterpreterObject): # dependency('foo', static: true) should implicitly add # default_options: ['default_library=static'] static = kwargs.get('static') - default_options = func_kwargs.get('default_options', {}) - if static is not None and 'default_library' not in default_options: + forced_options = {} + if static is not None: default_library = 'static' if static else 'shared' mlog.log(f'Building fallback subproject with default_library={default_library}') - default_options = copy.copy(default_options) - default_options['default_library'] = default_library - func_kwargs['default_options'] = default_options + forced_options[OptionKey('default_library')] = default_library # Configure the subproject subp_name = self.subproject_name varname = self.subproject_varname func_kwargs.setdefault('version', []) - if 'default_options' in kwargs and isinstance(kwargs['default_options'], str): - func_kwargs['default_options'] = listify(kwargs['default_options']) - self.interpreter.do_subproject(subp_name, func_kwargs) + self.interpreter.do_subproject(subp_name, func_kwargs, forced_options=forced_options) return self._get_subproject_dep(subp_name, varname, kwargs) def _get_subproject(self, subp_name: str) -> T.Optional[SubprojectHolder]: diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index bf41bfb..730f3d3 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -115,6 +115,7 @@ if T.TYPE_CHECKING: from . import kwargs as kwtypes from ..backend.backends import Backend from ..interpreterbase.baseobjects import InterpreterObject, TYPE_var, TYPE_kwargs + from ..options import OptionDict from ..programs import OverrideProgram from .type_checking import SourcesVarargsType @@ -270,7 +271,7 @@ class Interpreter(InterpreterBase, HoldableObject): subproject: str = '', subdir: str = '', subproject_dir: str = 'subprojects', - default_project_options: T.Optional[T.Dict[OptionKey, str]] = None, + invoker_method_default_options: T.Optional[OptionDict] = None, ast: T.Optional[mparser.CodeBlockNode] = None, relaxations: T.Optional[T.Set[InterpreterRuleRelaxation]] = None, user_defined_options: T.Optional[coredata.SharedCMDOptions] = None, @@ -295,13 +296,12 @@ class Interpreter(InterpreterBase, HoldableObject): self.subproject_stack: T.List[str] = [] self.configure_file_outputs: T.Dict[str, int] = {} # Passed from the outside, only used in subprojects. - if default_project_options: - self.default_project_options = default_project_options if isinstance(default_project_options, str) else default_project_options.copy() - if isinstance(default_project_options, dict): - pass + if invoker_method_default_options: + assert isinstance(invoker_method_default_options, dict) + self.invoker_method_default_options = invoker_method_default_options else: - self.default_project_options = {} - self.project_default_options: T.List[str] = [] + self.invoker_method_default_options = {} + self.project_default_options: OptionDict = {} self.build_func_dict() self.build_holder_map() self.user_defined_options = user_defined_options @@ -426,6 +426,7 @@ class Interpreter(InterpreterBase, HoldableObject): build.Generator: OBJ.GeneratorHolder, build.GeneratedList: OBJ.GeneratedListHolder, build.ExtractedObjects: OBJ.GeneratedObjectsHolder, + build.OverrideExecutable: OBJ.OverrideExecutableHolder, build.RunTarget: OBJ.RunTargetHolder, build.AliasTarget: OBJ.AliasTargetHolder, build.Headers: OBJ.HeadersHolder, @@ -868,7 +869,8 @@ class Interpreter(InterpreterBase, HoldableObject): self.subprojects[subp_name] = sub return sub - def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_method: T.Optional[wrap.Method] = None) -> SubprojectHolder: + def do_subproject(self, subp_name: str, kwargs: kwtypes.DoSubproject, force_method: T.Optional[wrap.Method] = None, + forced_options: T.Optional[OptionDict] = None) -> SubprojectHolder: if subp_name == 'sub_static': pass disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) @@ -879,6 +881,16 @@ class Interpreter(InterpreterBase, HoldableObject): default_options = kwargs['default_options'] + # This in practice is only used for default_library. forced_options is the + # only case in which a meson.build file overrides the machine file or the + # command line. + if forced_options: + for k, v in forced_options.items(): + # FIXME: this should have no business poking at augments[], + # but set_option() does not do what we want + self.coredata.optstore.augments[k.evolve(subproject=subp_name)] = v + default_options = {**forced_options, **default_options} + if subp_name == '': raise InterpreterException('Subproject name must not be empty.') if subp_name[0] == '.': @@ -930,7 +942,8 @@ class Interpreter(InterpreterBase, HoldableObject): m += ['method', mlog.bold(method)] mlog.log(*m, '\n', nested=False) - methods_map: T.Dict[wrap.Method, T.Callable[[str, str, T.Dict[OptionKey, str, kwtypes.DoSubproject]], SubprojectHolder]] = { + methods_map: T.Dict[wrap.Method, T.Callable[[str, str, OptionDict, kwtypes.DoSubproject], + SubprojectHolder]] = { 'meson': self._do_subproject_meson, 'cmake': self._do_subproject_cmake, 'cargo': self._do_subproject_cargo, @@ -952,7 +965,7 @@ class Interpreter(InterpreterBase, HoldableObject): raise e def _do_subproject_meson(self, subp_name: str, subdir: str, - default_options: T.List[str], + default_options: OptionDict, kwargs: kwtypes.DoSubproject, ast: T.Optional[mparser.CodeBlockNode] = None, build_def_files: T.Optional[T.List[str]] = None, @@ -1012,7 +1025,7 @@ class Interpreter(InterpreterBase, HoldableObject): return self.subprojects[subp_name] def _do_subproject_cmake(self, subp_name: str, subdir: str, - default_options: T.List[str], + default_options: OptionDict, kwargs: kwtypes.DoSubproject) -> SubprojectHolder: from ..cmake import CMakeInterpreter with mlog.nested(subp_name): @@ -1039,13 +1052,14 @@ class Interpreter(InterpreterBase, HoldableObject): return result def _do_subproject_cargo(self, subp_name: str, subdir: str, - default_options: T.List[str], + default_options: OptionDict, kwargs: kwtypes.DoSubproject) -> SubprojectHolder: from .. import cargo FeatureNew.single_use('Cargo subproject', '1.3.0', self.subproject, location=self.current_node) mlog.warning('Cargo subproject is an experimental feature and has no backwards compatibility guarantees.', once=True, location=self.current_node) if self.environment.cargo is None: + self.add_languages(['rust'], True, MachineChoice.HOST) self.environment.cargo = cargo.Interpreter(self.environment) with mlog.nested(subp_name): ast = self.environment.cargo.interpret(subdir) @@ -1184,23 +1198,34 @@ class Interpreter(InterpreterBase, HoldableObject): self._load_option_file() self.project_default_options = kwargs['default_options'] - if isinstance(self.project_default_options, str): - self.project_default_options = [self.project_default_options] - assert isinstance(self.project_default_options, (list, dict)) if self.environment.first_invocation or (self.subproject != '' and self.subproject not in self.coredata.initialized_subprojects): if self.subproject == '': self.coredata.optstore.initialize_from_top_level_project_call(self.project_default_options, self.user_defined_options.cmd_line_options, self.environment.options) else: - invoker_method_default_options = self.default_project_options self.coredata.optstore.initialize_from_subproject_call(self.subproject, - invoker_method_default_options, + self.invoker_method_default_options, self.project_default_options, - self.user_defined_options.cmd_line_options) + self.user_defined_options.cmd_line_options, + self.environment.options) self.coredata.initialized_subprojects.add(self.subproject) if not self.is_subproject(): + # We have to activate VS before adding languages and before calling + # self.set_backend() otherwise it wouldn't be able to detect which + # vs backend version we need. But after setting default_options in case + # the project sets vs backend by default. + backend = self.coredata.optstore.get_value_for(OptionKey('backend')) + assert backend is None or isinstance(backend, str), 'for mypy' + vsenv = self.coredata.optstore.get_value_for(OptionKey('vsenv')) + assert isinstance(vsenv, bool), 'for mypy' + force_vsenv = vsenv or backend.startswith('vs') + mesonlib.setup_vsenv(force_vsenv) + self.set_backend() + + if not self.is_subproject(): + self.coredata.optstore.validate_cmd_line_options(self.user_defined_options.cmd_line_options) self.build.project_name = proj_name self.active_projectname = proj_name @@ -1270,22 +1295,9 @@ class Interpreter(InterpreterBase, HoldableObject): mlog.log('Project name:', mlog.bold(proj_name)) mlog.log('Project version:', mlog.bold(self.project_version)) - if not self.is_subproject(): - # We have to activate VS before adding languages and before calling - # self.set_backend() otherwise it wouldn't be able to detect which - # vs backend version we need. But after setting default_options in case - # the project sets vs backend by default. - backend = self.coredata.optstore.get_value_for(OptionKey('backend')) - assert backend is None or isinstance(backend, str), 'for mypy' - vsenv = self.coredata.optstore.get_value_for(OptionKey('vsenv')) - assert isinstance(vsenv, bool), 'for mypy' - force_vsenv = vsenv or backend.startswith('vs') - mesonlib.setup_vsenv(force_vsenv) - self.add_languages(proj_langs, True, MachineChoice.HOST) self.add_languages(proj_langs, False, MachineChoice.BUILD) - self.set_backend() if not self.is_subproject(): self.check_stdlibs() @@ -1528,7 +1540,7 @@ class Interpreter(InterpreterBase, HoldableObject): self.backend.allow_thin_archives[for_machine] = False else: # update new values from commandline, if it applies - self.coredata.process_compiler_options(lang, comp, self.environment, self.subproject) + self.coredata.process_compiler_options(lang, comp, self.subproject) if for_machine == MachineChoice.HOST or self.environment.is_cross_build(): logger_fun = mlog.log @@ -1589,7 +1601,7 @@ class Interpreter(InterpreterBase, HoldableObject): def program_from_overrides(self, command_names: T.List[mesonlib.FileOrString], extra_info: T.List['mlog.TV_Loggable'] - ) -> T.Optional[T.Union[ExternalProgram, OverrideProgram, build.Executable]]: + ) -> T.Optional[T.Union[ExternalProgram, OverrideProgram, build.OverrideExecutable]]: for name in command_names: if not isinstance(name, str): continue @@ -1604,7 +1616,7 @@ class Interpreter(InterpreterBase, HoldableObject): if isinstance(name, str): self.build.searched_programs.add(name) - def add_find_program_override(self, name: str, exe: T.Union[build.Executable, ExternalProgram, 'OverrideProgram']) -> None: + def add_find_program_override(self, name: str, exe: T.Union[build.OverrideExecutable, ExternalProgram, 'OverrideProgram']) -> None: if name in self.build.searched_programs: raise InterpreterException(f'Tried to override finding of executable "{name}" which has already been found.') if name in self.build.find_overrides: @@ -1623,13 +1635,13 @@ class Interpreter(InterpreterBase, HoldableObject): # the host machine. def find_program_impl(self, args: T.List[mesonlib.FileOrString], for_machine: MachineChoice = MachineChoice.HOST, - default_options: T.Optional[T.Dict[OptionKey, options.ElementaryOptionValues]] = None, + default_options: T.Optional[OptionDict] = None, required: bool = True, silent: bool = True, wanted: T.Union[str, T.List[str]] = '', search_dirs: T.Optional[T.List[str]] = None, version_arg: T.Optional[str] = '', version_func: T.Optional[ProgramVersionFunc] = None - ) -> T.Union['ExternalProgram', 'build.Executable', 'OverrideProgram']: + ) -> T.Union['ExternalProgram', 'build.OverrideExecutable', 'OverrideProgram']: args = mesonlib.listify(args) extra_info: T.List[mlog.TV_Loggable] = [] @@ -1654,7 +1666,7 @@ class Interpreter(InterpreterBase, HoldableObject): return progobj def program_lookup(self, args: T.List[mesonlib.FileOrString], for_machine: MachineChoice, - default_options: T.Optional[T.Dict[OptionKey, options.ElementaryOptionValues]], + default_options: T.Optional[OptionDict], required: bool, search_dirs: T.Optional[T.List[str]], wanted: T.Union[str, T.List[str]], @@ -1722,7 +1734,7 @@ class Interpreter(InterpreterBase, HoldableObject): return True def find_program_fallback(self, fallback: str, args: T.List[mesonlib.FileOrString], - default_options: T.Dict[OptionKey, options.ElementaryOptionValues], + default_options: OptionDict, required: bool, extra_info: T.List[mlog.TV_Loggable] ) -> T.Optional[T.Union[ExternalProgram, build.Executable, OverrideProgram]]: mlog.log('Fallback to subproject', mlog.bold(fallback), 'which provides program', @@ -3243,9 +3255,9 @@ class Interpreter(InterpreterBase, HoldableObject): def build_both_libraries(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], kwargs: kwtypes.Library) -> build.BothLibraries: shared_lib = self.build_target(node, args, kwargs, build.SharedLibrary) static_lib = self.build_target(node, args, kwargs, build.StaticLibrary) - preferred_library = self.coredata.optstore.get_value_for(OptionKey('default_both_libraries')) + preferred_library = self.coredata.optstore.get_value_for(OptionKey('default_both_libraries', subproject=self.subproject)) if preferred_library == 'auto': - preferred_library = self.coredata.optstore.get_value_for(OptionKey('default_library')) + preferred_library = self.coredata.optstore.get_value_for(OptionKey('default_library', subproject=self.subproject)) if preferred_library == 'both': preferred_library = 'shared' diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index a2fadbe..17ba989 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -15,7 +15,7 @@ from .. import mlog from ..modules import ModuleReturnValue, ModuleObject, ModuleState, ExtensionModule, NewExtensionModule from ..backend.backends import TestProtocol from ..interpreterbase import ( - ContainerTypeInfo, KwargInfo, MesonOperator, + ContainerTypeInfo, KwargInfo, InterpreterObject, MesonOperator, MesonInterpreterObject, ObjectHolder, MutableInterpreterObject, FeatureNew, FeatureDeprecated, typed_pos_args, typed_kwargs, typed_operator, @@ -32,7 +32,7 @@ if T.TYPE_CHECKING: from . import kwargs from ..cmake.interpreter import CMakeInterpreter from ..envconfig import MachineInfo - from ..interpreterbase import FeatureCheckBase, InterpreterObject, SubProject, TYPE_var, TYPE_kwargs, TYPE_nvar, TYPE_nkwargs + from ..interpreterbase import FeatureCheckBase, SubProject, TYPE_var, TYPE_kwargs, TYPE_nvar, TYPE_nkwargs from .interpreter import Interpreter from typing_extensions import TypedDict @@ -97,16 +97,6 @@ class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]): auto = T.cast('options.UserFeatureOption', self.env.coredata.optstore.get_value_object_for('auto_features')) self.held_object = copy.copy(auto) self.held_object.name = option.name - self.methods.update({'enabled': self.enabled_method, - 'disabled': self.disabled_method, - 'allowed': self.allowed_method, - 'auto': self.auto_method, - 'require': self.require_method, - 'disable_auto_if': self.disable_auto_if_method, - 'enable_auto_if': self.enable_auto_if_method, - 'disable_if': self.disable_if_method, - 'enable_if': self.enable_if_method, - }) @property def value(self) -> str: @@ -124,22 +114,26 @@ class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]): @noPosargs @noKwargs + @InterpreterObject.method('enabled') def enabled_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.value == 'enabled' @noPosargs @noKwargs + @InterpreterObject.method('disabled') def disabled_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.value == 'disabled' @noPosargs @noKwargs @FeatureNew('feature_option.allowed()', '0.59.0') + @InterpreterObject.method('allowed') def allowed_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.value != 'disabled' @noPosargs @noKwargs + @InterpreterObject.method('auto') def auto_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.value == 'auto' @@ -160,6 +154,7 @@ class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]): 'feature_option.require', _ERROR_MSG_KW, ) + @InterpreterObject.method('require') def require_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> options.UserFeatureOption: return self._disable_if(not args[0], kwargs['error_message']) @@ -169,6 +164,7 @@ class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]): 'feature_option.disable_if', _ERROR_MSG_KW, ) + @InterpreterObject.method('disable_if') def disable_if_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> options.UserFeatureOption: return self._disable_if(args[0], kwargs['error_message']) @@ -178,6 +174,7 @@ class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]): 'feature_option.enable_if', _ERROR_MSG_KW, ) + @InterpreterObject.method('enable_if') def enable_if_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> options.UserFeatureOption: if not args[0]: return copy.deepcopy(self.held_object) @@ -192,12 +189,14 @@ class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]): @FeatureNew('feature_option.disable_auto_if()', '0.59.0') @noKwargs @typed_pos_args('feature_option.disable_auto_if', bool) + @InterpreterObject.method('disable_auto_if') def disable_auto_if_method(self, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> options.UserFeatureOption: return copy.deepcopy(self.held_object) if self.value != 'auto' or not args[0] else self.as_disabled() @FeatureNew('feature_option.enable_auto_if()', '1.1.0') @noKwargs @typed_pos_args('feature_option.enable_auto_if', bool) + @InterpreterObject.method('enable_auto_if') def enable_auto_if_method(self, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> options.UserFeatureOption: return self.as_enabled() if self.value == 'auto' and args[0] else copy.deepcopy(self.held_object) @@ -220,10 +219,6 @@ class RunProcess(MesonInterpreterObject): raise AssertionError('BUG: RunProcess must be passed an ExternalProgram') self.capture = capture self.returncode, self.stdout, self.stderr = self.run_command(cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir, check) - self.methods.update({'returncode': self.returncode_method, - 'stdout': self.stdout_method, - 'stderr': self.stderr_method, - }) def run_command(self, cmd: ExternalProgram, @@ -271,16 +266,19 @@ class RunProcess(MesonInterpreterObject): @noPosargs @noKwargs + @InterpreterObject.method('returncode') def returncode_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int: return self.returncode @noPosargs @noKwargs + @InterpreterObject.method('stdout') def stdout_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.stdout @noPosargs @noKwargs + @InterpreterObject.method('stderr') def stderr_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.stderr @@ -288,11 +286,6 @@ class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], Mu def __init__(self, obj: mesonlib.EnvironmentVariables, interpreter: 'Interpreter'): super().__init__(obj, interpreter) - self.methods.update({'set': self.set_method, - 'unset': self.unset_method, - 'append': self.append_method, - 'prepend': self.prepend_method, - }) def __repr__(self) -> str: repr_str = "<{0}: {1}>" @@ -310,6 +303,7 @@ class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], Mu @typed_pos_args('environment.set', str, varargs=str, min_varargs=1) @typed_kwargs('environment.set', ENV_SEPARATOR_KW) + @InterpreterObject.method('set') def set_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args self.held_object.set(name, values, kwargs['separator']) @@ -317,11 +311,13 @@ class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], Mu @FeatureNew('environment.unset', '1.4.0') @typed_pos_args('environment.unset', str) @noKwargs + @InterpreterObject.method('unset') def unset_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> None: self.held_object.unset(args[0]) @typed_pos_args('environment.append', str, varargs=str, min_varargs=1) @typed_kwargs('environment.append', ENV_SEPARATOR_KW) + @InterpreterObject.method('append') def append_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args self.warn_if_has_name(name) @@ -329,6 +325,7 @@ class EnvironmentVariablesHolder(ObjectHolder[mesonlib.EnvironmentVariables], Mu @typed_pos_args('environment.prepend', str, varargs=str, min_varargs=1) @typed_kwargs('environment.prepend', ENV_SEPARATOR_KW) + @InterpreterObject.method('prepend') def prepend_method(self, args: T.Tuple[str, T.List[str]], kwargs: 'EnvironmentSeparatorKW') -> None: name, values = args self.warn_if_has_name(name) @@ -342,15 +339,6 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte def __init__(self, obj: build.ConfigurationData, interpreter: 'Interpreter'): super().__init__(obj, interpreter) - self.methods.update({'set': self.set_method, - 'set10': self.set10_method, - 'set_quoted': self.set_quoted_method, - 'has': self.has_method, - 'get': self.get_method, - 'keys': self.keys_method, - 'get_unquoted': self.get_unquoted_method, - 'merge_from': self.merge_from_method, - }) def __deepcopy__(self, memo: T.Dict) -> 'ConfigurationDataHolder': return ConfigurationDataHolder(copy.deepcopy(self.held_object), self.interpreter) @@ -364,12 +352,14 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte @typed_pos_args('configuration_data.set', str, (str, int, bool)) @typed_kwargs('configuration_data.set', _CONF_DATA_SET_KWS) + @InterpreterObject.method('set') def set_method(self, args: T.Tuple[str, T.Union[str, int, bool]], kwargs: 'kwargs.ConfigurationDataSet') -> None: self.__check_used() self.held_object.values[args[0]] = (args[1], kwargs['description']) @typed_pos_args('configuration_data.set_quoted', str, str) @typed_kwargs('configuration_data.set_quoted', _CONF_DATA_SET_KWS) + @InterpreterObject.method('set_quoted') def set_quoted_method(self, args: T.Tuple[str, str], kwargs: 'kwargs.ConfigurationDataSet') -> None: self.__check_used() escaped_val = '\\"'.join(args[1].split('"')) @@ -377,6 +367,7 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte @typed_pos_args('configuration_data.set10', str, (int, bool)) @typed_kwargs('configuration_data.set10', _CONF_DATA_SET_KWS) + @InterpreterObject.method('set10') def set10_method(self, args: T.Tuple[str, T.Union[int, bool]], kwargs: 'kwargs.ConfigurationDataSet') -> None: self.__check_used() # bool is a subclass of int, so we need to check for bool explicitly. @@ -394,12 +385,14 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte @typed_pos_args('configuration_data.has', (str, int, bool)) @noKwargs + @InterpreterObject.method('has') def has_method(self, args: T.Tuple[T.Union[str, int, bool]], kwargs: TYPE_kwargs) -> bool: return args[0] in self.held_object.values @FeatureNew('configuration_data.get()', '0.38.0') @typed_pos_args('configuration_data.get', str, optargs=[(str, int, bool)]) @noKwargs + @InterpreterObject.method('get') def get_method(self, args: T.Tuple[str, T.Optional[T.Union[str, int, bool]]], kwargs: TYPE_kwargs) -> T.Union[str, int, bool]: name = args[0] @@ -412,6 +405,7 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte @FeatureNew('configuration_data.get_unquoted()', '0.44.0') @typed_pos_args('configuration_data.get_unquoted', str, optargs=[(str, int, bool)]) @noKwargs + @InterpreterObject.method('get_unquoted') def get_unquoted_method(self, args: T.Tuple[str, T.Optional[T.Union[str, int, bool]]], kwargs: TYPE_kwargs) -> T.Union[str, int, bool]: name = args[0] @@ -431,6 +425,7 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte @FeatureNew('configuration_data.keys()', '0.57.0') @noPosargs @noKwargs + @InterpreterObject.method('keys') def keys_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[str]: return sorted(self.keys()) @@ -439,6 +434,7 @@ class ConfigurationDataHolder(ObjectHolder[build.ConfigurationData], MutableInte @typed_pos_args('configuration_data.merge_from', build.ConfigurationData) @noKwargs + @InterpreterObject.method('merge_from') def merge_from_method(self, args: T.Tuple[build.ConfigurationData], kwargs: TYPE_kwargs) -> None: from_object = args[0] self.held_object.values.update(from_object.values) @@ -455,31 +451,19 @@ _PARTIAL_DEP_KWARGS = [ class DependencyHolder(ObjectHolder[Dependency]): def __init__(self, dep: Dependency, interpreter: 'Interpreter'): super().__init__(dep, interpreter) - self.methods.update({'found': self.found_method, - 'type_name': self.type_name_method, - 'version': self.version_method, - 'name': self.name_method, - 'get_pkgconfig_variable': self.pkgconfig_method, - 'get_configtool_variable': self.configtool_method, - 'get_variable': self.variable_method, - 'partial_dependency': self.partial_dependency_method, - 'include_type': self.include_type_method, - 'as_system': self.as_system_method, - 'as_link_whole': self.as_link_whole_method, - 'as_static': self.as_static_method, - 'as_shared': self.as_shared_method, - }) def found(self) -> bool: return self.found_method([], {}) @noPosargs @noKwargs + @InterpreterObject.method('type_name') def type_name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.type_name @noPosargs @noKwargs + @InterpreterObject.method('found') def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: if self.held_object.type_name == 'internal': return True @@ -487,11 +471,13 @@ class DependencyHolder(ObjectHolder[Dependency]): @noPosargs @noKwargs + @InterpreterObject.method('version') def version_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.get_version() @noPosargs @noKwargs + @InterpreterObject.method('name') def name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.get_name() @@ -503,6 +489,7 @@ class DependencyHolder(ObjectHolder[Dependency]): KwargInfo('default', str, default=''), PKGCONFIG_DEFINE_KW.evolve(name='define_variable') ) + @InterpreterObject.method('get_pkgconfig_variable') def pkgconfig_method(self, args: T.Tuple[str], kwargs: 'kwargs.DependencyPkgConfigVar') -> str: from ..dependencies.pkgconfig import PkgConfigDependency if not isinstance(self.held_object, PkgConfigDependency): @@ -521,6 +508,7 @@ class DependencyHolder(ObjectHolder[Dependency]): 'use dependency.get_variable(configtool : ...) instead') @noKwargs @typed_pos_args('dependency.get_config_tool_variable', str) + @InterpreterObject.method('get_configtool_variable') def configtool_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> str: from ..dependencies.configtool import ConfigToolDependency if not isinstance(self.held_object, ConfigToolDependency): @@ -533,6 +521,7 @@ class DependencyHolder(ObjectHolder[Dependency]): @FeatureNew('dependency.partial_dependency', '0.46.0') @noPosargs @typed_kwargs('dependency.partial_dependency', *_PARTIAL_DEP_KWARGS) + @InterpreterObject.method('partial_dependency') def partial_dependency_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.DependencyMethodPartialDependency') -> Dependency: pdep = self.held_object.get_partial_dependency(**kwargs) return pdep @@ -549,6 +538,7 @@ class DependencyHolder(ObjectHolder[Dependency]): KwargInfo('default_value', (str, NoneType)), PKGCONFIG_DEFINE_KW, ) + @InterpreterObject.method('get_variable') def variable_method(self, args: T.Tuple[T.Optional[str]], kwargs: 'kwargs.DependencyGetVariable') -> str: default_varname = args[0] if default_varname is not None: @@ -570,18 +560,21 @@ class DependencyHolder(ObjectHolder[Dependency]): @FeatureNew('dependency.include_type', '0.52.0') @noPosargs @noKwargs + @InterpreterObject.method('include_type') def include_type_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.get_include_type() @FeatureNew('dependency.as_system', '0.52.0') @noKwargs @typed_pos_args('dependency.as_system', optargs=[str]) + @InterpreterObject.method('as_system') def as_system_method(self, args: T.Tuple[T.Optional[str]], kwargs: TYPE_kwargs) -> Dependency: return self.held_object.generate_system_dependency(args[0] or 'system') @FeatureNew('dependency.as_link_whole', '0.56.0') @noKwargs @noPosargs + @InterpreterObject.method('as_link_whole') def as_link_whole_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> Dependency: if not isinstance(self.held_object, InternalDependency): raise InterpreterException('as_link_whole method is only supported on declare_dependency() objects') @@ -594,6 +587,7 @@ class DependencyHolder(ObjectHolder[Dependency]): 'dependency.as_static', KwargInfo('recursive', bool, default=False), ) + @InterpreterObject.method('as_static') def as_static_method(self, args: T.List[TYPE_var], kwargs: InternalDependencyAsKW) -> Dependency: if not isinstance(self.held_object, InternalDependency): raise InterpreterException('as_static method is only supported on declare_dependency() objects') @@ -605,6 +599,7 @@ class DependencyHolder(ObjectHolder[Dependency]): 'dependency.as_shared', KwargInfo('recursive', bool, default=False), ) + @InterpreterObject.method('as_shared') def as_shared_method(self, args: T.List[TYPE_var], kwargs: InternalDependencyAsKW) -> Dependency: if not isinstance(self.held_object, InternalDependency): raise InterpreterException('as_shared method is only supported on declare_dependency() objects') @@ -615,13 +610,10 @@ _EXTPROG = T.TypeVar('_EXTPROG', bound=ExternalProgram) class _ExternalProgramHolder(ObjectHolder[_EXTPROG]): def __init__(self, ep: _EXTPROG, interpreter: 'Interpreter') -> None: super().__init__(ep, interpreter) - self.methods.update({'found': self.found_method, - 'path': self.path_method, - 'version': self.version_method, - 'full_path': self.full_path_method}) @noPosargs @noKwargs + @InterpreterObject.method('found') def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.found() @@ -629,12 +621,14 @@ class _ExternalProgramHolder(ObjectHolder[_EXTPROG]): @noKwargs @FeatureDeprecated('ExternalProgram.path', '0.55.0', 'use ExternalProgram.full_path() instead') + @InterpreterObject.method('path') def path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self._full_path() @noPosargs @noKwargs @FeatureNew('ExternalProgram.full_path', '0.55.0') + @InterpreterObject.method('full_path') def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self._full_path() @@ -648,6 +642,7 @@ class _ExternalProgramHolder(ObjectHolder[_EXTPROG]): @noPosargs @noKwargs @FeatureNew('ExternalProgram.version', '0.62.0') + @InterpreterObject.method('version') def version_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: if not self.found(): raise InterpreterException('Unable to get the version of a not-found external program') @@ -665,25 +660,23 @@ class ExternalProgramHolder(_ExternalProgramHolder[ExternalProgram]): class ExternalLibraryHolder(ObjectHolder[ExternalLibrary]): def __init__(self, el: ExternalLibrary, interpreter: 'Interpreter'): super().__init__(el, interpreter) - self.methods.update({'found': self.found_method, - 'type_name': self.type_name_method, - 'partial_dependency': self.partial_dependency_method, - 'name': self.name_method, - }) @noPosargs @noKwargs + @InterpreterObject.method('type_name') def type_name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.type_name @noPosargs @noKwargs + @InterpreterObject.method('found') def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.held_object.found() @FeatureNew('dependency.partial_dependency', '0.46.0') @noPosargs @typed_kwargs('dependency.partial_dependency', *_PARTIAL_DEP_KWARGS) + @InterpreterObject.method('partial_dependency') def partial_dependency_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.DependencyMethodPartialDependency') -> Dependency: pdep = self.held_object.get_partial_dependency(**kwargs) return pdep @@ -691,6 +684,7 @@ class ExternalLibraryHolder(ObjectHolder[ExternalLibrary]): @FeatureNew('dependency.name', '1.5.0') @noPosargs @noKwargs + @InterpreterObject.method('name') def name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.name @@ -699,36 +693,34 @@ class ExternalLibraryHolder(ObjectHolder[ExternalLibrary]): class MachineHolder(ObjectHolder['MachineInfo']): def __init__(self, machine_info: 'MachineInfo', interpreter: 'Interpreter'): super().__init__(machine_info, interpreter) - self.methods.update({'system': self.system_method, - 'cpu': self.cpu_method, - 'cpu_family': self.cpu_family_method, - 'endian': self.endian_method, - 'kernel': self.kernel_method, - 'subsystem': self.subsystem_method, - }) @noPosargs @noKwargs + @InterpreterObject.method('cpu_family') def cpu_family_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.cpu_family @noPosargs @noKwargs + @InterpreterObject.method('cpu') def cpu_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.cpu @noPosargs @noKwargs + @InterpreterObject.method('system') def system_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.system @noPosargs @noKwargs + @InterpreterObject.method('endian') def endian_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.endian @noPosargs @noKwargs + @InterpreterObject.method('kernel') def kernel_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: if self.held_object.kernel is not None: return self.held_object.kernel @@ -736,6 +728,7 @@ class MachineHolder(ObjectHolder['MachineInfo']): @noPosargs @noKwargs + @InterpreterObject.method('subsystem') def subsystem_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: if self.held_object.subsystem is not None: return self.held_object.subsystem @@ -748,12 +741,11 @@ class IncludeDirsHolder(ObjectHolder[build.IncludeDirs]): class FileHolder(ObjectHolder[mesonlib.File]): def __init__(self, file: mesonlib.File, interpreter: 'Interpreter'): super().__init__(file, interpreter) - self.methods.update({'full_path': self.full_path_method, - }) @noPosargs @noKwargs @FeatureNew('file.full_path', '1.4.0') + @InterpreterObject.method('full_path') def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.absolute_path(self.env.source_dir, self.env.build_dir) @@ -836,12 +828,10 @@ class SubprojectHolder(MesonInterpreterObject): self.subdir = PurePath(subdir).as_posix() self.cm_interpreter: T.Optional[CMakeInterpreter] = None self.callstack = callstack - self.methods.update({'get_variable': self.get_variable_method, - 'found': self.found_method, - }) @noPosargs @noKwargs + @InterpreterObject.method('found') def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.found() @@ -863,6 +853,7 @@ class SubprojectHolder(MesonInterpreterObject): @noKwargs @typed_pos_args('subproject.get_variable', str, optargs=[object]) @noArgsFlattening + @InterpreterObject.method('get_variable') def get_variable_method(self, args: T.Tuple[str, T.Optional[str]], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]: return self.get_variable(args, kwargs) @@ -905,16 +896,6 @@ _BuildTarget = T.TypeVar('_BuildTarget', bound=T.Union[build.BuildTarget, build. class BuildTargetHolder(ObjectHolder[_BuildTarget]): def __init__(self, target: _BuildTarget, interp: 'Interpreter'): super().__init__(target, interp) - self.methods.update({'extract_objects': self.extract_objects_method, - 'extract_all_objects': self.extract_all_objects_method, - 'name': self.name_method, - 'get_id': self.get_id_method, - 'outdir': self.outdir_method, - 'full_path': self.full_path_method, - 'path': self.path_method, - 'found': self.found_method, - 'private_dir_include': self.private_dir_include_method, - }) def __repr__(self) -> str: r = '<{} {}: {}>' @@ -934,6 +915,7 @@ class BuildTargetHolder(ObjectHolder[_BuildTarget]): @noPosargs @noKwargs + @InterpreterObject.method('found') def found_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: if not (isinstance(self.held_object, build.Executable) and self.held_object.was_returned_by_find_program): FeatureNew.single_use('BuildTarget.found', '0.59.0', subproject=self.held_object.subproject) @@ -941,27 +923,32 @@ class BuildTargetHolder(ObjectHolder[_BuildTarget]): @noPosargs @noKwargs + @InterpreterObject.method('private_dir_include') def private_dir_include_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.IncludeDirs: return build.IncludeDirs('', [], False, [self.interpreter.backend.get_target_private_dir(self._target_object)]) @noPosargs @noKwargs + @InterpreterObject.method('full_path') def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.interpreter.backend.get_target_filename_abs(self._target_object) @noPosargs @noKwargs @FeatureDeprecated('BuildTarget.path', '0.55.0', 'Use BuildTarget.full_path instead') + @InterpreterObject.method('path') def path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.interpreter.backend.get_target_filename_abs(self._target_object) @noPosargs @noKwargs + @InterpreterObject.method('outdir') def outdir_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.interpreter.backend.get_target_dir(self._target_object) @noKwargs @typed_pos_args('extract_objects', varargs=(mesonlib.File, str, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) + @InterpreterObject.method('extract_objects') def extract_objects_method(self, args: T.Tuple[T.List[T.Union[mesonlib.FileOrString, 'build.GeneratedTypes']]], kwargs: TYPE_nkwargs) -> build.ExtractedObjects: tobj = self._target_object unity_value = self.interpreter.coredata.get_option_for_target(tobj, "unity") @@ -981,6 +968,7 @@ class BuildTargetHolder(ObjectHolder[_BuildTarget]): ''') ) ) + @InterpreterObject.method('extract_all_objects') def extract_all_objects_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.BuildTargeMethodExtractAllObjects') -> build.ExtractedObjects: return self._target_object.extract_all_objects(kwargs['recursive']) @@ -989,12 +977,14 @@ class BuildTargetHolder(ObjectHolder[_BuildTarget]): @FeatureDeprecated('BuildTarget.get_id', '1.2.0', 'This was never formally documented and does not seem to have a real world use. ' + 'See https://github.com/mesonbuild/meson/pull/6061') + @InterpreterObject.method('get_id') def get_id_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self._target_object.get_id() @FeatureNew('name', '0.54.0') @noPosargs @noKwargs + @InterpreterObject.method('name') def name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self._target_object.name @@ -1010,9 +1000,6 @@ class SharedLibraryHolder(BuildTargetHolder[build.SharedLibrary]): class BothLibrariesHolder(BuildTargetHolder[build.BothLibraries]): def __init__(self, libs: build.BothLibraries, interp: 'Interpreter'): super().__init__(libs, interp) - self.methods.update({'get_shared_lib': self.get_shared_lib_method, - 'get_static_lib': self.get_static_lib_method, - }) def __repr__(self) -> str: r = '<{} {}: {}, {}: {}>' @@ -1022,6 +1009,7 @@ class BothLibrariesHolder(BuildTargetHolder[build.BothLibraries]): @noPosargs @noKwargs + @InterpreterObject.method('get_shared_lib') def get_shared_lib_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.SharedLibrary: lib = copy.copy(self.held_object.shared) lib.both_lib = None @@ -1029,6 +1017,7 @@ class BothLibrariesHolder(BuildTargetHolder[build.BothLibraries]): @noPosargs @noKwargs + @InterpreterObject.method('get_static_lib') def get_static_lib_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.StaticLibrary: lib = copy.copy(self.held_object.static) lib.both_lib = None @@ -1043,12 +1032,11 @@ class JarHolder(BuildTargetHolder[build.Jar]): class CustomTargetIndexHolder(ObjectHolder[build.CustomTargetIndex]): def __init__(self, target: build.CustomTargetIndex, interp: 'Interpreter'): super().__init__(target, interp) - self.methods.update({'full_path': self.full_path_method, - }) @FeatureNew('custom_target[i].full_path', '0.54.0') @noPosargs @noKwargs + @InterpreterObject.method('full_path') def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: assert self.interpreter.backend is not None return self.interpreter.backend.get_target_filename_abs(self.held_object) @@ -1058,13 +1046,6 @@ _CT = T.TypeVar('_CT', bound=build.CustomTarget) class _CustomTargetHolder(ObjectHolder[_CT]): def __init__(self, target: _CT, interp: 'Interpreter'): super().__init__(target, interp) - self.methods.update({'full_path': self.full_path_method, - 'to_list': self.to_list_method, - }) - - self.operators.update({ - MesonOperator.INDEX: self.op_index, - }) def __repr__(self) -> str: r = '<{} {}: {}>' @@ -1073,12 +1054,14 @@ class _CustomTargetHolder(ObjectHolder[_CT]): @noPosargs @noKwargs + @InterpreterObject.method('full_path') def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.interpreter.backend.get_target_filename_abs(self.held_object) @FeatureNew('custom_target.to_list', '0.54.0') @noPosargs @noKwargs + @InterpreterObject.method('to_list') def to_list_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[build.CustomTargetIndex]: result = [] for i in self.held_object: @@ -1087,6 +1070,7 @@ class _CustomTargetHolder(ObjectHolder[_CT]): @noKwargs @typed_operator(MesonOperator.INDEX, int) + @InterpreterObject.operator(MesonOperator.INDEX) def op_index(self, other: int) -> build.CustomTargetIndex: try: return self.held_object[other] @@ -1108,7 +1092,6 @@ class GeneratedListHolder(ObjectHolder[build.GeneratedList]): class GeneratorHolder(ObjectHolder[build.Generator]): def __init__(self, gen: build.Generator, interpreter: 'Interpreter'): super().__init__(gen, interpreter) - self.methods.update({'process': self.process_method}) @typed_pos_args('generator.process', min_varargs=1, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)) @typed_kwargs( @@ -1117,6 +1100,7 @@ class GeneratorHolder(ObjectHolder[build.Generator]): KwargInfo('extra_args', ContainerTypeInfo(list, str), listify=True, default=[]), ENV_KW.evolve(since='1.3.0') ) + @InterpreterObject.method('process') def process_method(self, args: T.Tuple[T.List[T.Union[str, mesonlib.File, 'build.GeneratedTypes']]], kwargs: 'kwargs.GeneratorProcess') -> build.GeneratedList: @@ -1142,3 +1126,11 @@ class StructuredSourcesHolder(ObjectHolder[build.StructuredSources]): def __init__(self, sources: build.StructuredSources, interp: 'Interpreter'): super().__init__(sources, interp) + +class OverrideExecutableHolder(BuildTargetHolder[build.OverrideExecutable]): + @noPosargs + @noKwargs + @FeatureNew('OverrideExecutable.version', '1.9.0') + @InterpreterObject.method('version') + def version_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: + return self.held_object.get_version(self.interpreter) diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index fb34bbb..d741aab 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -321,7 +321,7 @@ class Subproject(ExtractRequired): class DoSubproject(ExtractRequired): - default_options: T.List[str] + default_options: T.Union[T.List[str], T.Dict[str, options.ElementaryOptionValues], str] version: T.List[str] cmake_options: T.List[str] options: T.Optional[CMakeSubprojectOptions] diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 8ede691..602575c 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -18,7 +18,7 @@ from ..programs import OverrideProgram, ExternalProgram from ..interpreter.type_checking import ENV_KW, ENV_METHOD_KW, ENV_SEPARATOR_KW, env_convertor_with_method from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated, typed_pos_args, noArgsFlattening, noPosargs, noKwargs, - typed_kwargs, KwargInfo, InterpreterException) + typed_kwargs, KwargInfo, InterpreterException, InterpreterObject) from .primitives import MesonVersionString from .type_checking import NATIVE_KW, NoneType @@ -55,38 +55,6 @@ class MesonMain(MesonInterpreterObject): super().__init__(subproject=interpreter.subproject) self.build = build self.interpreter = interpreter - self.methods.update({'add_devenv': self.add_devenv_method, - 'add_dist_script': self.add_dist_script_method, - 'add_install_script': self.add_install_script_method, - 'add_postconf_script': self.add_postconf_script_method, - 'backend': self.backend_method, - 'build_options': self.build_options_method, - 'build_root': self.build_root_method, - 'can_run_host_binaries': self.can_run_host_binaries_method, - 'current_source_dir': self.current_source_dir_method, - 'current_build_dir': self.current_build_dir_method, - 'get_compiler': self.get_compiler_method, - 'get_cross_property': self.get_cross_property_method, - 'get_external_property': self.get_external_property_method, - 'global_build_root': self.global_build_root_method, - 'global_source_root': self.global_source_root_method, - 'has_exe_wrapper': self.has_exe_wrapper_method, - 'has_external_property': self.has_external_property_method, - 'install_dependency_manifest': self.install_dependency_manifest_method, - 'is_cross_build': self.is_cross_build_method, - 'is_subproject': self.is_subproject_method, - 'is_unity': self.is_unity_method, - 'override_dependency': self.override_dependency_method, - 'override_find_program': self.override_find_program_method, - 'project_build_root': self.project_build_root_method, - 'project_license': self.project_license_method, - 'project_license_files': self.project_license_files_method, - 'project_name': self.project_name_method, - 'project_source_root': self.project_source_root_method, - 'project_version': self.project_version_method, - 'source_root': self.source_root_method, - 'version': self.version_method, - }) def _find_source_script( self, name: str, prog: T.Union[str, mesonlib.File, build.Executable, ExternalProgram], @@ -157,6 +125,7 @@ class MesonMain(MesonInterpreterObject): KwargInfo('install_tag', (str, NoneType), since='0.60.0'), KwargInfo('dry_run', bool, default=False, since='1.1.0'), ) + @InterpreterObject.method('add_install_script') def add_install_script_method( self, args: T.Tuple[T.Union[str, mesonlib.File, build.Executable, ExternalProgram], @@ -175,6 +144,7 @@ class MesonMain(MesonInterpreterObject): varargs=(str, mesonlib.File, ExternalProgram) ) @noKwargs + @InterpreterObject.method('add_postconf_script') def add_postconf_script_method( self, args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram], @@ -191,6 +161,7 @@ class MesonMain(MesonInterpreterObject): ) @noKwargs @FeatureNew('meson.add_dist_script', '0.48.0') + @InterpreterObject.method('add_dist_script') def add_dist_script_method( self, args: T.Tuple[T.Union[str, mesonlib.File, ExternalProgram], @@ -208,6 +179,7 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs + @InterpreterObject.method('current_source_dir') def current_source_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.source_dir sub = self.interpreter.subdir @@ -217,6 +189,7 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs + @InterpreterObject.method('current_build_dir') def current_build_dir_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.build_dir sub = self.interpreter.subdir @@ -226,24 +199,28 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs + @InterpreterObject.method('backend') def backend_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.backend.name @noPosargs @noKwargs @FeatureDeprecated('meson.source_root', '0.56.0', 'use meson.project_source_root() or meson.global_source_root() instead.') + @InterpreterObject.method('source_root') def source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.environment.source_dir @noPosargs @noKwargs @FeatureDeprecated('meson.build_root', '0.56.0', 'use meson.project_build_root() or meson.global_build_root() instead.') + @InterpreterObject.method('build_root') def build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.environment.build_dir @noPosargs @noKwargs @FeatureNew('meson.project_source_root', '0.56.0') + @InterpreterObject.method('project_source_root') def project_source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.source_dir sub = self.interpreter.root_subdir @@ -254,6 +231,7 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs @FeatureNew('meson.project_build_root', '0.56.0') + @InterpreterObject.method('project_build_root') def project_build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: src = self.interpreter.environment.build_dir sub = self.interpreter.root_subdir @@ -264,24 +242,28 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs @FeatureNew('meson.global_source_root', '0.58.0') + @InterpreterObject.method('global_source_root') def global_source_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.environment.source_dir @noPosargs @noKwargs @FeatureNew('meson.global_build_root', '0.58.0') + @InterpreterObject.method('global_build_root') def global_build_root_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.environment.build_dir @noPosargs @noKwargs @FeatureDeprecated('meson.has_exe_wrapper', '0.55.0', 'use meson.can_run_host_binaries instead.') + @InterpreterObject.method('has_exe_wrapper') def has_exe_wrapper_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: return self._can_run_host_binaries_impl() @noPosargs @noKwargs @FeatureNew('meson.can_run_host_binaries', '0.55.0') + @InterpreterObject.method('can_run_host_binaries') def can_run_host_binaries_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: return self._can_run_host_binaries_impl() @@ -294,11 +276,13 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs + @InterpreterObject.method('is_cross_build') def is_cross_build_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: return self.build.environment.is_cross_build() @typed_pos_args('meson.get_compiler', str) @typed_kwargs('meson.get_compiler', NATIVE_KW) + @InterpreterObject.method('get_compiler') def get_compiler_method(self, args: T.Tuple[str], kwargs: 'NativeKW') -> 'Compiler': cname = args[0] for_machine = kwargs['native'] @@ -310,23 +294,27 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs + @InterpreterObject.method('is_unity') def is_unity_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: optval = self.interpreter.environment.coredata.optstore.get_value_for(OptionKey('unity')) return optval == 'on' or (optval == 'subprojects' and self.interpreter.is_subproject()) @noPosargs @noKwargs + @InterpreterObject.method('is_subproject') def is_subproject_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> bool: return self.interpreter.is_subproject() @typed_pos_args('meson.install_dependency_manifest', str) @noKwargs + @InterpreterObject.method('install_dependency_manifest') def install_dependency_manifest_method(self, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> None: self.build.dep_manifest_name = args[0] @FeatureNew('meson.override_find_program', '0.46.0') @typed_pos_args('meson.override_find_program', str, (mesonlib.File, ExternalProgram, build.Executable)) @noKwargs + @InterpreterObject.method('override_find_program') def override_find_program_method(self, args: T.Tuple[str, T.Union[mesonlib.File, ExternalProgram, build.Executable]], kwargs: 'TYPE_kwargs') -> None: name, exe = args if isinstance(exe, mesonlib.File): @@ -335,6 +323,8 @@ class MesonMain(MesonInterpreterObject): if not os.path.exists(abspath): raise InterpreterException(f'Tried to override {name} with a file that does not exist.') exe = OverrideProgram(name, self.interpreter.project_version, command=[abspath]) + elif isinstance(exe, build.Executable): + exe = build.OverrideExecutable(exe, self.interpreter.project_version) self.interpreter.add_find_program_override(name, exe) @typed_kwargs( @@ -344,6 +334,7 @@ class MesonMain(MesonInterpreterObject): ) @typed_pos_args('meson.override_dependency', str, dependencies.Dependency) @FeatureNew('meson.override_dependency', '0.54.0') + @InterpreterObject.method('override_dependency') def override_dependency_method(self, args: T.Tuple[str, dependencies.Dependency], kwargs: 'FuncOverrideDependency') -> None: name, dep = args if not name: @@ -409,28 +400,33 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs + @InterpreterObject.method('project_version') def project_version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.build.dep_manifest[self.interpreter.active_projectname].version @FeatureNew('meson.project_license()', '0.45.0') @noPosargs @noKwargs + @InterpreterObject.method('project_license') def project_license_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> T.List[str]: return self.build.dep_manifest[self.interpreter.active_projectname].license @FeatureNew('meson.project_license_files()', '1.1.0') @noPosargs @noKwargs + @InterpreterObject.method('project_license_files') def project_license_files_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[mesonlib.File]: return [l[1] for l in self.build.dep_manifest[self.interpreter.active_projectname].license_files] @noPosargs @noKwargs + @InterpreterObject.method('version') def version_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> MesonVersionString: return MesonVersionString(self.interpreter.coredata.version) @noPosargs @noKwargs + @InterpreterObject.method('project_name') def project_name_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: return self.interpreter.active_projectname @@ -447,6 +443,7 @@ class MesonMain(MesonInterpreterObject): @FeatureDeprecated('meson.get_cross_property', '0.58.0', 'Use meson.get_external_property() instead') @typed_pos_args('meson.get_cross_property', str, optargs=[object]) @noKwargs + @InterpreterObject.method('get_cross_property') def get_cross_property_method(self, args: T.Tuple[str, T.Optional[object]], kwargs: 'TYPE_kwargs') -> object: propname, fallback = args return self.__get_external_property_impl(propname, fallback, MachineChoice.HOST) @@ -455,6 +452,7 @@ class MesonMain(MesonInterpreterObject): @FeatureNew('meson.get_external_property', '0.54.0') @typed_pos_args('meson.get_external_property', str, optargs=[object]) @typed_kwargs('meson.get_external_property', NATIVE_KW) + @InterpreterObject.method('get_external_property') def get_external_property_method(self, args: T.Tuple[str, T.Optional[object]], kwargs: 'NativeKW') -> object: propname, fallback = args return self.__get_external_property_impl(propname, fallback, kwargs['native']) @@ -462,6 +460,7 @@ class MesonMain(MesonInterpreterObject): @FeatureNew('meson.has_external_property', '0.58.0') @typed_pos_args('meson.has_external_property', str) @typed_kwargs('meson.has_external_property', NATIVE_KW) + @InterpreterObject.method('has_external_property') def has_external_property_method(self, args: T.Tuple[str], kwargs: 'NativeKW') -> bool: prop_name = args[0] return prop_name in self.interpreter.environment.properties[kwargs['native']] @@ -469,6 +468,7 @@ class MesonMain(MesonInterpreterObject): @FeatureNew('add_devenv', '0.58.0') @typed_kwargs('environment', ENV_METHOD_KW, ENV_SEPARATOR_KW.evolve(since='0.62.0')) @typed_pos_args('add_devenv', (str, list, dict, mesonlib.EnvironmentVariables)) + @InterpreterObject.method('add_devenv') def add_devenv_method(self, args: T.Tuple[T.Union[str, list, dict, mesonlib.EnvironmentVariables]], kwargs: 'AddDevenvKW') -> None: env = args[0] @@ -482,6 +482,7 @@ class MesonMain(MesonInterpreterObject): @noPosargs @noKwargs @FeatureNew('meson.build_options', '1.1.0') + @InterpreterObject.method('build_options') def build_options_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> str: options = self.interpreter.user_defined_options if options is None: diff --git a/mesonbuild/interpreter/primitives/array.py b/mesonbuild/interpreter/primitives/array.py index b42ddea..ff520a2 100644 --- a/mesonbuild/interpreter/primitives/array.py +++ b/mesonbuild/interpreter/primitives/array.py @@ -5,9 +5,10 @@ from __future__ import annotations import typing as T from ...interpreterbase import ( - ObjectHolder, + InterpreterObject, IterableObject, MesonOperator, + ObjectHolder, typed_operator, noKwargs, noPosargs, @@ -22,31 +23,16 @@ from ...interpreterbase import ( from ...mparser import PlusAssignmentNode if T.TYPE_CHECKING: - # Object holders need the actual interpreter - from ...interpreter import Interpreter from ...interpreterbase import TYPE_kwargs 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, - }) + # Operators that only require type checks + TRIVIAL_OPERATORS = { + MesonOperator.EQUALS: (list, lambda obj, x: obj.held_object == x), + MesonOperator.NOT_EQUALS: (list, lambda obj, x: obj.held_object != x), + MesonOperator.IN: (object, lambda obj, x: x in obj.held_object), + MesonOperator.NOT_IN: (object, lambda obj, x: x not in obj.held_object), + } def display_name(self) -> str: return 'array' @@ -63,6 +49,7 @@ class ArrayHolder(ObjectHolder[T.List[TYPE_var]], IterableObject): @noArgsFlattening @noKwargs @typed_pos_args('array.contains', object) + @InterpreterObject.method('contains') 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: @@ -77,12 +64,14 @@ class ArrayHolder(ObjectHolder[T.List[TYPE_var]], IterableObject): @noKwargs @noPosargs + @InterpreterObject.method('length') 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]) + @InterpreterObject.method('get') 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): @@ -92,6 +81,7 @@ class ArrayHolder(ObjectHolder[T.List[TYPE_var]], IterableObject): return self.held_object[index] @typed_operator(MesonOperator.PLUS, object) + @InterpreterObject.operator(MesonOperator.PLUS) def op_plus(self, other: TYPE_var) -> T.List[TYPE_var]: if not isinstance(other, list): if not isinstance(self.current_node, PlusAssignmentNode): @@ -101,6 +91,7 @@ class ArrayHolder(ObjectHolder[T.List[TYPE_var]], IterableObject): return self.held_object + other @typed_operator(MesonOperator.INDEX, int) + @InterpreterObject.operator(MesonOperator.INDEX) def op_index(self, other: int) -> TYPE_var: try: return self.held_object[other] diff --git a/mesonbuild/interpreter/primitives/boolean.py b/mesonbuild/interpreter/primitives/boolean.py index 4b49caf..eb01b9f 100644 --- a/mesonbuild/interpreter/primitives/boolean.py +++ b/mesonbuild/interpreter/primitives/boolean.py @@ -3,8 +3,9 @@ from __future__ import annotations from ...interpreterbase import ( - ObjectHolder, + InterpreterObject, MesonOperator, + ObjectHolder, typed_pos_args, noKwargs, noPosargs, @@ -15,35 +16,28 @@ from ...interpreterbase import ( import typing as T if T.TYPE_CHECKING: - # Object holders need the actual interpreter - from ...interpreter import Interpreter from ...interpreterbase import TYPE_var, TYPE_kwargs class BooleanHolder(ObjectHolder[bool]): - def __init__(self, obj: bool, interpreter: 'Interpreter') -> None: - super().__init__(obj, interpreter) - self.methods.update({ - 'to_int': self.to_int_method, - 'to_string': self.to_string_method, - }) - - self.trivial_operators.update({ - MesonOperator.BOOL: (None, lambda x: self.held_object), - MesonOperator.NOT: (None, lambda x: not self.held_object), - MesonOperator.EQUALS: (bool, lambda x: self.held_object == x), - MesonOperator.NOT_EQUALS: (bool, lambda x: self.held_object != x), - }) + TRIVIAL_OPERATORS = { + MesonOperator.BOOL: (None, lambda obj, x: obj.held_object), + MesonOperator.NOT: (None, lambda obj, x: not obj.held_object), + MesonOperator.EQUALS: (bool, lambda obj, x: obj.held_object == x), + MesonOperator.NOT_EQUALS: (bool, lambda obj, x: obj.held_object != x), + } def display_name(self) -> str: return 'bool' @noKwargs @noPosargs + @InterpreterObject.method('to_int') def to_int_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int: return 1 if self.held_object else 0 @noKwargs @typed_pos_args('bool.to_string', optargs=[str, str]) + @InterpreterObject.method('to_string') def to_string_method(self, args: T.Tuple[T.Optional[str], T.Optional[str]], kwargs: TYPE_kwargs) -> str: true_str = args[0] or 'true' false_str = args[1] or 'false' diff --git a/mesonbuild/interpreter/primitives/dict.py b/mesonbuild/interpreter/primitives/dict.py index ab4c15f..d641fa8 100644 --- a/mesonbuild/interpreter/primitives/dict.py +++ b/mesonbuild/interpreter/primitives/dict.py @@ -5,9 +5,10 @@ from __future__ import annotations import typing as T from ...interpreterbase import ( - ObjectHolder, + InterpreterObject, IterableObject, MesonOperator, + ObjectHolder, typed_operator, noKwargs, noPosargs, @@ -20,34 +21,20 @@ from ...interpreterbase import ( ) if T.TYPE_CHECKING: - # Object holders need the actual interpreter - from ...interpreter import Interpreter from ...interpreterbase import TYPE_kwargs 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, - }) + # Operators that only require type checks + TRIVIAL_OPERATORS = { + # Arithmetic + MesonOperator.PLUS: (dict, lambda obj, x: {**obj.held_object, **x}), + + # Comparison + MesonOperator.EQUALS: (dict, lambda obj, x: obj.held_object == x), + MesonOperator.NOT_EQUALS: (dict, lambda obj, x: obj.held_object != x), + MesonOperator.IN: (str, lambda obj, x: x in obj.held_object), + MesonOperator.NOT_IN: (str, lambda obj, x: x not in obj.held_object), + } def display_name(self) -> str: return 'dict' @@ -63,17 +50,20 @@ class DictHolder(ObjectHolder[T.Dict[str, TYPE_var]], IterableObject): @noKwargs @typed_pos_args('dict.has_key', str) + @InterpreterObject.method('has_key') def has_key_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool: return args[0] in self.held_object @noKwargs @noPosargs + @InterpreterObject.method('keys') 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]) + @InterpreterObject.method('get') 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]] @@ -82,6 +72,7 @@ class DictHolder(ObjectHolder[T.Dict[str, TYPE_var]], IterableObject): raise InvalidArguments(f'Key {args[0]!r} is not in the dictionary.') @typed_operator(MesonOperator.INDEX, str) + @InterpreterObject.operator(MesonOperator.INDEX) 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.') diff --git a/mesonbuild/interpreter/primitives/integer.py b/mesonbuild/interpreter/primitives/integer.py index cdf2355..c59ea6e 100644 --- a/mesonbuild/interpreter/primitives/integer.py +++ b/mesonbuild/interpreter/primitives/integer.py @@ -3,47 +3,33 @@ from __future__ import annotations from ...interpreterbase import ( - FeatureBroken, InvalidArguments, MesonOperator, ObjectHolder, KwargInfo, + InterpreterObject, MesonOperator, ObjectHolder, + FeatureBroken, InvalidArguments, KwargInfo, noKwargs, noPosargs, typed_operator, typed_kwargs ) import typing as T if T.TYPE_CHECKING: - # Object holders need the actual interpreter - from ...interpreter import Interpreter from ...interpreterbase import TYPE_var, TYPE_kwargs class IntegerHolder(ObjectHolder[int]): - def __init__(self, obj: int, interpreter: 'Interpreter') -> None: - super().__init__(obj, interpreter) - self.methods.update({ - 'is_even': self.is_even_method, - 'is_odd': self.is_odd_method, - 'to_string': self.to_string_method, - }) + # Operators that only require type checks + TRIVIAL_OPERATORS = { + # Arithmetic + MesonOperator.UMINUS: (None, lambda obj, x: -obj.held_object), + MesonOperator.PLUS: (int, lambda obj, x: obj.held_object + x), + MesonOperator.MINUS: (int, lambda obj, x: obj.held_object - x), + MesonOperator.TIMES: (int, lambda obj, x: obj.held_object * x), - self.trivial_operators.update({ - # Arithmetic - MesonOperator.UMINUS: (None, lambda x: -self.held_object), - MesonOperator.PLUS: (int, lambda x: self.held_object + x), - MesonOperator.MINUS: (int, lambda x: self.held_object - x), - MesonOperator.TIMES: (int, lambda x: self.held_object * x), - - # Comparison - MesonOperator.EQUALS: (int, lambda x: self.held_object == x), - MesonOperator.NOT_EQUALS: (int, lambda x: self.held_object != x), - MesonOperator.GREATER: (int, lambda x: self.held_object > x), - MesonOperator.LESS: (int, lambda x: self.held_object < x), - MesonOperator.GREATER_EQUALS: (int, lambda x: self.held_object >= x), - MesonOperator.LESS_EQUALS: (int, lambda x: self.held_object <= x), - }) - - # Use actual methods for functions that require additional checks - self.operators.update({ - MesonOperator.DIV: self.op_div, - MesonOperator.MOD: self.op_mod, - }) + # Comparison + MesonOperator.EQUALS: (int, lambda obj, x: obj.held_object == x), + MesonOperator.NOT_EQUALS: (int, lambda obj, x: obj.held_object != x), + MesonOperator.GREATER: (int, lambda obj, x: obj.held_object > x), + MesonOperator.LESS: (int, lambda obj, x: obj.held_object < x), + MesonOperator.GREATER_EQUALS: (int, lambda obj, x: obj.held_object >= x), + MesonOperator.LESS_EQUALS: (int, lambda obj, x: obj.held_object <= x), + } def display_name(self) -> str: return 'int' @@ -57,11 +43,13 @@ class IntegerHolder(ObjectHolder[int]): @noKwargs @noPosargs + @InterpreterObject.method('is_even') def is_even_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.held_object % 2 == 0 @noKwargs @noPosargs + @InterpreterObject.method('is_odd') def is_odd_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: return self.held_object % 2 != 0 @@ -70,16 +58,19 @@ class IntegerHolder(ObjectHolder[int]): KwargInfo('fill', int, default=0, since='1.3.0') ) @noPosargs + @InterpreterObject.method('to_string') def to_string_method(self, args: T.List[TYPE_var], kwargs: T.Dict[str, T.Any]) -> str: return str(self.held_object).zfill(kwargs['fill']) @typed_operator(MesonOperator.DIV, int) + @InterpreterObject.operator(MesonOperator.DIV) def op_div(self, other: int) -> int: if other == 0: raise InvalidArguments('Tried to divide by 0') return self.held_object // other @typed_operator(MesonOperator.MOD, int) + @InterpreterObject.operator(MesonOperator.MOD) def op_mod(self, other: int) -> int: if other == 0: raise InvalidArguments('Tried to divide by 0') diff --git a/mesonbuild/interpreter/primitives/range.py b/mesonbuild/interpreter/primitives/range.py index 23d5617..1aceb68 100644 --- a/mesonbuild/interpreter/primitives/range.py +++ b/mesonbuild/interpreter/primitives/range.py @@ -5,8 +5,9 @@ from __future__ import annotations import typing as T from ...interpreterbase import ( - MesonInterpreterObject, + InterpreterObject, IterableObject, + MesonInterpreterObject, MesonOperator, InvalidArguments, ) @@ -18,10 +19,8 @@ class RangeHolder(MesonInterpreterObject, IterableObject): def __init__(self, start: int, stop: int, step: int, *, subproject: 'SubProject') -> None: super().__init__(subproject=subproject) self.range = range(start, stop, step) - self.operators.update({ - MesonOperator.INDEX: self.op_index, - }) + @InterpreterObject.operator(MesonOperator.INDEX) def op_index(self, other: int) -> int: try: return self.range[other] diff --git a/mesonbuild/interpreter/primitives/string.py b/mesonbuild/interpreter/primitives/string.py index a224dfa..49dd716 100644 --- a/mesonbuild/interpreter/primitives/string.py +++ b/mesonbuild/interpreter/primitives/string.py @@ -9,8 +9,9 @@ import typing as T from ...mesonlib import version_compare, version_compare_many from ...interpreterbase import ( - ObjectHolder, + InterpreterObject, MesonOperator, + ObjectHolder, FeatureNew, typed_operator, noArgsFlattening, @@ -24,73 +25,47 @@ from ...interpreterbase import ( if T.TYPE_CHECKING: - # Object holders need the actual interpreter - from ...interpreter import Interpreter from ...interpreterbase import TYPE_var, TYPE_kwargs class StringHolder(ObjectHolder[str]): - def __init__(self, obj: str, interpreter: 'Interpreter') -> None: - super().__init__(obj, interpreter) - self.methods.update({ - 'contains': self.contains_method, - 'startswith': self.startswith_method, - 'endswith': self.endswith_method, - 'format': self.format_method, - 'join': self.join_method, - 'replace': self.replace_method, - 'split': self.split_method, - 'splitlines': self.splitlines_method, - 'strip': self.strip_method, - 'substring': self.substring_method, - 'to_int': self.to_int_method, - 'to_lower': self.to_lower_method, - 'to_upper': self.to_upper_method, - 'underscorify': self.underscorify_method, - 'version_compare': self.version_compare_method, - }) - - self.trivial_operators.update({ - # Arithmetic - MesonOperator.PLUS: (str, lambda x: self.held_object + x), - - # Comparison - MesonOperator.EQUALS: (str, lambda x: self.held_object == x), - MesonOperator.NOT_EQUALS: (str, lambda x: self.held_object != x), - MesonOperator.GREATER: (str, lambda x: self.held_object > x), - MesonOperator.LESS: (str, lambda x: self.held_object < x), - MesonOperator.GREATER_EQUALS: (str, lambda x: self.held_object >= x), - MesonOperator.LESS_EQUALS: (str, lambda x: self.held_object <= x), - }) - - # Use actual methods for functions that require additional checks - self.operators.update({ - MesonOperator.DIV: self.op_div, - MesonOperator.INDEX: self.op_index, - MesonOperator.IN: self.op_in, - MesonOperator.NOT_IN: self.op_notin, - }) + TRIVIAL_OPERATORS = { + # Arithmetic + MesonOperator.PLUS: (str, lambda obj, x: obj.held_object + x), + + # Comparison + MesonOperator.EQUALS: (str, lambda obj, x: obj.held_object == x), + MesonOperator.NOT_EQUALS: (str, lambda obj, x: obj.held_object != x), + MesonOperator.GREATER: (str, lambda obj, x: obj.held_object > x), + MesonOperator.LESS: (str, lambda obj, x: obj.held_object < x), + MesonOperator.GREATER_EQUALS: (str, lambda obj, x: obj.held_object >= x), + MesonOperator.LESS_EQUALS: (str, lambda obj, x: obj.held_object <= x), + } def display_name(self) -> str: return 'str' @noKwargs @typed_pos_args('str.contains', str) + @InterpreterObject.method('contains') def contains_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool: return self.held_object.find(args[0]) >= 0 @noKwargs @typed_pos_args('str.startswith', str) + @InterpreterObject.method('startswith') def startswith_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool: return self.held_object.startswith(args[0]) @noKwargs @typed_pos_args('str.endswith', str) + @InterpreterObject.method('endswith') def endswith_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool: return self.held_object.endswith(args[0]) @noArgsFlattening @noKwargs @typed_pos_args('str.format', varargs=object) + @InterpreterObject.method('format') def format_method(self, args: T.Tuple[T.List[TYPE_var]], kwargs: TYPE_kwargs) -> str: arg_strings: T.List[str] = [] for arg in args[0]: @@ -111,27 +86,32 @@ class StringHolder(ObjectHolder[str]): @noKwargs @noPosargs @FeatureNew('str.splitlines', '1.2.0') + @InterpreterObject.method('splitlines') def splitlines_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.List[str]: return self.held_object.splitlines() @noKwargs @typed_pos_args('str.join', varargs=str) + @InterpreterObject.method('join') def join_method(self, args: T.Tuple[T.List[str]], kwargs: TYPE_kwargs) -> str: return self.held_object.join(args[0]) @noKwargs @FeatureNew('str.replace', '0.58.0') @typed_pos_args('str.replace', str, str) + @InterpreterObject.method('replace') def replace_method(self, args: T.Tuple[str, str], kwargs: TYPE_kwargs) -> str: return self.held_object.replace(args[0], args[1]) @noKwargs @typed_pos_args('str.split', optargs=[str]) + @InterpreterObject.method('split') def split_method(self, args: T.Tuple[T.Optional[str]], kwargs: TYPE_kwargs) -> T.List[str]: return self.held_object.split(args[0]) @noKwargs @typed_pos_args('str.strip', optargs=[str]) + @InterpreterObject.method('strip') def strip_method(self, args: T.Tuple[T.Optional[str]], kwargs: TYPE_kwargs) -> str: if args[0]: FeatureNew.single_use('str.strip with a positional argument', '0.43.0', self.subproject, location=self.current_node) @@ -140,6 +120,7 @@ class StringHolder(ObjectHolder[str]): @noKwargs @FeatureNew('str.substring', '0.56.0') @typed_pos_args('str.substring', optargs=[int, int]) + @InterpreterObject.method('substring') def substring_method(self, args: T.Tuple[T.Optional[int], T.Optional[int]], kwargs: TYPE_kwargs) -> str: start = args[0] if args[0] is not None else 0 end = args[1] if args[1] is not None else len(self.held_object) @@ -147,6 +128,7 @@ class StringHolder(ObjectHolder[str]): @noKwargs @noPosargs + @InterpreterObject.method('to_int') def to_int_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int: try: return int(self.held_object) @@ -155,20 +137,24 @@ class StringHolder(ObjectHolder[str]): @noKwargs @noPosargs + @InterpreterObject.method('to_lower') def to_lower_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.lower() @noKwargs @noPosargs + @InterpreterObject.method('to_upper') def to_upper_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return self.held_object.upper() @noKwargs @noPosargs + @InterpreterObject.method('underscorify') def underscorify_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: return re.sub(r'[^a-zA-Z0-9]', '_', self.held_object) @noKwargs + @InterpreterObject.method('version_compare') @typed_pos_args('str.version_compare', varargs=str, min_varargs=1) def version_compare_method(self, args: T.Tuple[T.List[str]], kwargs: TYPE_kwargs) -> bool: if len(args[0]) > 1: @@ -181,10 +167,12 @@ class StringHolder(ObjectHolder[str]): @FeatureNew('/ with string arguments', '0.49.0') @typed_operator(MesonOperator.DIV, str) + @InterpreterObject.operator(MesonOperator.DIV) def op_div(self, other: str) -> str: return self._op_div(self.held_object, other) @typed_operator(MesonOperator.INDEX, int) + @InterpreterObject.operator(MesonOperator.INDEX) def op_index(self, other: int) -> str: try: return self.held_object[other] @@ -193,11 +181,13 @@ class StringHolder(ObjectHolder[str]): @FeatureNew('"in" string operator', '1.0.0') @typed_operator(MesonOperator.IN, str) + @InterpreterObject.operator(MesonOperator.IN) def op_in(self, other: str) -> bool: return other in self.held_object @FeatureNew('"not in" string operator', '1.0.0') @typed_operator(MesonOperator.NOT_IN, str) + @InterpreterObject.operator(MesonOperator.NOT_IN) def op_notin(self, other: str) -> bool: return other not in self.held_object @@ -208,6 +198,7 @@ class MesonVersionString(str): class MesonVersionStringHolder(StringHolder): @noKwargs @typed_pos_args('str.version_compare', str) + @InterpreterObject.method('version_compare') def version_compare_method(self, args: T.Tuple[str], kwargs: TYPE_kwargs) -> bool: self.interpreter.tmp_meson_version = args[0] return version_compare(self.held_object, args[0]) @@ -221,6 +212,7 @@ class DependencyVariableString(str): pass class DependencyVariableStringHolder(StringHolder): + @InterpreterObject.operator(MesonOperator.DIV) def op_div(self, other: str) -> T.Union[str, DependencyVariableString]: ret = super().op_div(other) if '..' in other: @@ -243,6 +235,7 @@ class OptionString(str): class OptionStringHolder(StringHolder): held_object: OptionString + @InterpreterObject.operator(MesonOperator.DIV) def op_div(self, other: str) -> T.Union[str, OptionString]: ret = super().op_div(other) name = self._op_div(self.held_object.optname, other) diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index 78938ba..fbe3e3e 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -11,10 +11,10 @@ from .. import compilers from ..build import (CustomTarget, BuildTarget, CustomTargetIndex, ExtractedObjects, GeneratedList, IncludeDirs, BothLibraries, SharedLibrary, StaticLibrary, Jar, Executable, StructuredSources) -from ..options import UserFeatureOption +from ..options import OptionKey, UserFeatureOption from ..dependencies import Dependency, InternalDependency from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo -from ..mesonlib import (File, FileMode, MachineChoice, listify, has_path_sep, +from ..mesonlib import (File, FileMode, MachineChoice, has_path_sep, listify, stringlistify, EnvironmentVariables) from ..programs import ExternalProgram @@ -293,11 +293,22 @@ COMMAND_KW: KwargInfo[T.List[T.Union[str, BuildTarget, CustomTarget, CustomTarge ) -OVERRIDE_OPTIONS_KW: KwargInfo[T.Union[str, T.Dict[str, ElementaryOptionValues], T.List[str]]] = KwargInfo( +def _override_options_convertor(raw: T.Union[str, T.List[str], T.Dict[str, ElementaryOptionValues]]) -> T.Dict[str, ElementaryOptionValues]: + if isinstance(raw, dict): + return raw + raw = stringlistify(raw) + output: T.Dict[str, ElementaryOptionValues] = {} + for each in raw: + k, v = split_equal_string(each) + output[k] = v + return output + +OVERRIDE_OPTIONS_KW: KwargInfo[T.Union[str, T.List[str], T.Dict[str, ElementaryOptionValues]]] = KwargInfo( 'override_options', (str, ContainerTypeInfo(list, str), ContainerTypeInfo(dict, (str, int, bool, list))), default={}, validator=_options_validator, + convertor=_override_options_convertor, since_values={dict: '1.2.0'}, ) @@ -394,7 +405,13 @@ INCLUDE_DIRECTORIES: KwargInfo[T.List[T.Union[str, IncludeDirs]]] = KwargInfo( default=[], ) -DEFAULT_OPTIONS = OVERRIDE_OPTIONS_KW.evolve(name='default_options') +def _default_options_convertor(raw: T.Union[str, T.List[str], T.Dict[str, ElementaryOptionValues]]) -> T.Dict[OptionKey, ElementaryOptionValues]: + d = _override_options_convertor(raw) + return {OptionKey.from_string(k): v for k, v in d.items()} + +DEFAULT_OPTIONS = OVERRIDE_OPTIONS_KW.evolve( + name='default_options', + convertor=_default_options_convertor) ENV_METHOD_KW = KwargInfo('method', str, default='set', since='0.62.0', validator=in_set_validator({'set', 'prepend', 'append'})) |