Zt_|K?
zA?jl^325#b&Ch5apm`Nu@oxwgZ-CKTfbLU#8xD)wsvMI2&z~TKp67`oDlMsAOZ$dq
z1NMO>+6FuzM`_(K38b+vi#4h3N_*<0#nRAJXK_SnOPy*Mu)6i}yqFh5fqx@CBpUAV
zh%%>-$w}RCjek2SPb)gmCUWVdt}E2=j$b~PoqH;t&(7#Z%lNl)Fp!Ar$!sRX8T_~o
zwLku>rqg&rR~7xatPB+4sidZd6OBq(XF@7p1?mb>NR*RFlvf-wrwCKL%r6O54WlAZ
z9gHe8P@SN))9^g4s9Bm1XJy53QbnJknS^zMY&l#9|CJ85j$Rv+x#~$@
DNczCl
literal 0
HcmV?d00001
diff --git a/frame/__pycache__/__init__.cpython-312.pyc b/frame/__pycache__/__init__.cpython-312.pyc
index 9cabe467e0f5f0e6ac9379fe1f0b80e9c32604a1..7a98443a3b14fb1d226286978594ab948629829c 100644
GIT binary patch
delta 26
gcmbQrIDwJtG%qg~0}!acnaE|rs6WwOVq%OX08f$zK>z>%
delta 32
mcmbQhIF*s>G%qg~0}xo;oXBOuXfn}Wg4H=AH931?xFrC2WC$Vv
diff --git a/parse/StoryMap.py b/parse/StoryMap.py
new file mode 100644
index 0000000..7441793
--- /dev/null
+++ b/parse/StoryMap.py
@@ -0,0 +1,149 @@
+import xml.dom.minidom as mdom
+from typing import List, Tuple, Dict
+from enum import Enum
+from frame.ReferView import EmptyNode, MemoryNode
+
+
+class ModifyReason(Enum):
+ Removed = 0,
+ Append = 1,
+ Changed = 2,
+ Nothing = 4,
+
+
+class FragmentSlice(EmptyNode):
+ def __init__(self, def_mark: bool = False, name: str= ""):
+ self.is_define_node = (def_mark, name)
+ self.story_refer = ""
+ self.fragm_refer = ""
+
+ self.prev_node: 'FragmentSlice' = None # 上游节点
+ self.next_node: 'FragmentSlice' = None # 下游节点
+ self.refers_slice: Dict[str, 'FragmentSlice'] = {} # 引用切面
+
+ self.changed_prev_nodes: List[Tuple[ModifyReason, 'FragmentSlice']] = [] # 变更的上游节点
+ self.text_sections: List[str] = [] # 文本段落
+ pass
+
+ def get_from_memory(self) -> str:
+ return r"\n".join(self.text_sections)
+ pass
+
+ def set_to_memory(self, content: str):
+ self.text_sections = content.split(r"\n")
+ pass
+
+
+class StoryMap:
+ def __init__(self, name: str):
+ self.story_name = name
+ self.sort_index = 0
+ self.empty_head = FragmentSlice()
+ self.slice_list: List[FragmentSlice] = [self.empty_head]
+ pass
+
+ def append_fragment_slice(self, node: FragmentSlice):
+ self.slice_list[-1].next_node = node
+ node.prev_node = self.slice_list[-1]
+ self.slice_list.append(node)
+ pass
+
+ def get_fragment_defined(self, name: str) -> FragmentSlice:
+ for fit in self.slice_list:
+ if fit.is_define_node[0]:
+ if fit.is_define_node[1] == name:
+ return fit
+ pass
+ pass
+ return None
+
+
+class XAST_ParseTool:
+ def __init__(self, ast_path: str):
+ self.dom_tree = mdom.parse(ast_path)
+ self.story_list: List[StoryMap] = []
+ names = self.story_names()
+ for nm in names:
+ vinst = self.__extract_empty_storymap(nm)
+ self.__storynode_initfrags(vinst[0], vinst[1])
+ self.story_list.append(vinst[0])
+ pass
+
+ def story_names(self) -> List[str]:
+ """
+ 获取所有故事名称
+ :return: List[故事名]
+ """
+ storys = self.dom_tree.getElementsByTagName("story")
+ values = []
+ for n in storys:
+ values.append(n.getAttribute("name"))
+ pass
+ return values
+
+ def __extract_empty_storymap(self, name: str) -> Tuple[StoryMap, mdom.Element]:
+ storys = self.dom_tree.getElementsByTagName("story")
+ for node in storys:
+ if node.getAttribute("name") == name:
+ mem_node = StoryMap(name)
+ mem_node.sort_index = int(node.getAttribute("sort"))
+ return (mem_node, node)
+ pass
+ return None
+
+ def __storynode_initfrags(self, node: StoryMap, e: mdom.Element):
+ first_elem: mdom.Element = e.firstChild
+ while first_elem != None:
+ if hasattr(first_elem, "tagName"):
+ dom_tag = first_elem.tagName
+ if first_elem.tagName == "fragment":
+ fnode = FragmentSlice(True, first_elem.getAttribute("name"))
+ self.__fragmnode_init_desc(fnode, first_elem)
+ node.append_fragment_slice(fnode)
+ elif first_elem.tagName == "refer":
+ fnode = FragmentSlice()
+ fnode.story_refer = first_elem.getAttribute("story")
+ fnode.fragm_refer = first_elem.getAttribute("fragment")
+ self.__fragmnode_init_desc(fnode, first_elem)
+ node.append_fragment_slice(fnode)
+ pass
+ pass
+ first_elem = first_elem.nextSibling
+ pass
+
+ def __fragmnode_init_desc(self, node: FragmentSlice, e: mdom.Element):
+ node_elem: mdom.Element = e.firstChild
+ while node_elem != None:
+ if hasattr(node_elem, "tagName") and node_elem.tagName == "text-section":
+ line = node_elem.getAttribute("text")
+ node.text_sections.append(line)
+ pass
+ node_elem = node_elem.nextSibling
+ pass
+ pass
+
+ def storylines_plait(self, storys: Dict[str, StoryMap]):
+ for snode in storys.values():
+ self.__storyline_plait_within(snode, storys)
+ pass
+
+ def __storyline_plait_within(self, story: StoryMap, storys_map: Dict[str, StoryMap]):
+ for fnode in story.slice_list[1:]:
+ if not fnode.is_define_node[0]:
+ sname = fnode.story_refer
+ fname = fnode.fragm_refer
+ target_story = storys_map[sname]
+ target_fragment = target_story.get_fragment_defined(fname)
+ target_fragment.refers_slice[story.story_name] = fnode
+ pass
+ pass
+ pass
+ pass
+
+
+def storyline_list2map(storylines: List[StoryMap]) -> Dict[str, StoryMap]:
+ retv = {}
+ for linst in storylines:
+ retv[linst.story_name] = linst
+ pass
+ return retv
diff --git a/parse/StorylineCmp.py b/parse/StorylineCmp.py
new file mode 100644
index 0000000..5c6e2ab
--- /dev/null
+++ b/parse/StorylineCmp.py
@@ -0,0 +1,53 @@
+from parse.StoryMap import StoryMap, ModifyReason, FragmentSlice
+from typing import Dict, List
+
+
+class CmpTool:
+ def __init__(self):
+ pass
+
+ def graph_compare(self, graph_new: Dict[str, StoryMap], graph_old: Dict[str, StoryMap]):
+ fragments_has_removed = []
+ for story in graph_old.values():
+ fragments_has_removed = fragments_has_removed + self.__event_remove_check(graph_new, story)
+ pass
+
+ fragments_has_appended = []
+ for story in graph_new.values():
+ fragments_has_appended = fragments_has_appended + self.__event_append_check(graph_old, story)
+ pass
+
+
+
+
+ pass
+
+ def __event_remove_check(self, graph_new: Dict[str, StoryMap], story_old: StoryMap) -> List[FragmentSlice]:
+ list_retv = []
+ for slice in story_old.slice_list[1:]:
+ if slice.is_define_node[0]:
+ s_name = story_old.story_name
+ f_name = slice.is_define_node[1]
+ story_findout = graph_new[s_name]
+ if story_findout is None or story_findout.get_fragment_defined(f_name) is None:
+ list_retv.append(slice)
+ pass
+ pass
+ pass
+ return list_retv
+
+ def __event_append_check(self, graph_old: Dict[str, StoryMap], story_new: StoryMap) -> List[FragmentSlice]:
+ list_retv = []
+ for slice in story_new.slice_list[1:]:
+ if slice.is_define_node[0]:
+ s_name = story_new.story_name
+ f_name = slice.is_define_node[1]
+ story_findout = graph_old[s_name]
+ if story_findout is None or story_findout.get_fragment_defined(f_name) is None:
+ list_retv.append(slice)
+ pass
+ pass
+ pass
+ return list_retv
+
+ def __event_changed_check(self,):
\ No newline at end of file
diff --git a/parse/__pycache__/StoryMap.cpython-312.pyc b/parse/__pycache__/StoryMap.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fa229177ecdc447102027ae80da9b8b8f864edfe
GIT binary patch
literal 6516
zcmbVQOKcm*8J=A(pW;gv^|bYfEL)-=(NbbJj^oC)EkBajv|}kn!`fKT+NDf|4`p`c
zngR{DfDbZY)JiXw>x1P>!@w8i6!+Bh)B?Sjq7t$T7YWcqksA{k2#`zr|FaK@G}WRV
zfb;xkIRESW|JlF#d>#U2=AXY$M1zF<0|#cY8=bA+LFYb^h{UBxnw#Z0lICMJ4rln3
zkhaI{X-CYFcE+4+&X#he-7z=o3n@>!CDxMm#=IQi$r&QqZxhKOyPw$f(_=n1>x5aC
z++xl8*{mC8Jx_RpGQj3qV9smJ1#?{3_bn1c!!}JgmsC{EKC`%xk~Lu}Ije>_O*oZV
zOow^ReJZ`6=Av0i);#Csbe6LItbVv&bH-q64|MJmnZ!7W#CVB|*(5$DNVb?=5@L>=
zJ?zlD=d)5Wk-H?vm24)=QM_fC`xcLY#uy1OiiVw