|
|
|
# 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
|
|
|
|
|
|
|
|
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
|