interpreter: split keyword definitions out of the interpreter

pull/9066/head
Dylan Baker 3 years ago committed by Xavier Claessens
parent 40d5a38d1b
commit d1b52b913f
  1. 119
      mesonbuild/interpreter/interpreter.py
  2. 106
      mesonbuild/interpreter/type_checking.py

@ -50,6 +50,12 @@ from .interpreterobjects import (
extract_search_dirs,
NullSubprojectInterpreter,
)
from .type_checking import (
INSTALL_MODE_KW,
LANGUAGE_KW,
NATIVE_KW,
REQUIRED_KW,
)
from pathlib import Path
import os
@ -74,101 +80,6 @@ if T.TYPE_CHECKING:
build.GeneratedList]
def _language_validator(l: T.List[str]) -> T.Optional[str]:
"""Validate language keyword argument.
Particularly for functions like `add_compiler()`, and `add_*_args()`
"""
diff = {a.lower() for a in l}.difference(compilers.all_languages)
if diff:
return f'unknown languages: {", ".join(diff)}'
return None
def _install_mode_validator(mode: T.List[T.Union[str, bool, int]]) -> T.Optional[str]:
"""Validate the `install_mode` keyword argument.
This is a rather odd thing, it's a scalar, or an array of 3 values in the form:
[(str | False), (str | int | False) = False, (str | int | False) = False]
Where the second and third arguments are not required, and are considered to
default to False.
"""
if not mode:
return None
if True in mode:
return 'can only be a string or false, not true'
if len(mode) > 3:
return 'may have at most 3 elements'
perms = mode[0]
if not isinstance(perms, (str, bool)):
return 'permissions part must be a string or false'
if isinstance(perms, str):
if not len(perms) == 9:
return (f'permissions string must be exactly 9 characters, got "{len(perms)}" '
'in the form rwxr-xr-x')
for i in [0, 3, 6]:
if perms[i] not in {'-', 'r'}:
return f'bit {i} must be "-" or "r", not {perms[i]}'
for i in [1, 4, 7]:
if perms[i] not in {'-', 'w'}:
return f'bit {i} must be "-" or "w", not {perms[i]}'
for i in [2, 5]:
if perms[i] not in {'-', 'x', 's', 'S'}:
return f'bit {i} must be "-", "s", "S", or "x", not {perms[i]}'
if perms[8] not in {'-', 'x', 't', 'T'}:
return f'bit 8 must be "-", "t", "T", or "x", not {perms[8]}'
if len(mode) >= 2 and not isinstance(mode[1], (int, str, bool)):
return 'second componenent must be a string, number, or False if provided'
if len(mode) >= 3 and not isinstance(mode[2], (int, str, bool)):
return 'third componenent must be a string, number, or False if provided'
return None
def _install_mode_convertor(mode: T.Optional[T.List[T.Union[str, bool, int]]]) -> FileMode:
"""Convert the DSL form of the `install_mode` keyword arugment to `FileMode`
This is not required, and if not required returns None
TODO: It's not clear to me why this needs to be None and not just return an
emtpy FileMode.
"""
# this has already been validated by the validator
return FileMode(*[m if isinstance(m, str) else None for m in mode])
_NATIVE_KW = KwargInfo(
'native', bool,
default=False,
convertor=lambda n: MachineChoice.BUILD if n else MachineChoice.HOST)
_LANGUAGE_KW = KwargInfo(
'language', ContainerTypeInfo(list, str, allow_empty=False),
listify=True,
required=True,
validator=_language_validator,
convertor=lambda x: [i.lower() for i in x])
_INSTALL_MODE_KW = KwargInfo(
'install_mode',
ContainerTypeInfo(list, (str, bool, int)),
listify=True,
default=[],
validator=_install_mode_validator,
convertor=_install_mode_convertor,
)
_REQUIRED_KW = KwargInfo(
'required',
(bool, coredata.UserFeatureOption),
default=True,
# TODO: extract_required_kwarg could be converted to a convertor
)
def stringifyUserArguments(args, quote=False):
if isinstance(args, list):
return '[%s]' % ', '.join([stringifyUserArguments(x, True) for x in args])
@ -626,7 +537,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@typed_pos_args('import', str)
@typed_kwargs(
'import',
_REQUIRED_KW.evolve(since='0.59.0'),
REQUIRED_KW.evolve(since='0.59.0'),
KwargInfo('disabler', bool, default=False, since='0.59.0'),
)
@disablerIfNotFound
@ -1876,7 +1787,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
'install_headers',
KwargInfo('install_dir', (str, None)),
KwargInfo('subdir', (str, None)),
_INSTALL_MODE_KW.evolve(since='0.47.0'),
INSTALL_MODE_KW.evolve(since='0.47.0'),
)
def func_install_headers(self, node: mparser.BaseNode,
args: T.Tuple[T.List['mesonlib.FileOrString']],
@ -1897,7 +1808,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
'install_man',
KwargInfo('install_dir', (str, None)),
KwargInfo('locale', (str, None), since='0.58.0'),
_INSTALL_MODE_KW.evolve(since='0.47.0')
INSTALL_MODE_KW.evolve(since='0.47.0')
)
def func_install_man(self, node: mparser.BaseNode,
args: T.Tuple[T.List['mesonlib.FileOrString']],
@ -1993,7 +1904,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
KwargInfo('install_dir', str),
KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File)), listify=True, default=[]),
KwargInfo('rename', ContainerTypeInfo(list, str), default=[], listify=True, since='0.46.0'),
_INSTALL_MODE_KW.evolve(since='0.38.0'),
INSTALL_MODE_KW.evolve(since='0.38.0'),
)
def func_install_data(self, node: mparser.BaseNode,
args: T.Tuple[T.List['mesonlib.FileOrString']],
@ -2026,7 +1937,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
KwargInfo('exclude_directories', ContainerTypeInfo(list, str),
default=[], listify=True, since='0.42.0',
validator=lambda x: 'cannot be absolute' if any(os.path.isabs(d) for d in x) else None),
_INSTALL_MODE_KW.evolve(since='0.38.0'),
INSTALL_MODE_KW.evolve(since='0.38.0'),
)
def func_install_subdir(self, node: mparser.BaseNode, args: T.Tuple[str],
kwargs: 'kwargs.FuncInstallSubdir') -> build.InstallDir:
@ -2354,22 +2265,22 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
exclude_suites)
@typed_pos_args('add_global_arguments', varargs=str)
@typed_kwargs('add_global_arguments', _NATIVE_KW, _LANGUAGE_KW)
@typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
def func_add_global_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwargs.FuncAddProjectArgs') -> None:
self._add_global_arguments(node, self.build.global_args[kwargs['native']], args[0], kwargs)
@typed_pos_args('add_global_link_arguments', varargs=str)
@typed_kwargs('add_global_arguments', _NATIVE_KW, _LANGUAGE_KW)
@typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
def func_add_global_link_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwargs.FuncAddProjectArgs') -> None:
self._add_global_arguments(node, self.build.global_link_args[kwargs['native']], args[0], kwargs)
@typed_pos_args('add_project_arguments', varargs=str)
@typed_kwargs('add_project_arguments', _NATIVE_KW, _LANGUAGE_KW)
@typed_kwargs('add_project_arguments', NATIVE_KW, LANGUAGE_KW)
def func_add_project_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwargs.FuncAddProjectArgs') -> None:
self._add_project_arguments(node, self.build.projects_args[kwargs['native']], args[0], kwargs)
@typed_pos_args('add_project_link_arguments', varargs=str)
@typed_kwargs('add_global_arguments', _NATIVE_KW, _LANGUAGE_KW)
@typed_kwargs('add_global_arguments', NATIVE_KW, LANGUAGE_KW)
def func_add_project_link_arguments(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwargs: 'kwargs.FuncAddProjectArgs') -> None:
self._add_project_arguments(node, self.build.projects_link_args[kwargs['native']], args[0], kwargs)

