#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)example_novel::NovelNode::FragmentRefer) { auto refer = std::dynamic_pointer_cast(target->element()); auto signature = refer->storyRefer() + u8"&" + refer->fragmentRefer(); root->getNamedNodeBy((int)example_novel::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); } FragmentSortHelper::FragmentSortHelper(std::shared_ptr node_bind, int story_sort) { if (node_bind->element()->typeMark() == (int)example_novel::NovelNode::FragmentDefine) { type_marks = Type::ELEMENT; } else { type_marks = Type::REFER; } element_bind = node_bind; next_attachment = nullptr; this->story_sort = story_sort; } FragmentSortHelper::Type FragmentSortHelper::nodeType() const { return type_marks; } std::shared_ptr FragmentSortHelper::nodeBind() const { return element_bind; } int FragmentSortHelper::storySort() const { return story_sort; } std::shared_ptr FragmentSortHelper::next() const { return next_attachment; } void FragmentSortHelper::attachNext(std::shared_ptr fragment) { this->next_attachment = fragment; } void FragmentSortHelper::assignSibling(std::shared_ptr other) { auto temp_list = this->siblings_store; temp_list.append(other->siblings_store); temp_list.append(other); temp_list.append(shared_from_this()); QHash> helpers; for (auto& it : temp_list) { helpers[it->element_bind->element()->signature()] = it; } temp_list = helpers.values(); for (auto& it : temp_list) { auto vlist = temp_list; vlist.removeAll(it); it->siblings_store = vlist; } } QList > FragmentSortHelper::siblings() const { return siblings_store; } void FragmentOrdersCheck::elements_link_build(const QList >& stories) { QHash> helper; for (auto& i : stories) helper[i->storyName()] = i; auto auto_refer = [&](std::shared_ptr story) { auto fragment_head = story->fragmentSort(); while (fragment_head) { switch (fragment_head->nodeType()) { case FragmentSortHelper::Type::REFER: { auto access = fragment_head->nodeBind(); auto elm = std::dynamic_pointer_cast(access->element()); if (!helper.contains(elm->storyRefer())) { throw new lib_parse::CheckException(QString(u8"Parse[0x0001]故事线“%1”不存在!").arg(elm->storyRefer())); } auto story_target = helper[elm->storyRefer()]; auto fragm_target = story_target->fragment(elm->fragmentRefer()); if (!fragm_target) { throw new lib_parse::CheckException( QString(u8"Parse[0x0002]故事线“%1”的情节“%2”不存在!").arg(elm->storyRefer()).arg(elm->fragmentRefer())); } fragment_head->assignSibling(fragm_target); }break; default: break; } fragment_head = fragment_head->next(); } }; for (auto& vit : stories) { auto_refer(vit); } } template void cast(InputIt Begin, InputIt End, OutputIt Dst, Operate fn) { while (Begin != End) { *Dst++ = fn(*Begin++); } } void FragmentOrdersCheck::sort_cycle_check(const QList>& tracks, std::shared_ptr _current, int story_sort_source) { if (!_current || !_current->next()) return; auto target = _current->next(); if (tracks.contains(peaks_appoint_element(target))) { QString error_cycle; for (auto& it : tracks) error_cycle += u8"->" + it->nodeBind()->element()->signature() + u8"\n"; error_cycle += u8"->" + target->nodeBind()->element()->signature() + u8"。"; throw new lib_parse::CheckException(u8"Parse[0x0003]排序异常:\n" + error_cycle); } auto nlist = tracks; nlist.append(peaks_appoint_element(target)); if (target->nodeType() == example_novel::FragmentSortHelper::Type::REFER) { decltype (target->siblings()) sibling_forks; auto siblings = target->siblings(); for (auto& vit : siblings) { if (vit->storySort() <= story_sort_source) sibling_forks << vit; } for (auto& fork : sibling_forks) { sort_cycle_check(nlist, fork, story_sort_source); } } sort_cycle_check(nlist, target, story_sort_source); } std::shared_ptr example_novel::FragmentOrdersCheck::peaks_appoint_element(std::shared_ptr refer_n) const { if (refer_n->nodeType() == example_novel::FragmentSortHelper::Type::ELEMENT) return refer_n; auto sibs = refer_n->siblings(); for (auto ptr : sibs) { if (ptr->nodeType() == example_novel::FragmentSortHelper::Type::ELEMENT) return ptr; } return nullptr; } void FragmentOrdersCheck::validCheck(std::shared_ptr root) const { std::function>(std::shared_ptr)> peak_story = [&](std::shared_ptr pnode) -> QList> { QList> listret; if (pnode->element()->typeMark() == (int)example_novel::NovelNode::StoryDefine) listret << pnode; for (auto& vit : pnode->children()) listret.append(peak_story(vit)); return listret; }; auto stories = peak_story(root); std::sort(std::begin(stories), std::end(stories), [](std::shared_ptr itema, std::shared_ptr itemb) -> bool { auto storya = std::dynamic_pointer_cast(itema->element()); auto storyb = std::dynamic_pointer_cast(itemb->element()); return storya->sort() < storyb->sort(); }); for (auto& sit : stories) { auto story_sort = std::make_shared(sit); const_cast(this)->stories_list << story_sort; auto children = sit->children(); std::shared_ptr temp_ptr = nullptr; for (auto& nf : children) { switch ((example_novel::NovelNode)nf->element()->typeMark()) { case example_novel::NovelNode::FragmentDefine: case example_novel::NovelNode::FragmentRefer: { auto frag_sort = std::make_shared(nf, story_sort->sortValue()); if (!temp_ptr) { story_sort->attachFragmentSort(frag_sort); } else { temp_ptr->attachNext(frag_sort); } temp_ptr = frag_sort; } break; default: break; } } } // 重复排序检查 int prev_sort = 0; for (auto& s : stories_list) { if (s->sortValue() < 1) throw new lib_parse::CheckException(u8"Parse[0x0006]故事“%1”的排序<1。"); if (prev_sort >= s->sortValue()) { auto idx = stories_list.indexOf(s); auto prev = stories_list[idx - 1]; throw new lib_parse::CheckException(QString(u8"Parse[0x0007]故事“%1”与故事“%2”排序重复。").arg(s->storyName()).arg(prev->storyName())); } } const_cast(this)->elements_link_build(this->stories_list); for (auto& s : this->stories_list) { if(!s->fragmentSort()) continue; QList> tracks; tracks << peaks_appoint_element(s->fragmentSort()); const_cast(this)->sort_cycle_check(tracks, s->fragmentSort(), s->sortValue()); } } StorySortHelper::StorySortHelper(std::shared_ptr story_bind) { this->story_bind = story_bind; this->fragments_bind = nullptr; } std::shared_ptr StorySortHelper::storyElement() const { return std::dynamic_pointer_cast(story_bind->element()); } QString StorySortHelper::storyName() const { return storyElement()->name(); } int StorySortHelper::sortValue() const { return storyElement()->sort(); } std::shared_ptr StorySortHelper::fragmentSort() const { return this->fragments_bind; } void StorySortHelper::attachFragmentSort(std::shared_ptr refer) { this->fragments_bind = refer; } std::shared_ptr StorySortHelper::fragment(const QString& name) const { auto temp_ptr = fragments_bind; do { if (temp_ptr->nodeType() == FragmentSortHelper::Type::ELEMENT) { auto node = std::dynamic_pointer_cast(temp_ptr->nodeBind()->element()); if (node->name() == name) return temp_ptr; } temp_ptr = temp_ptr->next(); } while (temp_ptr); return nullptr; }