1
- from typing import Callable as _Callable , List as _List
1
+ from typing import Callable as _Callable , Dict as _Dict , ClassVar as _ClassVar
2
2
from misc .codegen .lib import schema as _schema
3
3
import inspect as _inspect
4
4
from dataclasses import dataclass as _dataclass
@@ -62,11 +62,14 @@ def include(source: str):
62
62
_inspect .currentframe ().f_back .f_locals .setdefault ("includes" , []).append (source )
63
63
64
64
65
+ @_dataclass
65
66
class _Namespace :
66
67
""" simple namespacing mechanism """
68
+ name : str
67
69
68
- def __init__ (self , ** kwargs ):
69
- self .__dict__ .update (kwargs )
70
+ def add (self , pragma : "_PragmaBase" , key : str | None = None ):
71
+ self .__dict__ [pragma .pragma ] = pragma
72
+ pragma .pragma = key or f"{ self .name } _{ pragma .pragma } "
70
73
71
74
72
75
@_dataclass
@@ -77,51 +80,86 @@ def modify(self, prop: _schema.Property):
77
80
prop .synth = self .synth
78
81
79
82
def negate (self ) -> "PropertyModifier" :
80
- return _SynthModifier (False )
83
+ return _SynthModifier (self .name , False )
84
+
85
+
86
+ qltest = _Namespace ("qltest" )
87
+ ql = _Namespace ("ql" )
88
+ cpp = _Namespace ("cpp" )
89
+ rust = _Namespace ("rust" )
90
+ synth = _SynthModifier ("synth" )
91
+
92
+
93
+ @_dataclass
94
+ class _PragmaBase :
95
+ pragma : str
96
+
97
+
98
+ @_dataclass
99
+ class _ClassPragma (_PragmaBase ):
100
+ """ A class pragma.
101
+ For schema classes it acts as a python decorator with `@`.
102
+ """
103
+ value : object = None
81
104
105
+ def __call__ (self , cls : type ) -> type :
106
+ """ use this pragma as a decorator on classes """
107
+ # not using hasattr as we don't want to land on inherited pragmas
108
+ if "_pragmas" not in cls .__dict__ :
109
+ cls ._pragmas = {}
110
+ self ._apply (cls ._pragmas )
111
+ return cls
82
112
83
- qltest = _Namespace ()
84
- ql = _Namespace ()
85
- cpp = _Namespace ()
86
- rust = _Namespace ()
87
- synth = _SynthModifier ()
113
+ def _apply (self , pragmas : _Dict [str , object ]) -> None :
114
+ pragmas [self .pragma ] = self .value
88
115
89
116
90
117
@_dataclass
91
- class _Pragma (_schema .PropertyModifier ):
118
+ class _Pragma (_ClassPragma , _schema .PropertyModifier ):
92
119
""" A class or property pragma.
93
120
For properties, it functions similarly to a `_PropertyModifier` with `|`, adding the pragma.
94
121
For schema classes it acts as a python decorator with `@`.
95
122
"""
96
- pragma : str
97
123
remove : bool = False
98
124
99
- def __post_init__ (self ):
100
- namespace , _ , name = self .pragma .partition ('_' )
101
- setattr (globals ()[namespace ], name , self )
102
-
103
125
def modify (self , prop : _schema .Property ):
104
126
self ._apply (prop .pragmas )
105
127
106
128
def negate (self ) -> "PropertyModifier" :
107
129
return _Pragma (self .pragma , remove = True )
108
130
109
- def __call__ (self , cls : type ) -> type :
110
- """ 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 ]
115
- return cls
116
-
117
- def _apply (self , pragmas : _List [str ]) -> None :
131
+ def _apply (self , pragmas : _Dict [str , object ]) -> None :
118
132
if self .remove :
119
- try :
120
- pragmas .remove (self .pragma )
121
- except ValueError :
122
- pass
133
+ pragmas .pop (self .pragma , None )
123
134
else :
124
- pragmas .append (self .pragma )
135
+ super ()._apply (pragmas )
136
+
137
+
138
+ @_dataclass
139
+ class _ParametrizedClassPragma (_PragmaBase ):
140
+ """ A class parametrized pragma.
141
+ Needs to be applied to a parameter to give a class pragma.
142
+ """
143
+ _pragma_class : _ClassVar [type ] = _ClassPragma
144
+
145
+ function : _Callable [..., object ] = None
146
+
147
+ def __post_init__ (self ):
148
+ self .__signature__ = _inspect .signature (self .function ).replace (return_annotation = self ._pragma_class )
149
+
150
+ def __call__ (self , * args , ** kwargs ) -> _pragma_class :
151
+ return self ._pragma_class (self .pragma , value = self .function (* args , ** kwargs ))
152
+
153
+
154
+ @_dataclass
155
+ class _ParametrizedPragma (_ParametrizedClassPragma ):
156
+ """ A class or property parametrized pragma.
157
+ Needs to be applied to a parameter to give a pragma.
158
+ """
159
+ _pragma_class : _ClassVar [type ] = _Pragma
160
+
161
+ def __invert__ (self ) -> _Pragma :
162
+ return _Pragma (self .pragma , remove = True )
125
163
126
164
127
165
class _Optionalizer (_schema .PropertyModifier ):
@@ -190,30 +228,30 @@ def f(cls: type) -> type:
190
228
191
229
use_for_null = _annotate (null = True )
192
230
193
- _Pragma ("qltest_skip" )
194
- _Pragma ( "qltest_collapse_hierarchy" )
195
- _Pragma ( "qltest_uncollapse_hierarchy" )
196
- qltest .test_with = lambda cls : _annotate (test_with = cls )
231
+ qltest . add ( _Pragma ("skip" ) )
232
+ qltest . add ( _ClassPragma ( "collapse_hierarchy" ) )
233
+ qltest . add ( _ClassPragma ( "uncollapse_hierarchy" ) )
234
+ qltest .test_with = lambda cls : _annotate (test_with = cls ) # inheritable
197
235
198
- ql .default_doc_name = lambda doc : _annotate ( doc_name = doc )
199
- ql .hideable = _annotate (hideable = True )
200
- _Pragma ("ql_internal" )
236
+ ql .add ( _ParametrizedClassPragma ( " default_doc_name" , lambda doc : doc ) )
237
+ ql .hideable = _annotate (hideable = True ) # inheritable
238
+ ql . add ( _Pragma ("internal" ) )
201
239
202
- _Pragma ("cpp_skip" )
240
+ cpp . add ( _Pragma ("skip" ) )
203
241
204
- _Pragma ("rust_skip_doc_test" )
242
+ rust . add ( _Pragma ("skip_doc_test" ) )
205
243
206
- rust .doc_test_signature = lambda signature : _annotate ( rust_doc_test_function = signature )
244
+ rust .add ( _ParametrizedClassPragma ( " doc_test_signature" , lambda signature : signature ) )
207
245
208
246
209
247
def group (name : str = "" ) -> _ClassDecorator :
210
248
return _annotate (group = name )
211
249
212
250
213
- synth .from_class = lambda ref : _annotate ( synth = _schema .SynthInfo (
214
- from_class = _schema .get_type_name (ref )))
215
- synth .on_arguments = lambda ** kwargs : _annotate (
216
- synth = _schema .SynthInfo (on_arguments = {k : _schema .get_type_name (t ) for k , t in kwargs .items ()}))
251
+ synth .add ( _ParametrizedClassPragma ( " from_class" , lambda ref : _schema .SynthInfo (
252
+ from_class = _schema .get_type_name (ref ))), key = "synth" )
253
+ synth .add ( _ParametrizedClassPragma ( " on_arguments" , lambda ** kwargs :
254
+ _schema .SynthInfo (on_arguments = {k : _schema .get_type_name (t ) for k , t in kwargs .items ()})), key = "synth" )
217
255
218
256
219
257
class _PropertyModifierList (_schema .PropertyModifier ):
@@ -251,9 +289,9 @@ def decorator(cls: type) -> _PropertyAnnotation:
251
289
if cls .__doc__ is not None :
252
290
annotated_cls .__doc__ = cls .__doc__
253
291
old_pragmas = getattr (annotated_cls , "_pragmas" , None )
254
- new_pragmas = getattr (cls , "_pragmas" , [] )
292
+ new_pragmas = getattr (cls , "_pragmas" , {} )
255
293
if old_pragmas :
256
- old_pragmas .extend (new_pragmas )
294
+ old_pragmas .update (new_pragmas )
257
295
else :
258
296
annotated_cls ._pragmas = new_pragmas
259
297
for a , v in cls .__dict__ .items ():
0 commit comments