Interpreter: don't flatten the arguments of various methods

this fixes eg set_variable('foo', ['bar', 'baz']), which
was previously erroring out complaining about the number
of arguments.

Closes #1481
0.46
Mathieu Duponchelle 7 years ago committed by Nirbheek Chauhan
parent b6443c52ed
commit abb9a4e96f
  1. 9
      mesonbuild/interpreter.py
  2. 49
      mesonbuild/interpreterbase.py
  3. 4
      mesonbuild/modules/python.py
  4. 3
      mesonbuild/modules/unstable_icestorm.py
  5. 23
      test cases/common/198 args flattening/meson.build

@ -25,7 +25,7 @@ from .mesonlib import FileMode, Popen_safe, listify, extract_as_list, has_path_s
from .dependencies import ExternalProgram
from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException
from .interpreterbase import InterpreterBase
from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs, permittedKwargs, permittedMethodKwargs
from .interpreterbase import check_stringlist, flatten, noPosargs, noKwargs, stringArgs, permittedKwargs, permittedMethodKwargs, noArgsFlattening
from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler
from .modules import ModuleReturnValue
@ -202,6 +202,7 @@ class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
return name, val, desc
@noArgsFlattening
def set_method(self, args, kwargs):
(name, val, desc) = self.validate_args(args, kwargs)
self.held_object.values[name] = (val, desc)
@ -223,6 +224,7 @@ class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
def has_method(self, args, kwargs):
return args[0] in self.held_object.values
@noArgsFlattening
def get_method(self, args, kwargs):
if len(args) < 1 or len(args) > 2:
raise InterpreterException('Get method takes one or two arguments.')
@ -1309,6 +1311,8 @@ class ModuleHolder(InterpreterObject, ObjectHolder):
raise InvalidArguments('Module %s does not have method %s.' % (self.modname, method_name))
if method_name.startswith('_'):
raise InvalidArguments('Function {!r} in module {!r} is private.'.format(method_name, self.modname))
if not getattr(fn, 'no-args-flattening', False):
args = flatten(args)
# This is not 100% reliable but we can't use hash()
# because the Build object contains dicts and lists.
num_targets = len(self.interpreter.build.targets)
@ -1507,6 +1511,7 @@ class MesonMain(InterpreterObject):
def project_name_method(self, args, kwargs):
return self.interpreter.active_projectname
@noArgsFlattening
def get_cross_property_method(self, args, kwargs):
if len(args) < 1 or len(args) > 2:
raise InterpreterException('Must have one or two arguments.')
@ -3505,6 +3510,7 @@ This will become a hard error in the future.''')
return self.subproject != ''
@noKwargs
@noArgsFlattening
def func_set_variable(self, node, args, kwargs):
if len(args) != 2:
raise InvalidCode('Set_variable takes two arguments.')
@ -3513,6 +3519,7 @@ This will become a hard error in the future.''')
self.set_variable(varname, value)
@noKwargs
@noArgsFlattening
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.')

