@@ -115,6 +115,29 @@ def to_suffix(self) -> str:
115115 case Language .CPP :
116116 return ".cpp"
117117
118+ def to_json_dict (self ) -> dict [str , Any ]:
119+ """Returns a dictionary that can be serialized to json.
120+
121+ Returns:
122+ dict[str, Any]:
123+ the dictionary
124+ """
125+ return {"name" : self .name }
126+
127+ @staticmethod
128+ def from_json_dict (d : dict [str , Any ]) -> Language :
129+ """Returns a language parsed from a json dictionary.
130+
131+ Args:
132+ d (dict[str, Any]):
133+ the dictionary
134+
135+ Returns:
136+ Language:
137+ the language
138+ """
139+ return Language [d ["name" ]]
140+
118141
119142@dataclass (frozen = True )
120143class SourcePath :
@@ -131,12 +154,10 @@ def __del__(self) -> None:
131154
132155@dataclass (frozen = True , kw_only = True )
133156class Source (ABC ):
134- """A C or C++ base class for source programs together
157+ """A base class for C or C++source programs together
135158 with flags, includes and macro definitions.
136159
137160 Attributes:
138- code (str):
139- the source code
140161 language (Language):
141162 the program's language
142163 defined_macros (tuple[str,...]):
@@ -198,7 +219,122 @@ def get_file_suffix(self) -> str:
198219
199220 @abstractmethod
200221 def get_filename (self ) -> SourcePath :
201- pass
222+ raise NotImplementedError
223+
224+ def to_json_dict (self ) -> dict [str , Any ]:
225+ """Returns a dictionary that can be serialized to json.
226+
227+ Can be re-parses with Source.from_json_dict.
228+
229+ Returns:
230+ dict[str, Any]:
231+ the dictionary
232+ """
233+ j = {
234+ "language" : self .language .to_json_dict (),
235+ "defined_macros" : self .defined_macros ,
236+ "include_paths" : self .include_paths ,
237+ "system_include_paths" : self .system_include_paths ,
238+ "flags" : self .flags ,
239+ }
240+
241+ j |= self .to_json_dict_impl ()
242+
243+ assert set (j .keys ()) == set (field .name for field in fields (self )) | set (
244+ ("kind" ,)
245+ )
246+
247+ return j
248+
249+ @abstractmethod
250+ def to_json_dict_impl (self ) -> dict [str , Any ]:
251+ """Returns a dictionary that can be serialized to json.
252+
253+ Subclasses should implement this method and serialize
254+ their specific attributes.
255+
256+
257+ Returns:
258+ dict[str, Any]:
259+ the dictionary
260+ """
261+ raise NotImplementedError
262+
263+ @classmethod
264+ def from_json_dict (cls , d : dict [str , Any ]) -> Source :
265+ """Returns a source parsed from a json dictionary.
266+
267+ Args:
268+ d (dict[str, Any]):
269+ the dictionary
270+
271+ Returns:
272+ Source:
273+ the source
274+ """
275+ if cls is Source :
276+ match d ["kind" ]:
277+ case "SourceFile" :
278+ return SourceFile .from_json_dict_impl (
279+ d ,
280+ language = Language .from_json_dict (d ["language" ]),
281+ defined_macros = tuple (d ["defined_macros" ]),
282+ include_paths = tuple (d ["include_paths" ]),
283+ system_include_paths = tuple (d ["system_include_paths" ]),
284+ flags = tuple (d ["flags" ]),
285+ )
286+ case "SourceProgram" :
287+ return SourceProgram .from_json_dict_impl (
288+ d ,
289+ language = Language .from_json_dict (d ["language" ]),
290+ defined_macros = tuple (d ["defined_macros" ]),
291+ include_paths = tuple (d ["include_paths" ]),
292+ system_include_paths = tuple (d ["system_include_paths" ]),
293+ flags = tuple (d ["flags" ]),
294+ )
295+
296+ case _:
297+ raise ValueError (f"Unknown kind: { d ['kind' ]} " )
298+ else :
299+ return cls .from_json_dict_impl (
300+ d ,
301+ language = Language .from_json_dict (d ["language" ]),
302+ defined_macros = tuple (d ["defined_macros" ]),
303+ include_paths = tuple (d ["include_paths" ]),
304+ system_include_paths = tuple (d ["system_include_paths" ]),
305+ flags = tuple (d ["flags" ]),
306+ )
307+
308+ @staticmethod
309+ @abstractmethod
310+ def from_json_dict_impl (
311+ d : dict [str , Any ],
312+ language : Language ,
313+ defined_macros : tuple [str , ...],
314+ include_paths : tuple [str , ...],
315+ system_include_paths : tuple [str , ...],
316+ flags : tuple [str , ...],
317+ ) -> Source :
318+ """Returns a source parsed from a json dictionary.
319+
320+ Subclasses should implement this and parse their
321+ specific attributes from the dictionary.
322+
323+ Args:
324+ d (dict[str, Any]):
325+ the dictionary
326+ language (Language):
327+ the program's language
328+ defined_macros (tuple[str,...]):
329+ macros that will be defined when compiling this program
330+ include_paths (tuple[str,...]):
331+ include paths which will be passed to the compiler (with -I)
332+ system_include_paths (tuple[str,...]):
333+ system include paths which will be passed to the compiler (with -isystem)
334+ flags (tuple[str,...]):
335+ flags, prefixed with a dash ("-") that will be passed to the compiler
336+ """
337+ raise NotImplementedError
202338
203339
204340ProgramType = TypeVar ("ProgramType" , bound = "SourceProgram" )
@@ -274,6 +410,51 @@ def with_code(self: ProgramType, new_code: str) -> ProgramType:
274410 """
275411 return replace (self , code = new_code )
276412
413+ @staticmethod
414+ def from_json_dict_impl (
415+ d : dict [str , Any ],
416+ language : Language ,
417+ defined_macros : tuple [str , ...],
418+ include_paths : tuple [str , ...],
419+ system_include_paths : tuple [str , ...],
420+ flags : tuple [str , ...],
421+ ) -> SourceProgram :
422+ """Returns a source program parsed from a json dictionary.
423+
424+ Args:
425+ d (dict[str, Any]):
426+ the dictionary
427+ language (Language):
428+ the program's language
429+ defined_macros (tuple[str,...]):
430+ macros that will be defined when compiling this program
431+ include_paths (tuple[str,...]):
432+ include paths which will be passed to the compiler (with -I)
433+ system_include_paths (tuple[str,...]):
434+ system include paths which will be passed to the compiler (with -isystem)
435+ flags (tuple[str,...]):
436+ flags, prefixed with a dash ("-") that will be passed to the compiler
437+ """
438+ assert d ["kind" ] == "SourceProgram"
439+ return SourceProgram (
440+ code = d ["code" ],
441+ language = language ,
442+ defined_macros = defined_macros ,
443+ include_paths = include_paths ,
444+ system_include_paths = system_include_paths ,
445+ flags = flags ,
446+ )
447+
448+ def to_json_dict_impl (self ) -> dict [str , Any ]:
449+ """Returns a dictionary representation of this source program,
450+ only including the SourceProgram specific attributes.
451+
452+ Returns:
453+ dict[str, Any]:
454+ the dictionary
455+ """
456+ return {"kind" : "SourceProgram" , "code" : self .code }
457+
277458
278459@dataclass (frozen = True , kw_only = True )
279460class SourceFile (Source ):
@@ -304,6 +485,51 @@ def __post_init__(self) -> None:
304485 def get_filename (self ) -> SourcePath :
305486 return SourcePath (self .filename , None )
306487
488+ @staticmethod
489+ def from_json_dict_impl (
490+ d : dict [str , Any ],
491+ language : Language ,
492+ defined_macros : tuple [str , ...],
493+ include_paths : tuple [str , ...],
494+ system_include_paths : tuple [str , ...],
495+ flags : tuple [str , ...],
496+ ) -> SourceFile :
497+ """Returns a source file parsed from a json dictionary.
498+
499+ Args:
500+ d (dict[str, Any]):
501+ the dictionary
502+ language (Language):
503+ the program's language
504+ defined_macros (tuple[str,...]):
505+ macros that will be defined when compiling this program
506+ include_paths (tuple[str,...]):
507+ include paths which will be passed to the compiler (with -I)
508+ system_include_paths (tuple[str,...]):
509+ system include paths which will be passed to the compiler (with -isystem)
510+ flags (tuple[str,...]):
511+ flags, prefixed with a dash ("-") that will be passed to the compiler
512+ """
513+ assert d ["kind" ] == "SourceFile"
514+ return SourceFile (
515+ filename = Path (d ["filename" ]),
516+ language = language ,
517+ defined_macros = defined_macros ,
518+ include_paths = include_paths ,
519+ system_include_paths = system_include_paths ,
520+ flags = flags ,
521+ )
522+
523+ def to_json_dict_impl (self ) -> dict [str , Any ]:
524+ """Returns a dictionary representation of this source program,
525+ only including the SourceFile specific attributes.
526+
527+ Returns:
528+ dict[str, Any]:
529+ the dictionary
530+ """
531+ return {"kind" : "SourceFile" , "filename" : self .filename }
532+
307533
308534Revision = str
309535
0 commit comments