@ -0,0 +1,106 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright © 2021 Intel Corporation
"""Helpers for strict type checking."""
import typing as T
from .. import compilers
from ..coredata import UserFeatureOption
from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo
from ..mesonlib import FileMode, MachineChoice
def _language_validator(l: T.List[str]) -> T.Optional[str]:
"""Validate language keyword argument.
Particularly for functions like `add_compiler()`, and `add_*_args()`
"""
diff = {a.lower() for a in l}.difference(compilers.all_languages)
if diff:
return f'unknown languages: {", ".join(diff)}'
return None
def _install_mode_validator(mode: T.List[T.Union[str, bool, int]]) -> T.Optional[str]:
"""Validate the `install_mode` keyword argument.
This is a rather odd thing, it's a scalar, or an array of 3 values in the form:
[(str | False), (str | int | False) = False, (str | int | False) = False]
Where the second and third arguments are not required, and are considered to
default to False.
"""
if not mode:
return None
if True in mode:
return 'can only be a string or false, not true'
if len(mode) > 3:
return 'may have at most 3 elements'
perms = mode[0]
if not isinstance(perms, (str, bool)):
return 'permissions part must be a string or false'
if isinstance(perms, str):
if not len(perms) == 9:
return (f'permissions string must be exactly 9 characters, got "{len(perms)}" '
'in the form rwxr-xr-x')
for i in [0, 3, 6]:
if perms[i] not in {'-', 'r'}:
return f'bit {i} must be "-" or "r", not {perms[i]}'
for i in [1, 4, 7]:
if perms[i] not in {'-', 'w'}:
return f'bit {i} must be "-" or "w", not {perms[i]}'
for i in [2, 5]:
if perms[i] not in {'-', 'x', 's', 'S'}:
return f'bit {i} must be "-", "s", "S", or "x", not {perms[i]}'
if perms[8] not in {'-', 'x', 't', 'T'}:
return f'bit 8 must be "-", "t", "T", or "x", not {perms[8]}'
if len(mode) >= 2 and not isinstance(mode[1], (int, str, bool)):
return 'second componenent must be a string, number, or False if provided'
if len(mode) >= 3 and not isinstance(mode[2], (int, str, bool)):
return 'third componenent must be a string, number, or False if provided'
return None
def _install_mode_convertor(mode: T.Optional[T.List[T.Union[str, bool, int]]]) -> FileMode:
"""Convert the DSL form of the `install_mode` keyword arugment to `FileMode`
This is not required, and if not required returns None
TODO: It's not clear to me why this needs to be None and not just return an
emtpy FileMode.
"""
# this has already been validated by the validator
return FileMode(*[m if isinstance(m, str) else None for m in mode])
NATIVE_KW = KwargInfo(
'native', bool,
default=False,
convertor=lambda n: MachineChoice.BUILD if n else MachineChoice.HOST)
LANGUAGE_KW = KwargInfo(
'language', ContainerTypeInfo(list, str, allow_empty=False),
listify=True,
required=True,
validator=_language_validator,
convertor=lambda x: [i.lower() for i in x])
INSTALL_MODE_KW = KwargInfo(
'install_mode',
ContainerTypeInfo(list, (str, bool, int)),
listify=True,
default=[],
validator=_install_mode_validator,
convertor=_install_mode_convertor,
)
REQUIRED_KW = KwargInfo(
'required',
(bool, UserFeatureOption),
default=True,
# TODO: extract_required_kwarg could be converted to a convertor
)
Loading…
Cancel
Save