#include "parse_novel.h" #include #include #include using namespace example_novel; using namespace ast_basic; using namespace ast_gen; using namespace lib_syntax; using namespace example_novel; void FragmentExistsCheck::exists_check(std::shared_ptr root, std::shared_ptr target) const { if (target->element()->typeMark() == (int)NovelNode::FragmentRefer) { auto refer = std::dynamic_pointer_cast(target->element()); auto signature = refer->storyRefer() + u8"&" + refer->fragmentRefer(); root->getNamedNodeBy((int)NovelNode::FragmentDefine, signature); } for (auto& xit : target->children()) { exists_check(root, xit); } } void FragmentExistsCheck::validCheck(std::shared_ptr root) const { this->exists_check(std::dynamic_pointer_cast(root->element()), root); } QString FragmentExistsCheck::name() const { return u8"FragmentExistsCheck"; } QList> FragmentGraphCheck::refers_cycle_check( std::shared_ptr item, QList> prevs) const { if (prevs.contains(item)) { return prevs << item; } auto next_list = item->nextList(); if (next_list.size()) { prevs << item; for (auto next : next_list) { auto ref_link = refers_cycle_check(next, prevs); if (ref_link.size()) return ref_link; } } return QList>(); } void FragmentGraphCheck::setElement(std::shared_ptr inst) { elements_store[inst->nodePeer()->signature()] = inst; } std::shared_ptr FragmentGraphCheck::getElement(const QString& signature) const { return elements_store[signature]; } QList> FragmentGraphCheck::getHangoutNodes() { QList> values; for (auto node_item : elements_store) { if (!node_item->inDegree()) values.append(node_item); } for (auto inst : values) { auto name = inst->nodePeer()->signature(); elements_store.remove(name); } return values; } bool FragmentGraphCheck::nodeDismantle(std::shared_ptr inst) { bool flag = false; for (auto item : inst->nextList()) { item->inDegree()--; flag = true; } return flag; } void FragmentGraphCheck::validCheck(std::shared_ptr root) const { std::function>(std::shared_ptr)> story_peak = [&](std::shared_ptr root)->QList> { QList> return_temp; auto type_mark = (NovelNode)root->element()->typeMark(); if (type_mark == NovelNode::StoryDefine) { return_temp << root; } for (auto child : root->children()) { return_temp.append(story_peak(child)); } return return_temp; }; auto self = std::const_pointer_cast(this->shared_from_this()); // 获取所有故事线 auto all_story = story_peak(root); // 注册图节点 for (auto story : all_story) { auto fragment_items = story->children(); // 构建情节节点列表 for (auto frag_primitive : fragment_items) { switch (frag_primitive->element()->typeMark()) { case (int)NovelNode::FragmentDefine: { auto target_node = std::dynamic_pointer_cast(frag_primitive->element()); auto finst = std::make_shared(target_node); self->setElement(finst); }break; default: break; } } } // 构建图连接 for (auto story : all_story) { auto fragment_items = story->children(); // 过滤获取情节节点 for (auto idx = 0; idx < fragment_items.size(); idx++) { auto fragment_inst = fragment_items[idx]; switch (fragment_inst->element()->typeMark()) { case (int)NovelNode::FragmentDefine: case (int)NovelNode::FragmentRefer: break; default: fragment_items.removeAt(idx); idx--; break; } } auto get_name = [](std::shared_ptr node)->QString { switch (node->element()->typeMark()) { case (int)NovelNode::FragmentDefine: { auto def_node = std::dynamic_pointer_cast(node->element()); return def_node->signature(); }break; case (int)NovelNode::FragmentRefer: { auto ref_node = std::dynamic_pointer_cast(node->element()); return ref_node->referSignature(); }break; } return QString(); }; // 构建完整图结构 for (auto fidx = 1; fidx < fragment_items.size(); fidx++) { auto tail_name = get_name(fragment_items[fidx - 1]); auto head_name = get_name(fragment_items[fidx]); auto tail_helper = getElement(tail_name); auto head_helper = getElement(head_name); tail_helper->appendNext(head_helper); head_helper->inDegree()++; } } // 获取拓扑排序序列 auto values = self->getHangoutNodes(); for (auto idx = 0; idx < values.size(); ++idx) { auto target = values[idx]; self->nodeDismantle(target); auto x_values = self->getHangoutNodes(); values.append(x_values); } // 理论上不应该有残余 if (elements_store.size()) { for (auto node : elements_store.values()) { auto cycle_link = refers_cycle_check(node); QString error_msg = u8"Parse[0x0006]情节图存在环形结构:\n"; for (auto n : cycle_link) { error_msg += QString(u8"%1->").arg(n->nodePeer()->signature()); } if (cycle_link.size()) throw new lib_parse::CheckException(error_msg); } } } QString FragmentGraphCheck::name() const { return u8"FragmentGraphCheck"; } FragmentGraphHelper::FragmentGraphHelper(std::shared_ptr node) : node_peer(node) {} std::shared_ptr FragmentGraphHelper::nodePeer() const { return this->node_peer; } void FragmentGraphHelper::appendNext(std::shared_ptr node) { this->next_nodes.append(node); } QList> FragmentGraphHelper::nextList() const { return next_nodes; } uint& FragmentGraphHelper::inDegree() { return this->indegree; }