Codegen: allow parametrized pragmas

This commit is contained in:
Paolo Tranquilli
2024-09-20 09:17:05 +02:00
parent 594045b634
commit 9f1d50ebd1
4 changed files with 38 additions and 18 deletions

View File

@@ -32,11 +32,15 @@ class Property:
name: Optional[str] = None
type: Optional[str] = None
is_child: bool = False
pragmas: List[str] = field(default_factory=list)
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
doc: Optional[str] = None
description: List[str] = field(default_factory=list)
synth: bool = False
def __post_init__(self):
if not isinstance(self.pragmas, dict):
self.pragmas = dict.fromkeys(self.pragmas, None)
@property
def is_single(self) -> bool:
return self.kind == self.Kind.SINGLE
@@ -88,7 +92,7 @@ class Class:
derived: Set[str] = field(default_factory=set)
properties: List[Property] = field(default_factory=list)
group: str = ""
pragmas: List[str] = field(default_factory=list)
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
synth: Optional[Union[SynthInfo, bool]] = None
"""^^^ filled with `True` for non-final classes with only synthesized final descendants """
doc: List[str] = field(default_factory=list)
@@ -97,6 +101,10 @@ class Class:
test_with: Optional[str] = None
rust_doc_test_function: Optional["FunctionInfo"] = "() -> ()" # TODO: parametrized pragmas
def __post_init__(self):
if not isinstance(self.pragmas, dict):
self.pragmas = dict.fromkeys(self.pragmas, None)
@property
def final(self):
return not self.derived

View File

@@ -1,4 +1,4 @@
from typing import Callable as _Callable, List as _List
from typing import Callable as _Callable, Dict as _Dict
from misc.codegen.lib import schema as _schema
import inspect as _inspect
from dataclasses import dataclass as _dataclass
@@ -94,6 +94,7 @@ class _Pragma(_schema.PropertyModifier):
For schema classes it acts as a python decorator with `@`.
"""
pragma: str
value: object = None
remove: bool = False
def __post_init__(self):
@@ -108,20 +109,32 @@ class _Pragma(_schema.PropertyModifier):
def __call__(self, cls: type) -> type:
""" use this pragma as a decorator on classes """
if "_pragmas" in cls.__dict__: # not using hasattr as we don't want to land on inherited pragmas
self._apply(cls._pragmas)
elif not self.remove:
cls._pragmas = [self.pragma]
# not using hasattr as we don't want to land on inherited pragmas
if "_pragmas" not in cls.__dict__:
cls._pragmas = {}
self._apply(cls._pragmas)
return cls
def _apply(self, pragmas: _List[str]) -> None:
def _apply(self, pragmas: _Dict[str, object]) -> None:
if self.remove:
try:
pragmas.remove(self.pragma)
except ValueError:
pass
pragmas.pop(self.pragma, None)
else:
pragmas.append(self.pragma)
pragmas[self.pragma] = self.value
@_dataclass
class _ParametrizedPragma:
""" A class or property parametrized pragma.
Needs to be applied to a parameter to give a pragma.
"""
pragma: str
function: _Callable[[...], object] = None
def __call__(self, *args, **kwargs) -> _Pragma:
return _Pragma(self.pragma, value=self.function(*args, **kwargs))
def __invert__(self) -> _Pragma:
return _Pragma(self.pragma, remove=True)
class _Optionalizer(_schema.PropertyModifier):
@@ -251,9 +264,9 @@ def annotate(annotated_cls: type) -> _Callable[[type], _PropertyAnnotation]:
if cls.__doc__ is not None:
annotated_cls.__doc__ = cls.__doc__
old_pragmas = getattr(annotated_cls, "_pragmas", None)
new_pragmas = getattr(cls, "_pragmas", [])
new_pragmas = getattr(cls, "_pragmas", {})
if old_pragmas:
old_pragmas.extend(new_pragmas)
old_pragmas.update(new_pragmas)
else:
annotated_cls._pragmas = new_pragmas
for a, v in cls.__dict__.items():

View File

@@ -49,7 +49,7 @@ def _get_class(cls: type) -> schema.Class:
hideable=getattr(cls, "_hideable", False),
test_with=_get_name(getattr(cls, "_test_with", None)),
# in the following we don't use `getattr` to avoid inheriting
pragmas=cls.__dict__.get("_pragmas", []),
pragmas=cls.__dict__.get("_pragmas", {}),
synth=cls.__dict__.get("_synth", None),
properties=[
a | _PropertyNamer(n)

View File

@@ -798,8 +798,7 @@ def test_annotate_decorations():
pass
assert data.classes == {
"Root": schema.Class("Root", hideable=True,
pragmas=["qltest_skip", "cpp_skip", "qltest_collapse_hierarchy"]),
"Root": schema.Class("Root", hideable=True, pragmas=["qltest_skip", "cpp_skip", "qltest_collapse_hierarchy"]),
}