class CFG_Node: __counter = 1 def __init__(self, ast_node=None): self.ast_node = ast_node self.children = set() self.parents = set() self.label = None # Optional label for the node self.id = CFG_Node.__counter CFG_Node.__counter += 1 def get_children(self): return self.children def get_parents(self): return self.parents def add_child(self, child: 'CFG_Node', propagate=True): if propagate: child.parents.add(self) self.children.add(child) def add_parent(self, parent: 'CFG_Node', propagate=True): if propagate: parent.add_child(self) self.parents.add(parent) def remove_child(self, child: 'CFG_Node', propagate=True): if propagate: child.parents.remove(self) self.children.remove(child) def remove_parent(self, parent: 'CFG_Node', propagate=True): if propagate: parent.children.remove(self) self.parents.remove(parent) def __str__(self): if self.label: return f"CFG_Node({self.id}, label='{self.label}')" elif self.ast_node: return f"CFG_Node({self.id}, ast={type(self.ast_node).__name__})" else: return f"CFG_Node({self.id})" def __repr__(self): return self.__str__() class CFG_START(CFG_Node): def dot_shape(self): return "box" def dot_label(self): return "START" class CFG_END(CFG_Node): def dot_shape(self): return "box" def dot_label(self): return "END" class CFG_DIAMOND(CFG_Node): def dot_shape(self): return "diamond" class CFG_CALL(CFG_Node): def dot_shape(self): return "box" class CFG_RETURN(CFG_Node): def dot_shape(self): return "box"