diff --git a/SuperScriptDecorator/DecoratorBB.py b/SuperScriptDecorator/DecoratorBB.py index e6ebaa2..2876341 100644 --- a/SuperScriptDecorator/DecoratorBB.py +++ b/SuperScriptDecorator/DecoratorBB.py @@ -8,22 +8,19 @@ class IntermediateTreeNode(object): self.m_LocatedPos: int = DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER self.m_Collection: collections.deque[int] = collections.deque() -class BlocksFactory(object): - def __init__(self, db: sqlite3.Connection, graph: int): - # assign members - self.m_GraphCKID: int = graph - self.m_Db: sqlite3.Connection = db - self.__Cursor: sqlite3.Cursor = db.cursor() +class IntermediateOperDownwardSearch(object): + def __init__(self): + self.m_Collection: collections.deque[int] = collections.deque() + +class BlocksFactory(object): + def __init__(self, db: sqlite3.Connection, graph: DecoratorData.GraphResult): + # assign members + self.m_Graph: DecoratorData.GraphResult = graph + self.m_Db: sqlite3.Connection = db - self.m_BBDict: dict[int, DecoratorData.BBTreeNode] = {} - self.m_OperDict: dict[int, DecoratorData.OperTreeNode] = {} self.__AllBB: set[int] = set() self.__AllOper: set[int] = set() - self.m_PassiveOperLayer: DecoratorData.TreeLayout = DecoratorData.TreeLayout() - self.m_ActiveBBLayer: DecoratorData.TreeLayout = DecoratorData.TreeLayout() - self.m_PassiveBBLayer: DecoratorData.TreeLayout = DecoratorData.TreeLayout() - # fill data first self.__FillDataFromDb() @@ -37,25 +34,146 @@ class BlocksFactory(object): return next(iter(vals)) def __FillDataFromDb(self): - self.__Cursor.execute('SELECT * FROM [script_behavior] WHERE parent == ?', (self.m_GraphCKID, )) - for sqldata in self.__Cursor.fetchall(): + cursor: sqlite3.Cursor = self.m_Db.cursor() + cursor.execute('SELECT * FROM [script_behavior] WHERE parent == ?', (self.m_Graph.m_GraphCKID, )) + for sqldata in cursor.fetchall(): payload: DecoratorData.BBDataPayload = DecoratorData.BBDataPayload(sqldata) - self.m_BBDict[payload.m_CKID] = DecoratorData.BBTreeNode(payload) + self.m_Graph.m_BlockDict[payload.m_CKID] = DecoratorData.BBTreeNode(payload) self.__AllBB.add(payload.m_CKID) - self.__Cursor.execute('SELECT * FROM [script_pOper] WHERE parent == ?', (self.m_GraphCKID, )) - for sqldata in self.__Cursor.fetchall(): + cursor.execute('SELECT * FROM [script_pOper] WHERE parent == ?', (self.m_Graph.m_GraphCKID, )) + for sqldata in cursor.fetchall(): payload: DecoratorData.OperDataPayload = DecoratorData.OperDataPayload(sqldata) - self.m_OperDict[payload.m_CKID] = DecoratorData.OperTreeNode(payload) + self.m_Graph.m_BlockDict[payload.m_CKID] = DecoratorData.OperTreeNode(payload) self.__AllOper.add(payload.m_CKID) - def __FindBBBottomOperRoot(self, start_pOut: int) -> tuple[int]: - pass + cursor.close() - def __BuildOper(self, tree: DecoratorData.TreeLayout, start_oper: int): - pass + def __FindBBBottomOperRoot(self, start_pOut: tuple[int]) -> tuple[int]: + cursor: sqlite3.Cursor = self.m_Db.cursor() + cursor_outget: sqlite3.Cursor = self.m_Db.cursor() - def __BuildBB(self, tree: DecoratorData.TreeLayout, start_bb: int): + # prepare something + stack: collections.deque[int] = collections.deque() + procedOut: set[int] = set() + result: set[int] = set() + # prepare start symbol + stack.extend(start_pOut) + + # analyze + while len(stack) != 0: + # peek again + pout: int = stack.pop() + + # search this pOut in pLink + cursor.execute('SELECT [output], [output_obj], [output_type], [output_is_bb] FROM [script_pLink] WHERE ([input] == ? AND NOT (([output_type] == ? OR [output_type] == ?) AND [output_is_bb] == ?) AND [parent] == ?);', + (pout, + DecoratorConst.Export_pLink_InputOutputType.PIN, DecoratorConst.Export_pLink_InputOutputType.PTARGET, DecoratorConst.Export_Boolean.TRUE, # filter all BB's pIn + self.m_Graph.m_GraphCKID) + ) + + # read datas + for (output, output_obj, output_type, output_is_bb, ) in cursor.fetchall(): + # check dup + if output in procedOut: + continue + procedOut.add(output) + + if output_type == DecoratorConst.Export_pLink_InputOutputType.PIN and output_is_bb == DecoratorConst.Export_Boolean.FALSE: + # this is a oper. find its pOut and add into stack + cursor_outget.execute('SELECT [thisobj] FROM [script_pOut] WHERE [parent] == ?;', + (output_obj, ) + ) + for (thisobj, ) in cursor_outget.fetchall(): + stack.append(thisobj) + else: + # this oper point to non-pIn, should be add into result + result.add(output_obj) + + # free cursor and return + cursor.close() + cursor_outget.close() + return tuple(i for i in result) + + def __BuildOper(self, tree: DecoratorData.TreeLayout[DecoratorData.OperTreeNode], start_oper: int): + # prepare stack and start condition + stack: collections.deque[IntermediateTreeNode] = collections.deque() + + # check whether this BB has been processed + if start_oper not in self.__AllOper: + return + self.__AllOper.remove(start_oper) + + # create cursor + cursor: sqlite3.Cursor = self.m_Db.cursor() + + # create new layer and insert it + tree.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) + tree.NewItem(self.m_Graph.m_BlockDict[start_oper]) + + # prepare stack data + start_oper_data: IntermediateTreeNode = IntermediateTreeNode() + start_oper_data.m_LoactedLayer = tree.GetCurrentLayerIndex() + start_oper_data.m_LocatedPos = tree.GetCurrentItemIndex() + cursor.execute("SELECT [input_obj] FROM [script_pLink] WHERE ([output_obj] == ? AND [output_type] == ? AND [input_type] == ? AND [input_is_bb] == ? AND [parent] = ?);", + (start_oper, DecoratorConst.Export_pLink_InputOutputType.PIN, # order pOper's pIn + DecoratorConst.Export_pLink_InputOutputType.POUT, DecoratorConst.Export_Boolean.FALSE, # order pOper's pOut + self.m_Graph.m_GraphCKID, ) + ) + for (input_obj, ) in cursor.fetchall(): + start_oper_data.m_Collection.append(input_obj) + stack.append(start_oper_data) + + # start analyze + while len(stack) != 0: + # pick stack and decide whether pop this + stack_entry: IntermediateTreeNode = stack[-1] + if len(stack_entry.m_Collection) == 0: + stack.pop() + continue + + # pick a new Oper from collection. + # check whether it need process + oper_id: int = stack_entry.m_Collection[-1] + if oper_id not in self.__AllOper: + stack_entry.m_Collection.pop() + continue + self.__AllOper.remove(oper_id) + + # get corresponding tree node + tree_node: DecoratorData.BBTreeNode = self.m_Graph.m_BlockDict[oper_id] + + # start proc Oper + # create new stack entry + oper_data: IntermediateTreeNode = IntermediateTreeNode() + # push tree node into tree layout and get corresponding index. + # create new layer according to whether first visit + if stack_entry.m_FirstVisit: + tree.NewItem(tree_node) + + oper_data.m_LoactedLayer = stack_entry.m_LoactedLayer + oper_data.m_LocatedPos = stack_entry.m_LocatedPos + 1 + # reset first visit + stack_entry.m_FirstVisit = False + else: + tree.NewLayer(stack_entry.m_LoactedLayer, stack_entry.m_LocatedPos) + tree.NewItem(tree_node) + + oper_data.m_LoactedLayer = tree.GetCurrentLayerIndex() + oper_data.m_LocatedPos = tree.GetCurrentItemIndex() + # query and fill stack entry data + cursor.execute("SELECT [input_obj] FROM [script_pLink] WHERE ([output_obj] == ? AND [output_type] == ? AND [input_type] == ? AND [input_is_bb] == ? AND [parent] = ?);", + (oper_id, DecoratorConst.Export_pLink_InputOutputType.PIN, # order pOper's pIn + DecoratorConst.Export_pLink_InputOutputType.POUT, DecoratorConst.Export_Boolean.FALSE, # order pOper's pOut + self.m_Graph.m_GraphCKID, ) + ) + for (output_obj, ) in cursor.fetchall(): + oper_data.m_Collection.append(output_obj) + stack.append(oper_data) + + cursor.close() + + def __BuildBB(self, tree: DecoratorData.TreeLayout[DecoratorData.BBTreeNode], start_bb: int): # prepare stack and start condition stack: collections.deque[IntermediateTreeNode] = collections.deque() @@ -64,18 +182,21 @@ class BlocksFactory(object): return self.__AllBB.remove(start_bb) + # create cursor + cursor: sqlite3.Cursor = self.m_Db.cursor() + # create new layer and insert it tree.NewLayer(DecoratorData.TreeLayout.NO_REFERENCE_LAYER, DecoratorData.TreeLayout.NO_START_POS_OF_REF_LAYER) - tree.NewItem(self.m_BBDict[start_bb]) + tree.NewItem(self.m_Graph.m_BlockDict[start_bb]) # prepare stack data start_bb_data: IntermediateTreeNode = IntermediateTreeNode() start_bb_data.m_LoactedLayer = tree.GetCurrentLayerIndex() start_bb_data.m_LocatedPos = tree.GetCurrentItemIndex() - self.__Cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;", - (start_bb, DecoratorConst.Database_bLink_InputOutputType.OUTPUT, self.m_GraphCKID, ) + cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [parent] = ?) ORDER BY [input_index] ASC;", + (start_bb, DecoratorConst.Export_bLink_InputOutputType.OUTPUT, self.m_Graph.m_GraphCKID, ) ) - for (output_obj, ) in self.__Cursor.fetchall(): + for (output_obj, ) in cursor.fetchall(): start_bb_data.m_Collection.append(output_obj) stack.append(start_bb_data) @@ -96,7 +217,7 @@ class BlocksFactory(object): self.__AllBB.remove(bb_id) # get corresponding tree node - tree_node = self.m_BBDict[bb_id] + tree_node: DecoratorData.BBTreeNode = self.m_Graph.m_BlockDict[bb_id] # start proc BB # create new stack entry @@ -117,25 +238,33 @@ class BlocksFactory(object): bb_data.m_LoactedLayer = tree.GetCurrentLayerIndex() bb_data.m_LocatedPos = tree.GetCurrentItemIndex() # query and fill stack entry data - self.__Cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;", - (bb_id, DecoratorConst.Database_bLink_InputOutputType.OUTPUT, self.m_GraphCKID, ) + cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;", + (bb_id, DecoratorConst.Export_bLink_InputOutputType.OUTPUT, self.m_Graph.m_GraphCKID, ) ) - for (output_obj, ) in self.__Cursor.fetchall(): + for (output_obj, ) in cursor.fetchall(): bb_data.m_Collection.append(output_obj) stack.append(bb_data) # todo: executing oper finder for current bb + cursor.close() + def __ProcActiveBB(self): - self.__Cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;", - (self.m_GraphCKID, DecoratorConst.Database_bLink_InputOutputType.INPUT, self.m_GraphCKID, ) + cursor: sqlite3.Cursor = self.m_Db.cursor() + cursor.execute("SELECT [output_obj] FROM [script_bLink] WHERE ([input_obj] == ? AND [input_type] == ? AND [belong_to] = ?) ORDER BY [input_index] ASC;", + (self.m_Graph.m_GraphCKID, DecoratorConst.Export_bLink_InputOutputType.INPUT, self.m_Graph.m_GraphCKID, ) ) - for (output_obj, ) in self.__Cursor.fetchall(): - self.__BuildBB(self.m_ActiveBBLayer, output_obj) + for (output_obj, ) in cursor.fetchall(): + self.__BuildBB(self.m_Graph.m_ActiveBB, output_obj) + + cursor.close() def __ProcPassiveBB(self): + cursor: sqlite3.Cursor = self.m_Db.cursor() while len(self.__AllBB) != 0: self.__BuildBB(self.m_PassiveBBLayer, self.__GetOneFromSet(self.__AllBB)) + cursor.close() + def __ProcPassiveOper(self): pass diff --git a/SuperScriptDecorator/DecoratorConst.py b/SuperScriptDecorator/DecoratorConst.py index b24f0f7..8f1ce35 100644 --- a/SuperScriptDecorator/DecoratorConst.py +++ b/SuperScriptDecorator/DecoratorConst.py @@ -1,9 +1,13 @@ -class Database_bLink_InputOutputType(object): +class Export_Boolean(object): + TRUE = 1 + FALSE = 0 + +class Export_bLink_InputOutputType(object): INPUT = 0 OUTPUT = 1 -class Database_pLink_InputOutputType(object): +class Export_pLink_InputOutputType(object): PIN = 0 POUT = 1 PLOCAL = 2 diff --git a/SuperScriptDecorator/DecoratorData.py b/SuperScriptDecorator/DecoratorData.py index cd037e7..29a2df4 100644 --- a/SuperScriptDecorator/DecoratorData.py +++ b/SuperScriptDecorator/DecoratorData.py @@ -1,3 +1,14 @@ +''' +NOTE: + +There are 3 different styles shape in generated graph. +"Block" is stands for the large block, including BB and pOper. +"Cell" is stands for the medium block, including pLocal, pAttr, Shortcut. +"Particle" is stands for the small block, including bIO, pIO, pTarget. + +Besides these shapes, the generated graph also include various links. +There are 2 types link. bLink and pLink. +''' import typing, collections, sqlite3 class Vector(object): @@ -59,7 +70,7 @@ class Margin(object): self.m_BodySize: Vector = Vector() self.m_BottomSize: Vector = Vector() -class ICanComputeSize(object): +class ICanManipulate(object): ''' This class is served for TreeLayout class. @@ -70,23 +81,15 @@ class ICanComputeSize(object): The reason is that the vertical and horizonal direction between BB and Oper is opposited. So we use Leaves and Root to give theme an uniformed concept. ''' - def GetPos() -> Vector: - ''' - Get current node's start position. - ''' - raise NotImplementedError() - def GetSize() -> Vector: - ''' - Get current node's size. - ''' - raise NotImplementedError() + def SetOrigin(): + pass def ComputeSize() -> Vector: ''' Get current node's start position ''' raise NotImplementedError() -TNode = typing.TypeVar('TNode', bound=ICanComputeSize) +TNode = typing.TypeVar('TNode', bound=ICanManipulate) class TreeLayoutLayer(typing.Generic[TNode]): def __init__(self, ref_layer: int, start_pos_of_ref_layer: int): @@ -154,11 +157,11 @@ class OperDataPayload(object): self.m_OpGuid: str = v.op_guid self.m_Parent: int = v.parent -class OperTreeNode(ICanComputeSize): +class OperTreeNode(ICanManipulate): def __init__(self, payload: OperDataPayload): self.m_Payload: OperDataPayload = payload -class BBTreeNode(ICanComputeSize): +class BBTreeNode(ICanManipulate): def __init__(self, payload: BBDataPayload): self.m_UpperOper: TreeLayout[OperTreeNode] = TreeLayout() self.m_LowerOper: TreeLayout[OperTreeNode] = TreeLayout() @@ -167,8 +170,19 @@ class BBTreeNode(ICanComputeSize): self.m_Payload: BBDataPayload = payload -class GraphWork(ICanComputeSize): +class GraphResult(ICanManipulate): def __init__(self): + self.m_GraphCKID: int = 0 + + self.m_BlockDict: dict[int, ICanManipulate] = {} + self.m_CellDict: dict[int, ICanManipulate] = {} + self.m_ParticleDict: dict[int, ICanManipulate] = {} + + self.m_bIn: collections.deque = collections.deque() + self.m_bOut: collections.deque = collections.deque() + self.m_pIn: collections.deque = collections.deque() + self.m_pOut: collections.deque = collections.deque() + self.m_PassiveVal: collections.deque = collections.deque() self.m_PassiveOper: TreeLayout[OperTreeNode] = TreeLayout() self.m_ActiveBB: TreeLayout[BBTreeNode] = TreeLayout()