interpreter: split keyword definitions out of the interpreter
This commit is contained in:
parent
40d5a38d1b
commit
d1b52b913f
|
@ -50,6 +50,12 @@ from .interpreterobjects import (
|
||||||
extract_search_dirs,
|
extract_search_dirs,
|
||||||
NullSubprojectInterpreter,
|
NullSubprojectInterpreter,
|
||||||
)
|
)
|
||||||
|
from .type_checking import (
|
||||||
|
INSTALL_MODE_KW,
|
||||||
|
LANGUAGE_KW,
|
||||||
|
NATIVE_KW,
|
||||||
|
REQUIRED_KW,
|
||||||
|
)
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
|
@ -74,101 +80,6 @@ if T.TYPE_CHECKING:
|
||||||
build.GeneratedList]
|
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):
|
def stringifyUserArguments(args, quote=False):
|
||||||
if isinstance(args, list):
|
if isinstance(args, list):
|
||||||
return '[%s]' % ', '.join([stringifyUserArguments(x, True) for x in args])
|
return '[%s]' % ', '.join([stringifyUserArguments(x, True) for x in args])
|
||||||
|
@ -626,7 +537,7 @@ class Interpreter(InterpreterBase, HoldableObject):
|
||||||
@typed_pos_args('import', str)
|
@typed_pos_args('import', str)
|
||||||
@typed_kwargs(
|
@typed_kwargs(
|
||||||
'import',
|
'import',
|
||||||
_REQUIRED_KW.evolve(since='0.59.0'),
|
REQUIRED_KW.evolve(since='0.59.0'),
|
||||||
KwargInfo('disabler', bool, default=False, since='0.59.0'),
|
KwargInfo('disabler', bool, default=False, since='0.59.0'),
|
||||||
)
|
)
|
||||||
@disablerIfNotFound
|
@disablerIfNotFound
|
||||||
|
@ -1876,7 +1787,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
|
||||||
'install_headers',
|
'install_headers',
|
||||||
KwargInfo('install_dir', (str, None)),
|
KwargInfo('install_dir', (str, None)),
|
||||||
KwargInfo('subdir', (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,
|
def func_install_headers(self, node: mparser.BaseNode,
|
||||||
args: T.Tuple[T.List['mesonlib.FileOrString']],
|
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',
|
'install_man',
|
||||||
KwargInfo('install_dir', (str, None)),
|
KwargInfo('install_dir', (str, None)),
|
||||||
KwargInfo('locale', (str, None), since='0.58.0'),
|
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,
|
def func_install_man(self, node: mparser.BaseNode,
|
||||||
args: T.Tuple[T.List['mesonlib.FileOrString']],
|
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('install_dir', str),
|
||||||
KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File)), listify=True, default=[]),
|
KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File)), listify=True, default=[]),
|
||||||
KwargInfo('rename', ContainerTypeInfo(list, str), default=[], listify=True, since='0.46.0'),
|
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,
|
def func_install_data(self, node: mparser.BaseNode,
|
||||||
args: T.Tuple[T.List['mesonlib.FileOrString']],
|
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),
|
KwargInfo('exclude_directories', ContainerTypeInfo(list, str),
|
||||||
default=[], listify=True, since='0.42.0',
|
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),
|
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],
|
def func_install_subdir(self, node: mparser.BaseNode, args: T.Tuple[str],
|
||||||
kwargs: 'kwargs.FuncInstallSubdir') -> build.InstallDir:
|
kwargs: 'kwargs.FuncInstallSubdir') -> build.InstallDir:
|
||||||
|
@ -2354,22 +2265,22 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
|
||||||
exclude_suites)
|
exclude_suites)
|
||||||
|
|
||||||
@typed_pos_args('add_global_arguments', varargs=str)
|
@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:
|
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)
|
self._add_global_arguments(node, self.build.global_args[kwargs['native']], args[0], kwargs)
|
||||||
|
|
||||||
@typed_pos_args('add_global_link_arguments', varargs=str)
|
@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:
|
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)
|
self._add_global_arguments(node, self.build.global_link_args[kwargs['native']], args[0], kwargs)
|
||||||
|
|
||||||
@typed_pos_args('add_project_arguments', varargs=str)
|
@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:
|
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)
|
self._add_project_arguments(node, self.build.projects_args[kwargs['native']], args[0], kwargs)
|
||||||
|
|
||||||
@typed_pos_args('add_project_link_arguments', varargs=str)
|
@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:
|
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)
|
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…
Reference in New Issue