Skip to content

Commit 9f1d50e

Browse files
author
Paolo Tranquilli
committed
Codegen: allow parametrized pragmas
1 parent 594045b commit 9f1d50e

File tree

4 files changed

+38
-18
lines changed

4 files changed

+38
-18
lines changed

misc/codegen/lib/schema.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@ class Kind(Enum):
3232
name: Optional[str] = None
3333
type: Optional[str] = None
3434
is_child: bool = False
35-
pragmas: List[str] = field(default_factory=list)
35+
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
3636
doc: Optional[str] = None
3737
description: List[str] = field(default_factory=list)
3838
synth: bool = False
3939

40+
def __post_init__(self):
41+
if not isinstance(self.pragmas, dict):
42+
self.pragmas = dict.fromkeys(self.pragmas, None)
43+
4044
@property
4145
def is_single(self) -> bool:
4246
return self.kind == self.Kind.SINGLE
@@ -88,7 +92,7 @@ class Class:
8892
derived: Set[str] = field(default_factory=set)
8993
properties: List[Property] = field(default_factory=list)
9094
group: str = ""
91-
pragmas: List[str] = field(default_factory=list)
95+
pragmas: List[str] | Dict[str, object] = field(default_factory=dict)
9296
synth: Optional[Union[SynthInfo, bool]] = None
9397
"""^^^ filled with `True` for non-final classes with only synthesized final descendants """
9498
doc: List[str] = field(default_factory=list)
@@ -97,6 +101,10 @@ class Class:
97101
test_with: Optional[str] = None
98102
rust_doc_test_function: Optional["FunctionInfo"] = "() -> ()" # TODO: parametrized pragmas
99103

104+
def __post_init__(self):
105+
if not isinstance(self.pragmas, dict):
106+
self.pragmas = dict.fromkeys(self.pragmas, None)
107+
100108
@property
101109
def final(self):
102110
return not self.derived

misc/codegen/lib/schemadefs.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Callable as _Callable, List as _List
1+
from typing import Callable as _Callable, Dict as _Dict
22
from misc.codegen.lib import schema as _schema
33
import inspect as _inspect
44
from dataclasses import dataclass as _dataclass
@@ -94,6 +94,7 @@ class _Pragma(_schema.PropertyModifier):
9494
For schema classes it acts as a python decorator with `@`.
9595
"""
9696
pragma: str
97+
value: object = None
9798
remove: bool = False
9899

99100
def __post_init__(self):
@@ -108,20 +109,32 @@ def negate(self) -> "PropertyModifier":
108109

109110
def __call__(self, cls: type) -> type:
110111
""" use this pragma as a decorator on classes """
111-
if "_pragmas" in cls.__dict__: # not using hasattr as we don't want to land on inherited pragmas
112-
self._apply(cls._pragmas)
113-
elif not self.remove:
114-
cls._pragmas = [self.pragma]
112+
# not using hasattr as we don't want to land on inherited pragmas
113+
if "_pragmas" not in cls.__dict__:
114+
cls._pragmas = {}
115+
self._apply(cls._pragmas)
115116
return cls
116117

117-
def _apply(self, pragmas: _List[str]) -> None:
118+
def _apply(self, pragmas: _Dict[str, object]) -> None:
118119
if self.remove:
119-
try:
120-
pragmas.remove(self.pragma)
121-
except ValueError:
122-
pass
120+
pragmas.pop(self.pragma, None)
123121
else:
124-
pragmas.append(self.pragma)
122+
pragmas[self.pragma] = self.value
123+
124+
125+
@_dataclass
126+
class _ParametrizedPragma:
127+
""" A class or property parametrized pragma.
128+
Needs to be applied to a parameter to give a pragma.
129+
"""
130+
pragma: str
131+
function: _Callable[[...], object] = None
132+
133+
def __call__(self, *args, **kwargs) -> _Pragma:
134+
return _Pragma(self.pragma, value=self.function(*args, **kwargs))
135+
136+
def __invert__(self) -> _Pragma:
137+
return _Pragma(self.pragma, remove=True)
125138

126139

127140
class _Optionalizer(_schema.PropertyModifier):
@@ -251,9 +264,9 @@ def decorator(cls: type) -> _PropertyAnnotation:
251264
if cls.__doc__ is not None:
252265
annotated_cls.__doc__ = cls.__doc__
253266
old_pragmas = getattr(annotated_cls, "_pragmas", None)
254-
new_pragmas = getattr(cls, "_pragmas", [])
267+
new_pragmas = getattr(cls, "_pragmas", {})
255268
if old_pragmas:
256-
old_pragmas.extend(new_pragmas)
269+
old_pragmas.update(new_pragmas)
257270
else:
258271
annotated_cls._pragmas = new_pragmas
259272
for a, v in cls.__dict__.items():

misc/codegen/loaders/schemaloader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def _get_class(cls: type) -> schema.Class:
4949
hideable=getattr(cls, "_hideable", False),
5050
test_with=_get_name(getattr(cls, "_test_with", None)),
5151
# in the following we don't use `getattr` to avoid inheriting
52-
pragmas=cls.__dict__.get("_pragmas", []),
52+
pragmas=cls.__dict__.get("_pragmas", {}),
5353
synth=cls.__dict__.get("_synth", None),
5454
properties=[
5555
a | _PropertyNamer(n)

misc/codegen/test/test_schemaloader.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -798,8 +798,7 @@ class _:
798798
pass
799799

800800
assert data.classes == {
801-
"Root": schema.Class("Root", hideable=True,
802-
pragmas=["qltest_skip", "cpp_skip", "qltest_collapse_hierarchy"]),
801+
"Root": schema.Class("Root", hideable=True, pragmas=["qltest_skip", "cpp_skip", "qltest_collapse_hierarchy"]),
803802
}
804803

805804

0 commit comments

Comments
 (0)