mirror of
https://gitlab.com/qemu-project/meson.git
synced 2025-09-16 14:41:54 +08:00

If an annotation could not be resolved, it's classified as a "missing import" and our configuration ignored it: ``` Skipping analyzing "mesonbuild.backends": module is installed, but missing library stubs or py.typed marker ``` As far as mypy is concerned, this library may or may not exist, but it doesn't have any typing information at all (may need to be installed first). We ignored this because of our docs/ and tools/ thirdparty dependencies, but we really should not. It is trivial to install them, and then enforce that this "just works". By enforcing it, we also make sure typos get caught.
316 lines
10 KiB
Python
316 lines
10 KiB
Python
# Copyright 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 .loaderbase import LoaderBase
|
|
from .model import (
|
|
Type,
|
|
PosArg,
|
|
VarArgs,
|
|
Kwarg,
|
|
Function,
|
|
Method,
|
|
ObjectType,
|
|
Object,
|
|
ReferenceManual,
|
|
)
|
|
|
|
from mesonbuild import mlog
|
|
from mesonbuild import mesonlib
|
|
|
|
from pathlib import Path
|
|
import typing as T
|
|
|
|
class Template:
|
|
d_feature_check: T.Dict[str, T.Any] = {}
|
|
s_posarg: T.Dict[str, T.Any] = {}
|
|
s_varargs: T.Dict[str, T.Any] = {}
|
|
s_kwarg: T.Dict[str, T.Any] = {}
|
|
s_function: T.Dict[str, T.Any] = {}
|
|
s_object: T.Dict[str, T.Any] = {}
|
|
|
|
class StrictTemplate(Template):
|
|
def __init__(self) -> None:
|
|
from strictyaml import Map, MapPattern, Optional, Str, Seq, Int, Bool, EmptyList, OrValidator # type: ignore[import-untyped]
|
|
|
|
d_named_object = {
|
|
'name': Str(),
|
|
'description': Str(),
|
|
}
|
|
|
|
d_feture_check = {
|
|
Optional('since', default=''): Str(),
|
|
Optional('deprecated', default=''): Str(),
|
|
}
|
|
|
|
self.s_posarg = Map({
|
|
**d_feture_check,
|
|
'description': Str(),
|
|
'type': Str(),
|
|
Optional('default', default=''): Str(),
|
|
})
|
|
|
|
self.s_varargs = Map({
|
|
**d_named_object, **d_feture_check,
|
|
'type': Str(),
|
|
Optional('min_varargs', default=-1): Int(),
|
|
Optional('max_varargs', default=-1): Int(),
|
|
})
|
|
|
|
self.s_kwarg = Map({
|
|
**d_feture_check,
|
|
'type': Str(),
|
|
'description': Str(),
|
|
Optional('required', default=False): Bool(),
|
|
Optional('default', default=''): Str(),
|
|
})
|
|
|
|
self.s_function = Map({
|
|
**d_named_object, **d_feture_check,
|
|
'returns': Str(),
|
|
Optional('notes', default=[]): OrValidator(Seq(Str()), EmptyList()),
|
|
Optional('warnings', default=[]): OrValidator(Seq(Str()), EmptyList()),
|
|
Optional('example', default=''): Str(),
|
|
Optional('posargs'): MapPattern(Str(), self.s_posarg),
|
|
Optional('optargs'): MapPattern(Str(), self.s_posarg),
|
|
Optional('varargs'): self.s_varargs,
|
|
Optional('posargs_inherit', default=''): Str(),
|
|
Optional('optargs_inherit', default=''): Str(),
|
|
Optional('varargs_inherit', default=''): Str(),
|
|
Optional('kwargs'): MapPattern(Str(), self.s_kwarg),
|
|
Optional('kwargs_inherit', default=[]): OrValidator(OrValidator(Seq(Str()), EmptyList()), Str()),
|
|
Optional('arg_flattening', default=True): Bool(),
|
|
})
|
|
|
|
self.s_object = Map({
|
|
**d_named_object, **d_feture_check,
|
|
'long_name': Str(),
|
|
Optional('extends', default=''): Str(),
|
|
Optional('notes', default=[]): OrValidator(Seq(Str()), EmptyList()),
|
|
Optional('warnings', default=[]): OrValidator(Seq(Str()), EmptyList()),
|
|
Optional('example', default=''): Str(),
|
|
Optional('methods'): Seq(self.s_function),
|
|
Optional('is_container', default=False): Bool()
|
|
})
|
|
|
|
class FastTemplate(Template):
|
|
d_feature_check: T.Dict[str, T.Any] = {
|
|
'since': '',
|
|
'deprecated': '',
|
|
}
|
|
|
|
s_posarg = {
|
|
**d_feature_check,
|
|
'default': '',
|
|
}
|
|
|
|
s_varargs: T.Dict[str, T.Any] = {
|
|
**d_feature_check,
|
|
'min_varargs': -1,
|
|
'max_varargs': -1,
|
|
}
|
|
|
|
s_kwarg = {
|
|
**d_feature_check,
|
|
'required': False,
|
|
'default': '',
|
|
}
|
|
|
|
s_function = {
|
|
**d_feature_check,
|
|
'notes': [],
|
|
'warnings': [],
|
|
'example': '',
|
|
'posargs': {},
|
|
'optargs': {},
|
|
'varargs': None,
|
|
'posargs_inherit': '',
|
|
'optargs_inherit': '',
|
|
'varargs_inherit': '',
|
|
'kwargs': {},
|
|
'kwargs_inherit': [],
|
|
'arg_flattening': True,
|
|
}
|
|
|
|
s_object = {
|
|
**d_feature_check,
|
|
'extends': '',
|
|
'notes': [],
|
|
'warnings': [],
|
|
'example': '',
|
|
'methods': [],
|
|
'is_container': False,
|
|
}
|
|
|
|
class LoaderYAML(LoaderBase):
|
|
def __init__(self, yaml_dir: Path, strict: bool=True) -> None:
|
|
super().__init__()
|
|
self.yaml_dir = yaml_dir
|
|
self.func_dir = self.yaml_dir / 'functions'
|
|
self.elem_dir = self.yaml_dir / 'elementary'
|
|
self.objs_dir = self.yaml_dir / 'objects'
|
|
self.builtin_dir = self.yaml_dir / 'builtins'
|
|
self.modules_dir = self.yaml_dir / 'modules'
|
|
self.strict = strict
|
|
|
|
template: Template
|
|
if self.strict:
|
|
import strictyaml
|
|
def loader(file: str, template: T.Any, label: str) -> T.Dict:
|
|
r: T.Dict = strictyaml.load(file, template, label=label).data
|
|
return r
|
|
|
|
self._load = loader
|
|
template = StrictTemplate()
|
|
else:
|
|
import yaml
|
|
from yaml import CLoader
|
|
def loader(file: str, template: T.Any, label: str) -> T.Dict:
|
|
return {**template, **yaml.load(file, Loader=CLoader)}
|
|
|
|
self._load = loader
|
|
template = FastTemplate()
|
|
|
|
self.template = template
|
|
|
|
def _fix_default(self, v: T.Dict) -> None:
|
|
if v["default"] is False:
|
|
v["default"] = "false"
|
|
elif v["default"] is True:
|
|
v["default"] = "true"
|
|
else:
|
|
v["default"] = str(v["default"])
|
|
|
|
def _process_function_base(self, raw: T.Dict, obj: T.Optional[Object] = None) -> Function:
|
|
# Handle arguments
|
|
posargs = raw.pop('posargs', {})
|
|
optargs = raw.pop('optargs', {})
|
|
varargs = raw.pop('varargs', None)
|
|
kwargs = raw.pop('kwargs', {})
|
|
|
|
# Fix kwargs_inherit
|
|
if isinstance(raw['kwargs_inherit'], str):
|
|
raw['kwargs_inherit'] = [raw['kwargs_inherit']]
|
|
|
|
# Parse args
|
|
posargs_mapped: T.List[PosArg] = []
|
|
optargs_mapped: T.List[PosArg] = []
|
|
varargs_mapped: T.Optional[VarArgs] = None
|
|
kwargs_mapped: T.Dict[str, Kwarg] = {}
|
|
|
|
for k, v in posargs.items():
|
|
if not self.strict:
|
|
v = {**self.template.s_posarg, **v}
|
|
self._fix_default(v)
|
|
v['type'] = Type(v['type'])
|
|
posargs_mapped += [PosArg(name=k, **v)]
|
|
|
|
for k, v in optargs.items():
|
|
if not self.strict:
|
|
v = {**self.template.s_posarg, **v}
|
|
self._fix_default(v)
|
|
v['type'] = Type(v['type'])
|
|
optargs_mapped += [PosArg(name=k, **v)]
|
|
|
|
for k, v in kwargs.items():
|
|
if not self.strict:
|
|
v = {**self.template.s_kwarg, **v}
|
|
self._fix_default(v)
|
|
v['type'] = Type(v['type'])
|
|
kwargs_mapped[k] = Kwarg(name=k, **v)
|
|
|
|
if varargs is not None:
|
|
if not self.strict:
|
|
varargs = {**self.template.s_varargs, **varargs}
|
|
varargs['type'] = Type(varargs['type'])
|
|
varargs_mapped = VarArgs(**varargs)
|
|
|
|
raw['returns'] = Type(raw['returns'])
|
|
|
|
# Build function object
|
|
if obj is not None:
|
|
return Method(
|
|
posargs=posargs_mapped,
|
|
optargs=optargs_mapped,
|
|
varargs=varargs_mapped,
|
|
kwargs=kwargs_mapped,
|
|
obj=obj,
|
|
**raw,
|
|
)
|
|
return Function(
|
|
posargs=posargs_mapped,
|
|
optargs=optargs_mapped,
|
|
varargs=varargs_mapped,
|
|
kwargs=kwargs_mapped,
|
|
**raw,
|
|
)
|
|
|
|
def _load_function(self, path: Path, obj: T.Optional[Object] = None) -> Function:
|
|
path_label = path.relative_to(self.yaml_dir).as_posix()
|
|
mlog.log('Loading', mlog.bold(path_label))
|
|
raw = self._load(self.read_file(path), self.template.s_function, label=path_label)
|
|
return self._process_function_base(raw)
|
|
|
|
def _load_object(self, obj_type: ObjectType, path: Path) -> Object:
|
|
path_label = path.relative_to(self.yaml_dir).as_posix()
|
|
mlog.log(f'Loading', mlog.bold(path_label))
|
|
raw = self._load(self.read_file(path), self.template.s_object, label=path_label)
|
|
|
|
def as_methods(mlist: T.List[Function]) -> T.List[Method]:
|
|
res: T.List[Method] = []
|
|
for i in mlist:
|
|
assert isinstance(i, Method)
|
|
res += [i]
|
|
return res
|
|
|
|
methods = raw.pop('methods', [])
|
|
obj = Object(methods=[], obj_type=obj_type, **raw)
|
|
|
|
newmethods = []
|
|
for x in methods:
|
|
if not self.strict:
|
|
x = {**self.template.s_function, **x}
|
|
newmethods += [self._process_function_base(x, obj)]
|
|
obj.methods = as_methods(newmethods)
|
|
return obj
|
|
|
|
def _load_module(self, path: Path) -> T.List[Object]:
|
|
assert path.is_dir()
|
|
module = self._load_object(ObjectType.MODULE, path / 'module.yaml')
|
|
objs = []
|
|
for p in path.iterdir():
|
|
if p.name == 'module.yaml':
|
|
continue
|
|
obj = self._load_object(ObjectType.RETURNED, p)
|
|
obj.defined_by_module = module
|
|
objs += [obj]
|
|
return [module, *objs]
|
|
|
|
def load_impl(self) -> ReferenceManual:
|
|
mlog.log('Loading YAML reference manual')
|
|
with mlog.nested():
|
|
manual = ReferenceManual(
|
|
functions=[self._load_function(x) for x in self.func_dir.iterdir()],
|
|
objects=mesonlib.listify([
|
|
[self._load_object(ObjectType.ELEMENTARY, x) for x in self.elem_dir.iterdir()],
|
|
[self._load_object(ObjectType.RETURNED, x) for x in self.objs_dir.iterdir()],
|
|
[self._load_object(ObjectType.BUILTIN, x) for x in self.builtin_dir.iterdir()],
|
|
[self._load_module(x) for x in self.modules_dir.iterdir()]
|
|
], flatten=True)
|
|
)
|
|
|
|
if not self.strict:
|
|
mlog.warning('YAML reference manual loaded using the best-effort fastyaml loader. Results are not guaranteed to be stable or correct.')
|
|
|
|
return manual
|