@ -31,6 +31,22 @@ def check_stringlist(a, msg='Arguments must be strings.'):
mlog.debug('Element not a string:', str(a))
raise InvalidArguments(msg)
def flatten(args):
if isinstance(args, mparser.StringNode):
return args.value
if isinstance(args, (int, str, mesonlib.File, InterpreterObject)):
return args
result = []
for a in args:
if isinstance(a, list):
rest = flatten(a)
result = result + rest
elif isinstance(a, mparser.StringNode):
result.append(a.value)
else:
result.append(a)
return result
def noPosargs(f):
@wraps(f)
def wrapped(self, node, args, kwargs):
@ -55,6 +71,10 @@ def stringArgs(f):
return f(self, node, args, kwargs)
return wrapped
def noArgsFlattening(f):
setattr(f, 'no-args-flattening', True)
return f
class permittedKwargs:
def __init__(self, permitted):
@ -114,7 +134,10 @@ class InterpreterObject:
def method_call(self, method_name, args, kwargs):
if method_name in self.methods:
return self.methods[method_name](args, kwargs)
method = self.methods[method_name]
if not getattr(method, 'no-args-flattening', False):
args = flatten(args)
return method(args, kwargs)
raise InvalidCode('Unknown method "%s" in object.' % method_name)
class MutableInterpreterObject(InterpreterObject):
@ -474,7 +497,11 @@ The result of this is undefined and will become a hard error in a future Meson r
if is_disabled(posargs, kwargs):
return Disabler()
if func_name in self.funcs:
return self.funcs[func_name](node, self.flatten(posargs), kwargs)
func = self.funcs[func_name]
if not getattr(func, 'no-args-flattening', False):
posargs = flatten(posargs)
return func(node, posargs, kwargs)
else:
self.unknown_function_called(func_name)
@ -508,7 +535,7 @@ The result of this is undefined and will become a hard error in a future Meson r
return Disabler()
if method_name == 'extract_objects':
self.validate_extraction(obj.held_object)
return obj.method_call(method_name, self.flatten(args), kwargs)
return obj.method_call(method_name, args, kwargs)
def bool_method_call(self, obj, method_name, args):
(posargs, kwargs) = self.reduce_arguments(args)
@ -668,22 +695,6 @@ The result of this is undefined and will become a hard error in a future Meson r
self.argument_depth -= 1
return reduced_pos, reduced_kw
def flatten(self, args):
if isinstance(args, mparser.StringNode):
return args.value
if isinstance(args, (int, str, mesonlib.File, InterpreterObject)):
return args
result = []
for a in args:
if isinstance(a, list):
rest = self.flatten(a)
result = result + rest
elif isinstance(a, mparser.StringNode):
result.append(a.value)
else:
result.append(a)
return result
def assignment(self, node):
assert(isinstance(node, mparser.AssignmentNode))
if self.argument_depth != 0:

@ -25,6 +25,7 @@ from ..interpreterbase import (
InterpreterObject, InvalidArguments
)
from ..interpreter import ExternalProgramHolder
from ..interpreterbase import flatten
from ..build import known_shmod_kwargs
from .. import mlog
from ..environment import detect_cpu_family
@ -415,6 +416,9 @@ class PythonInstallation(ExternalProgramHolder, InterpreterObject):
except AttributeError:
raise InvalidArguments('Python object does not have method %s.' % method_name)
if not getattr(fn, 'no-args-flattening', False):
args = flatten(args)
if method_name in ['extension_module', 'dependency', 'install_sources']:
value = fn(self.interpreter, None, args, kwargs)
return self.interpreter.holderify(value)

@ -13,6 +13,7 @@
# limitations under the License.
from .. import mesonlib
from ..interpreterbase import flatten
from . import ExtensionModule
@ -42,7 +43,7 @@ class IceStormModule(ExtensionModule):
kwarg_sources = kwargs.get('sources', [])
if not isinstance(kwarg_sources, list):
kwarg_sources = [kwarg_sources]
all_sources = interpreter.source_strings_to_files(interpreter.flatten(arg_sources + kwarg_sources))
all_sources = interpreter.source_strings_to_files(flatten(arg_sources + kwarg_sources))
if 'constraint_file' not in kwargs:
raise mesonlib.MesonException('Constraint file not specified.')

@ -0,0 +1,23 @@
project('args flattening')
arr = get_variable('does-not-exist', ['bar', 'baz'])
assert(arr == ['bar', 'baz'], 'get_variable with array fallback is broken')
set_variable('arr', ['bar', 'baz'])
assert(arr == ['bar', 'baz'], 'set_variable(array) is broken')
conf = configuration_data()
conf.set('foo', ['bar', 'baz'])
assert(conf.get('foo') == ['bar', 'baz'], 'configuration_data.set(array) is broken')
arr = conf.get('does-not-exist', ['bar', 'baz'])
assert(arr == ['bar', 'baz'], 'configuration_data.get with array fallback is broken')
arr = meson.get_cross_property('does-not-exist', ['bar', 'baz'])
assert(arr == ['bar', 'baz'], 'meson.get_cross_property with array fallback is broken')
Loading…
Cancel
Save