holders: Ensure that InterpreterBase is the sole instance for (un)holderifying

pull/8903/head
Daniel Mensinger 4 years ago
parent 6879e84c48
commit c2c7f7c9d7
  1. 128
      mesonbuild/interpreter/interpreter.py
  2. 19
      mesonbuild/interpreter/interpreterobjects.py
  3. 2
      mesonbuild/interpreterbase/__init__.py
  4. 37
      mesonbuild/interpreterbase/_unholder.py
  5. 12
      mesonbuild/interpreterbase/decorators.py
  6. 8
      mesonbuild/interpreterbase/helpers.py
  7. 149
      mesonbuild/interpreterbase/interpreterbase.py

@ -21,33 +21,35 @@ from .. import optinterpreter
from .. import compilers
from ..wrap import wrap, WrapMode
from .. import mesonlib
from ..mesonlib import FileMode, MachineChoice, OptionKey, listify, extract_as_list, has_path_sep, unholder
from ..mesonlib import HoldableObject, FileMode, MachineChoice, OptionKey, listify, extract_as_list, has_path_sep
from ..programs import ExternalProgram, NonExistingExternalProgram
from ..dependencies import Dependency
from ..depfile import DepFile
from ..interpreterbase import ContainerTypeInfo, InterpreterBase, KwargInfo, typed_kwargs, typed_pos_args
from ..interpreterbase import noPosargs, noKwargs, stringArgs, permittedKwargs, noArgsFlattening
from ..interpreterbase import noPosargs, noKwargs, stringArgs, permittedKwargs, noArgsFlattening, unholder_return
from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
from ..interpreterbase import InterpreterObject, Disabler, disablerIfNotFound
from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs, FeatureDeprecatedKwargs
from ..interpreterbase import ObjectHolder, RangeHolder
from ..interpreterbase import TYPE_nkwargs, TYPE_nvar, TYPE_var
from ..modules import ModuleObject, MutableModuleObject
from ..cmake import CMakeInterpreter
from ..backend.backends import Backend, ExecutableSerialisation
from . import interpreterobjects as OBJ
from . import compiler as compilerOBJ
from .mesonmain import MesonMain
from .compiler import CompilerHolder
from .interpreterobjects import (SubprojectHolder, MachineHolder, EnvironmentVariablesHolder,
FeatureOptionHolder, ExternalProgramHolder, CustomTargetHolder,
RunTargetHolder, IncludeDirsHolder, ConfigurationDataHolder,
DependencyHolder, ModuleObjectHolder, GeneratedListHolder,
TargetHolder, CustomTargetIndexHolder, GeneratedObjectsHolder,
StaticLibraryHolder, ExecutableHolder, SharedLibraryHolder,
SharedModuleHolder, HeadersHolder, BothLibrariesHolder,
BuildTargetHolder, DataHolder, JarHolder, Test, RunProcess,
ManHolder, GeneratorHolder, InstallDirHolder, extract_required_kwarg,
extract_search_dirs, MutableModuleObjectHolder, FileHolder)
from .dependencyfallbacks import DependencyFallbacksHolder
from .interpreterobjects import (
SubprojectHolder,
EnvironmentVariablesObject,
ConfigurationDataObject,
Test,
RunProcess,
extract_required_kwarg,
extract_search_dirs,
NullSubprojectInterpreter,
)
from pathlib import Path
import os
@ -386,45 +388,70 @@ class Interpreter(InterpreterBase, HoldableObject):
if 'MESON_UNIT_TEST' in os.environ:
self.funcs.update({'exception': self.func_exception})
def holderify(self, item):
if isinstance(item, list):
return [self.holderify(x) for x in item]
if isinstance(item, dict):
return {k: self.holderify(v) for k, v in item.items()}
if isinstance(item, build.CustomTarget):
return CustomTargetHolder(item, self)
elif isinstance(item, (int, str, bool, InterpreterObject)) or item is None:
return item
elif isinstance(item, build.Executable):
return ExecutableHolder(item, self)
elif isinstance(item, build.GeneratedList):
return GeneratedListHolder(item)
elif isinstance(item, build.RunTarget):
raise RuntimeError('This is not a pipe.')
elif isinstance(item, ExecutableSerialisation):
raise RuntimeError('Do not do this.')
elif isinstance(item, build.Data):
return DataHolder(item)
elif isinstance(item, dependencies.Dependency):
return DependencyHolder(item, self.subproject)
elif isinstance(item, ExternalProgram):
return ExternalProgramHolder(item, self.subproject)
elif isinstance(item, MutableModuleObject):
return MutableModuleObjectHolder(item, self)
elif isinstance(item, ModuleObject):
return ModuleObjectHolder(item, self)
elif isinstance(item, mesonlib.File):
return FileHolder(item)
else:
raise InterpreterException('Module returned a value of unknown type.')
def process_new_values(self, invalues):
def build_holder_map(self) -> None:
'''
Build a mapping of `HoldableObject` types to their corresponding
`ObjectHolder`s. This mapping is used in `InterpreterBase` to automatically
holderify all returned values from methods and functions.
'''
self.holder_map.update({
mesonlib.File: OBJ.FileHolder,
build.SharedLibrary: OBJ.SharedLibraryHolder,
build.StaticLibrary: OBJ.StaticLibraryHolder,
build.BothLibraries: OBJ.BothLibrariesHolder,
build.SharedModule: OBJ.SharedModuleHolder,
build.Executable: OBJ.ExecutableHolder,
build.Jar: OBJ.JarHolder,
build.CustomTarget: OBJ.CustomTargetHolder,
build.CustomTargetIndex: OBJ.CustomTargetIndexHolder,
build.Generator: OBJ.GeneratorHolder,
build.GeneratedList: OBJ.GeneratedListHolder,
build.ExtractedObjects: OBJ.GeneratedObjectsHolder,
build.RunTarget: OBJ.RunTargetHolder,
build.AliasTarget: OBJ.AliasTargetHolder,
build.Headers: OBJ.HeadersHolder,
build.Man: OBJ.ManHolder,
build.Data: OBJ.DataHolder,
build.InstallDir: OBJ.InstallDirHolder,
build.IncludeDirs: OBJ.IncludeDirsHolder,
compilers.RunResult: compilerOBJ.TryRunResultHolder,
dependencies.ExternalLibrary: OBJ.ExternalLibraryHolder,
coredata.UserFeatureOption: OBJ.FeatureOptionHolder,
})
'''
Build a mapping of `HoldableObject` base classes to their
corresponding `ObjectHolder`s. The difference to `self.holder_map`
is that the keys here define an upper bound instead of requireing an
exact match.
The mappings defined here are only used when there was no direct hit
found in `self.holder_map`.
'''
self.bound_holder_map.update({
dependencies.Dependency: OBJ.DependencyHolder,
ExternalProgram: OBJ.ExternalProgramHolder,
compilers.Compiler: compilerOBJ.CompilerHolder,
ModuleObject: OBJ.ModuleObjectHolder,
MutableModuleObject: OBJ.MutableModuleObjectHolder,
})
def append_holder_map(self, held_type: T.Type[mesonlib.HoldableObject], holder_type: T.Type[ObjectHolder]) -> None:
'''
Adds one additional mapping to the `holder_map`.
The intended use for this function is in the `initialize` method of
modules to register custom object holders.
'''
self.holder_map.update({
held_type: holder_type
})
def process_new_values(self, invalues: T.List[TYPE_var]) -> None:
invalues = listify(invalues)
for v in invalues:
if isinstance(v, (RunTargetHolder, CustomTargetHolder, BuildTargetHolder)):
v = v.held_object
if isinstance(v, ObjectHolder):
raise InterpreterException('Modules must not return ObjectHolders')
if isinstance(v, (build.BuildTarget, build.CustomTarget, build.RunTarget)):
self.add_target(v.name, v)
elif isinstance(v, list):
@ -2647,6 +2674,7 @@ This will become a hard error in the future.''', location=self.current_node)
@noKwargs
@noArgsFlattening
@unholder_return
def func_get_variable(self, node, args, kwargs):
if len(args) < 1 or len(args) > 2:
raise InvalidCode('Get_variable takes one or two arguments.')

@ -13,15 +13,13 @@ from .. import mlog
from ..modules import ModuleReturnValue, ModuleObject, ModuleState, ExtensionModule
from ..backend.backends import TestProtocol
from ..interpreterbase import (ContainerTypeInfo, KwargInfo,
MesonInterpreterObject, ObjectHolder, MutableInterpreterObject,
FeatureNewKwargs, FeatureNew, FeatureDeprecated,
typed_kwargs, typed_pos_args, stringArgs,
permittedKwargs, noArgsFlattening, noPosargs,
TYPE_var, TYPE_nkwargs, flatten,
InterpreterException, InvalidArguments,
InvalidCode)
from ..interpreterbase.decorators import FeatureCheckBase
from ..interpreterbase import (
ContainerTypeInfo, KwargInfo,
InterpreterObject, MesonInterpreterObject, ObjectHolder, MutableInterpreterObject,
FeatureCheckBase, FeatureNewKwargs, FeatureNew, FeatureDeprecated,
typed_pos_args, typed_kwargs, KwargInfo, stringArgs, permittedKwargs,
noArgsFlattening, noPosargs, noKwargs, unholder_return, TYPE_var, TYPE_kwargs, TYPE_nvar, TYPE_nkwargs,
flatten, InterpreterException, InvalidArguments, InvalidCode)
from ..dependencies import Dependency, ExternalLibrary, InternalDependency
from ..programs import ExternalProgram
from ..mesonlib import HoldableObject, MesonException, OptionKey, listify, Popen_safe
@ -751,7 +749,8 @@ class SubprojectHolder(ObjectHolder[T.Optional['Interpreter']]):
@permittedKwargs({})
@noArgsFlattening
def get_variable_method(self, args, kwargs):
@unholder_return
def get_variable_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]:
if len(args) < 1 or len(args) > 2:
raise InterpreterException('Get_variable takes one or two arguments.')
if not self.found():

@ -39,6 +39,7 @@ __all__ = [
'noKwargs',
'stringArgs',
'noArgsFlattening',
'unholder_return',
'disablerIfNotFound',
'permittedKwargs',
'typed_pos_args',
@ -87,6 +88,7 @@ from .decorators import (
noKwargs,
stringArgs,
noArgsFlattening,
unholder_return,
disablerIfNotFound,
permittedKwargs,
typed_pos_args,

@ -0,0 +1,37 @@
# Copyright 2013-2021 The Meson development team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from .baseobjects import InterpreterObject, MesonInterpreterObject, ObjectHolder, TYPE_var
from .exceptions import InvalidArguments
from ..mesonlib import HoldableObject, MesonBugException
import typing as T
def _unholder(obj: T.Union[TYPE_var, InterpreterObject]) -> TYPE_var:
if isinstance(obj, (int, bool, str)):
return obj
elif isinstance(obj, list):
return [_unholder(x) for x in obj]
elif isinstance(obj, dict):
return {k: _unholder(v) for k, v in obj.items()}
elif isinstance(obj, ObjectHolder):
assert isinstance(obj.held_object, HoldableObject)
return obj.held_object
elif isinstance(obj, MesonInterpreterObject):
return obj
elif isinstance(obj, HoldableObject):
raise MesonBugException(f'Argument {obj} of type {type(obj).__name__} is not held by an ObjectHolder.')
elif isinstance(obj, InterpreterObject):
raise InvalidArguments(f'Argument {obj} of type {type(obj).__name__} cannot be passed to a method or function')
raise MesonBugException(f'Unknown object {obj} of type {type(obj).__name__} in the parameters.')

@ -13,10 +13,11 @@
# limitations under the License.
from .. import mesonlib, mlog
from .baseobjects import TV_func, TYPE_nvar
from .baseobjects import TV_func, TYPE_var
from .disabler import Disabler
from .exceptions import InterpreterException, InvalidArguments
from .helpers import check_stringlist, get_callee_args
from ._unholder import _unholder
from functools import wraps
import abc
@ -67,13 +68,20 @@ def noArgsFlattening(f: TV_func) -> TV_func:
setattr(f, 'no-args-flattening', True) # noqa: B010
return f
def unholder_return(f: TV_func) -> T.Callable[..., TYPE_var]:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
res = f(*wrapped_args, **wrapped_kwargs)
return _unholder(res)
return T.cast(T.Callable[..., TYPE_var], wrapped)
def disablerIfNotFound(f: TV_func) -> TV_func:
@wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
kwargs = get_callee_args(wrapped_args)[3]
disabler = kwargs.pop('disabler', False)
ret = f(*wrapped_args, **wrapped_kwargs)
if disabler and not ret.held_object.found():
if disabler and not ret.found():
return Disabler()
return ret
return T.cast(TV_func, wrapped)

@ -19,15 +19,15 @@ import collections.abc
import typing as T
if T.TYPE_CHECKING:
from .baseobjects import TYPE_nvar, TV_fw_args, TV_fw_kwargs
from .baseobjects import TYPE_var, TYPE_kwargs
def flatten(args: T.Union['TYPE_nvar', T.List['TYPE_nvar']]) -> T.List['TYPE_nvar']:
def flatten(args: T.Union['TYPE_var', T.List['TYPE_var']]) -> T.List['TYPE_var']:
if isinstance(args, mparser.StringNode):
assert isinstance(args.value, str)
return [args.value]
if not isinstance(args, collections.abc.Sequence):
return [args]
result: T.List['TYPE_nvar'] = []
result: T.List['TYPE_var'] = []
for a in args:
if isinstance(a, list):
rest = flatten(a)
@ -51,7 +51,7 @@ def default_resolve_key(key: mparser.BaseNode) -> str:
raise InterpreterException('Invalid kwargs format.')
return key.value
def get_callee_args(wrapped_args: T.Sequence[T.Any], want_subproject: bool = False) -> T.Tuple[T.Any, mparser.BaseNode, 'TV_fw_args', 'TV_fw_kwargs', T.Optional[str]]:
def get_callee_args(wrapped_args: T.Sequence[T.Any], want_subproject: bool = False) -> T.Tuple[T.Any, mparser.BaseNode, T.List['TYPE_var'], 'TYPE_kwargs', T.Optional[str]]:
s = wrapped_args[0]
n = len(wrapped_args)
# Raise an error if the codepaths are not there

@ -20,13 +20,15 @@ from .. import environment, dependencies
from .baseobjects import (
InterpreterObject,
MesonInterpreterObject,
MutableInterpreterObject,
InterpreterObjectTypeVar,
ObjectHolder,
RangeHolder,
TYPE_elementary,
TYPE_var,
TYPE_nvar,
TYPE_nkwargs,
TYPE_kwargs,
)
from .exceptions import (
@ -41,10 +43,24 @@ from .exceptions import (
from .decorators import FeatureNew, builtinMethodNoKwargs
from .disabler import Disabler, is_disabled
from .helpers import check_stringlist, default_resolve_key, flatten
from ._unholder import _unholder
import os, copy, re
import typing as T
if T.TYPE_CHECKING:
from ..interpreter import Interpreter
HolderMapType = T.Dict[
T.Type[mesonlib.HoldableObject],
# For some reason, this has to be a callable and can't just be ObjectHolder[InterpreterObjectTypeVar]
T.Callable[[InterpreterObjectTypeVar, 'Interpreter'], ObjectHolder[InterpreterObjectTypeVar]]
]
FunctionType = T.Dict[
str,
T.Callable[[mparser.BaseNode, T.List[TYPE_var], T.Dict[str, TYPE_var]], TYPE_var]
]
class MesonVersionString(str):
pass
@ -54,12 +70,16 @@ class InterpreterBase:
def __init__(self, source_root: str, subdir: str, subproject: str):
self.source_root = source_root
self.funcs = {} # type: T.Dict[str, T.Callable[[mparser.BaseNode, T.List[TYPE_nvar], T.Dict[str, TYPE_nvar]], TYPE_var]]
self.builtin = {} # type: T.Dict[str, InterpreterObject]
self.funcs: FunctionType = {}
self.builtin: T.Dict[str, InterpreterObject] = {}
# Holder maps store a mapping from an HoldableObject to a class ObjectHolder
self.holder_map: HolderMapType = {}
self.bound_holder_map: HolderMapType = {}
self.subdir = subdir
self.root_subdir = subdir
self.subproject = subproject
self.variables = {} # type: T.Dict[str, TYPE_var]
# TODO: This should actually be more strict: T.Union[TYPE_elementary, InterpreterObject]
self.variables: T.Dict[str, T.Union[TYPE_var, InterpreterObject]] = {}
self.argument_depth = 0
self.current_lineno = -1
# Current node set during a function call. This can be used as location
@ -137,7 +157,7 @@ class InterpreterBase:
raise e
i += 1 # In THE FUTURE jump over blocks and stuff.
def evaluate_statement(self, cur: mparser.BaseNode) -> T.Optional[TYPE_var]:
def evaluate_statement(self, cur: mparser.BaseNode) -> T.Optional[T.Union[TYPE_var, InterpreterObject]]:
self.current_node = cur
if isinstance(cur, mparser.FunctionNode):
return self.function_call(cur)
@ -191,14 +211,14 @@ class InterpreterBase:
raise InvalidCode("Unknown statement.")
return None
def evaluate_arraystatement(self, cur: mparser.ArrayNode) -> list:
def evaluate_arraystatement(self, cur: mparser.ArrayNode) -> T.List[T.Union[TYPE_var, InterpreterObject]]:
(arguments, kwargs) = self.reduce_arguments(cur.args)
if len(kwargs) > 0:
raise InvalidCode('Keyword arguments are invalid in array construction.')
return arguments
@FeatureNew('dict', '0.47.0')
def evaluate_dictstatement(self, cur: mparser.DictNode) -> TYPE_nkwargs:
def evaluate_dictstatement(self, cur: mparser.DictNode) -> T.Union[TYPE_var, InterpreterObject]:
def resolve_key(key: mparser.BaseNode) -> str:
if not isinstance(key, mparser.StringNode):
FeatureNew.single_use('Dictionary entry using non literal key', '0.53.0', self.subproject)
@ -387,7 +407,7 @@ The result of this is undefined and will become a hard error in a future Meson r
else:
raise InvalidCode('You broke me.')
def evaluate_ternary(self, node: mparser.TernaryNode) -> TYPE_var:
def evaluate_ternary(self, node: mparser.TernaryNode) -> T.Union[TYPE_var, InterpreterObject]:
assert(isinstance(node, mparser.TernaryNode))
result = self.evaluate_statement(node.condition)
if isinstance(result, Disabler):
@ -479,7 +499,7 @@ The result of this is undefined and will become a hard error in a future Meson r
raise InvalidArguments('The += operator currently only works with arrays, dicts, strings or ints')
self.set_variable(varname, new_value)
def evaluate_indexing(self, node: mparser.IndexNode) -> TYPE_var:
def evaluate_indexing(self, node: mparser.IndexNode) -> T.Union[TYPE_elementary, InterpreterObject]:
assert(isinstance(node, mparser.IndexNode))
iobject = self.evaluate_statement(node.iobject)
if isinstance(iobject, Disabler):
@ -494,7 +514,7 @@ The result of this is undefined and will become a hard error in a future Meson r
raise InterpreterException('Key is not a string')
try:
# The cast is required because we don't have recursive types...
return T.cast(TYPE_var, iobject[index])
return T.cast(T.Union[TYPE_elementary, InterpreterObject], iobject[index])
except KeyError:
raise InterpreterException('Key %s is not in dict' % index)
else:
@ -504,35 +524,45 @@ The result of this is undefined and will become a hard error in a future Meson r
# Ignore the MyPy error, since we don't know all indexable types here
# and we handle non indexable types with an exception
# TODO maybe find a better solution
return iobject[index] # type: ignore
res = iobject[index] # type: ignore
# Only holderify if we are dealing with `InterpreterObject`, since raw
# lists already store ObjectHolders
if isinstance(iobject, InterpreterObject):
return self._holderify(res)
else:
return res
except IndexError:
# We are already checking for the existence of __getitem__, so this should be save
raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject))) # type: ignore
def function_call(self, node: mparser.FunctionNode) -> T.Optional[TYPE_var]:
def function_call(self, node: mparser.FunctionNode) -> T.Optional[T.Union[TYPE_elementary, InterpreterObject]]:
func_name = node.func_name
(posargs, kwargs) = self.reduce_arguments(node.args)
(h_posargs, h_kwargs) = self.reduce_arguments(node.args)
(posargs, kwargs) = self._unholder_args(h_posargs, h_kwargs)
if is_disabled(posargs, kwargs) and func_name not in {'get_variable', 'set_variable', 'is_disabler'}:
return Disabler()
if func_name in self.funcs:
func = self.funcs[func_name]
func_args = posargs # type: T.Any
func_args = posargs
if not getattr(func, 'no-args-flattening', False):
func_args = flatten(posargs)
return func(node, func_args, kwargs)
res = func(node, func_args, kwargs)
return self._holderify(res)
else:
self.unknown_function_called(func_name)
return None
def method_call(self, node: mparser.MethodNode) -> TYPE_var:
def method_call(self, node: mparser.MethodNode) -> T.Optional[T.Union[TYPE_var, InterpreterObject]]:
invokable = node.source_object
obj: T.Union[TYPE_var, InterpreterObject]
if isinstance(invokable, mparser.IdNode):
object_name = invokable.value
obj = self.get_variable(object_name)
else:
obj = self.evaluate_statement(invokable)
method_name = node.name
(args, kwargs) = self.reduce_arguments(node.args)
(h_args, h_kwargs) = self.reduce_arguments(node.args)
(args, kwargs) = self._unholder_args(h_args, h_kwargs)
if is_disabled(args, kwargs):
return Disabler()
if isinstance(obj, str):
@ -554,15 +584,48 @@ The result of this is undefined and will become a hard error in a future Meson r
return False
else:
return Disabler()
# TODO: InterpreterBase **really** shouldn't be in charge of checking this
if method_name == 'extract_objects':
if not isinstance(obj, ObjectHolder):
raise InvalidArguments(f'Invalid operation "extract_objects" on variable "{object_name}"')
raise InvalidArguments(f'Invalid operation "extract_objects" on variable "{object_name}" of type {type(obj).__name__}')
self.validate_extraction(obj.held_object)
obj.current_node = node
return obj.method_call(method_name, args, kwargs)
return self._holderify(obj.method_call(method_name, args, kwargs))
def _holderify(self, res: T.Optional[TYPE_var]) -> T.Union[TYPE_elementary, InterpreterObject]:
if res is None:
return None
if isinstance(res, (int, bool, str)):
return res
elif isinstance(res, list):
return [self._holderify(x) for x in res]
elif isinstance(res, dict):
return {k: self._holderify(v) for k, v in res.items()}
elif isinstance(res, mesonlib.HoldableObject):
# Always check for an exact match first.
cls = self.holder_map.get(type(res), None)
if cls is not None:
# Casts to Interpreter are required here since an assertion would
# not work for the `ast` module.
return cls(res, T.cast('Interpreter', self))
# Try the boundary types next.
for typ, cls in self.bound_holder_map.items():
if isinstance(res, typ):
return cls(res, T.cast('Interpreter', self))
raise mesonlib.MesonBugException(f'Object {res} of type {type(res).__name__} is neither in self.holder_map nor self.bound_holder_map.')
elif isinstance(res, ObjectHolder):
raise mesonlib.MesonBugException(f'Returned object {res} of type {type(res).__name__} is an object holder.')
elif isinstance(res, MesonInterpreterObject):
return res
raise mesonlib.MesonBugException(f'Unknown returned object {res} of type {type(res).__name__} in the parameters.')
def _unholder_args(self,
args: T.List[T.Union[TYPE_var, InterpreterObject]],
kwargs: T.Dict[str, T.Union[TYPE_var, InterpreterObject]]) -> T.Tuple[T.List[TYPE_var], TYPE_kwargs]:
return [_unholder(x) for x in args], {k: _unholder(v) for k, v in kwargs.items()}
@builtinMethodNoKwargs
def bool_method_call(self, obj: bool, method_name: str, posargs: T.List[TYPE_nvar], kwargs: T.Dict[str, T.Any]) -> T.Union[str, int]:
def bool_method_call(self, obj: bool, method_name: str, posargs: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, int]:
if method_name == 'to_string':
if not posargs:
if obj:
@ -585,7 +648,7 @@ The result of this is undefined and will become a hard error in a future Meson r
raise InterpreterException('Unknown method "%s" for a boolean.' % method_name)
@builtinMethodNoKwargs
def int_method_call(self, obj: int, method_name: str, posargs: T.List[TYPE_nvar], kwargs: T.Dict[str, T.Any]) -> T.Union[str, bool]:
def int_method_call(self, obj: int, method_name: str, posargs: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, bool]:
if method_name == 'is_even':
if not posargs:
return obj % 2 == 0
@ -605,7 +668,7 @@ The result of this is undefined and will become a hard error in a future Meson r
raise InterpreterException('Unknown method "%s" for an integer.' % method_name)
@staticmethod
def _get_one_string_posarg(posargs: T.List[TYPE_nvar], method_name: str) -> str:
def _get_one_string_posarg(posargs: T.List[TYPE_var], method_name: str) -> str:
if len(posargs) > 1:
m = '{}() must have zero or one arguments'
raise InterpreterException(m.format(method_name))
@ -618,7 +681,7 @@ The result of this is undefined and will become a hard error in a future Meson r
return None
@builtinMethodNoKwargs
def string_method_call(self, obj: str, method_name: str, posargs: T.List[TYPE_nvar], kwargs: T.Dict[str, T.Any]) -> T.Union[str, int, bool, T.List[str]]:
def string_method_call(self, obj: str, method_name: str, posargs: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, int, bool, T.List[str]]:
if method_name == 'strip':
s1 = self._get_one_string_posarg(posargs, 'strip')
if s1 is not None:
@ -690,7 +753,7 @@ The result of this is undefined and will become a hard error in a future Meson r
return obj.replace(posargs[0], posargs[1])
raise InterpreterException('Unknown method "%s" for a string.' % method_name)
def format_string(self, templ: str, args: T.List[TYPE_nvar]) -> str:
def format_string(self, templ: str, args: T.List[TYPE_var]) -> str:
arg_strings = []
for arg in args:
if isinstance(arg, mparser.BaseNode):
@ -711,7 +774,11 @@ The result of this is undefined and will become a hard error in a future Meson r
raise InvalidCode('Unknown function "%s".' % func_name)
@builtinMethodNoKwargs
def array_method_call(self, obj: T.List[TYPE_var], method_name: str, posargs: T.List[TYPE_nvar], kwargs: T.Dict[str, T.Any]) -> TYPE_var:
def array_method_call(self,
obj: T.List[T.Union[TYPE_elementary, InterpreterObject]],
method_name: str,
posargs: T.List[TYPE_var],
kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]:
if method_name == 'contains':
def check_contains(el: list) -> bool:
if len(posargs) != 1:
@ -752,7 +819,11 @@ The result of this is undefined and will become a hard error in a future Meson r
raise InterpreterException(m.format(method_name))
@builtinMethodNoKwargs
def dict_method_call(self, obj: T.Dict[str, TYPE_var], method_name: str, posargs: T.List[TYPE_nvar], kwargs: T.Dict[str, T.Any]) -> TYPE_var:
def dict_method_call(self,
obj: T.Dict[str, T.Union[TYPE_elementary, InterpreterObject]],
method_name: str,
posargs: T.List[TYPE_var],
kwargs: TYPE_kwargs) -> T.Union[TYPE_var, InterpreterObject]:
if method_name in ('has_key', 'get'):
if method_name == 'has_key':
if len(posargs) != 1:
@ -793,18 +864,20 @@ The result of this is undefined and will become a hard error in a future Meson r
args: mparser.ArgumentNode,
key_resolver: T.Callable[[mparser.BaseNode], str] = default_resolve_key,
duplicate_key_error: T.Optional[str] = None,
) -> T.Tuple[T.List[TYPE_nvar], TYPE_nkwargs]:
) -> T.Tuple[
T.List[T.Union[TYPE_var, InterpreterObject]],
T.Dict[str, T.Union[TYPE_var, InterpreterObject]]
]:
assert(isinstance(args, mparser.ArgumentNode))
if args.incorrect_order():
raise InvalidArguments('All keyword arguments must be after positional arguments.')
self.argument_depth += 1
reduced_pos = [self.evaluate_statement(arg) for arg in args.arguments] # type: T.List[TYPE_nvar]
reduced_kw = {} # type: TYPE_nkwargs
reduced_pos: T.List[T.Union[TYPE_var, InterpreterObject]] = [self.evaluate_statement(arg) for arg in args.arguments]
reduced_kw: T.Dict[str, T.Union[TYPE_var, InterpreterObject]] = {}
for key, val in args.kwargs.items():
reduced_key = key_resolver(key)
reduced_val = val # type: TYPE_nvar
if isinstance(reduced_val, mparser.BaseNode):
reduced_val = self.evaluate_statement(reduced_val)
assert isinstance(val, mparser.BaseNode)
reduced_val = self.evaluate_statement(val)
if duplicate_key_error and reduced_key in reduced_kw:
raise InvalidArguments(duplicate_key_error.format(reduced_key))
reduced_kw[reduced_key] = reduced_val
@ -812,7 +885,7 @@ The result of this is undefined and will become a hard error in a future Meson r
final_kw = self.expand_default_kwargs(reduced_kw)
return reduced_pos, final_kw
def expand_default_kwargs(self, kwargs: TYPE_nkwargs) -> TYPE_nkwargs:
def expand_default_kwargs(self, kwargs: T.Dict[str, T.Union[TYPE_var, InterpreterObject]]) -> T.Dict[str, T.Union[TYPE_var, InterpreterObject]]:
if 'kwargs' not in kwargs:
return kwargs
to_expand = kwargs.pop('kwargs')
@ -843,7 +916,7 @@ To specify a keyword argument, use : instead of =.''')
self.set_variable(var_name, value)
return None
def set_variable(self, varname: str, variable: TYPE_var) -> None:
def set_variable(self, varname: str, variable: T.Union[TYPE_var, InterpreterObject]) -> None:
if variable is None:
raise InvalidCode('Can not assign None to variable.')
if not isinstance(varname, str):
@ -856,7 +929,7 @@ To specify a keyword argument, use : instead of =.''')
raise InvalidCode('Tried to overwrite internal variable "%s"' % varname)
self.variables[varname] = variable
def get_variable(self, varname: str) -> TYPE_var:
def get_variable(self, varname: str) -> T.Union[TYPE_var, InterpreterObject]:
if varname in self.builtin:
return self.builtin[varname]
if varname in self.variables:
@ -865,7 +938,7 @@ To specify a keyword argument, use : instead of =.''')
def is_assignable(self, value: T.Any) -> bool:
return isinstance(value, (InterpreterObject, dependencies.Dependency,
str, int, list, dict))
str, int, list, dict, mesonlib.File))
def validate_extraction(self, buildtarget: InterpreterObject) -> None:
def validate_extraction(self, buildtarget: mesonlib.HoldableObject) -> None:
raise InterpreterException('validate_extraction is not implemented in this context (please file a bug)')

Loading…
Cancel
Save