276 lines
8.6 KiB
C++
276 lines
8.6 KiB
C++
|
#include "parse_novel.h"
|
|||
|
|
|||
|
#include <ast_novel.h>
|
|||
|
#include <iterator>
|
|||
|
|
|||
|
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<const ast_gen::GlobalElement> root,
|
|||
|
std::shared_ptr<const ast_gen::ElementAccess> target) const {
|
|||
|
if (target->element()->typeMark() == (int)example_novel::NovelNode::FragmentRefer) {
|
|||
|
auto refer = std::dynamic_pointer_cast<const example_novel::FragmentRefers>(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<const ast_gen::ElementAccess> root) const {
|
|||
|
this->exists_check(std::dynamic_pointer_cast<const ast_gen::GlobalElement>(root->element()), root);
|
|||
|
}
|
|||
|
|
|||
|
FragmentSortHelper::FragmentSortHelper(std::shared_ptr<const ast_gen::ElementAccess> 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<const ast_gen::ElementAccess> FragmentSortHelper::nodeBind() const { return element_bind; }
|
|||
|
|
|||
|
int FragmentSortHelper::storySort() const
|
|||
|
{
|
|||
|
return story_sort;
|
|||
|
}
|
|||
|
|
|||
|
std::shared_ptr<FragmentSortHelper> FragmentSortHelper::next() const {
|
|||
|
return next_attachment;
|
|||
|
}
|
|||
|
|
|||
|
void FragmentSortHelper::attachNext(std::shared_ptr<FragmentSortHelper> fragment) {
|
|||
|
this->next_attachment = fragment;
|
|||
|
}
|
|||
|
|
|||
|
void FragmentSortHelper::assignSibling(std::shared_ptr<FragmentSortHelper> other)
|
|||
|
{
|
|||
|
auto temp_list = this->siblings_store;
|
|||
|
temp_list.append(other->siblings_store);
|
|||
|
temp_list.append(other);
|
|||
|
temp_list.append(shared_from_this());
|
|||
|
|
|||
|
QHash<QString, std::shared_ptr<FragmentSortHelper>> 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<std::shared_ptr<FragmentSortHelper> > FragmentSortHelper::siblings() const
|
|||
|
{
|
|||
|
return siblings_store;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void FragmentOrdersCheck::elements_link_build(const QList<std::shared_ptr<StorySortHelper> >& stories)
|
|||
|
{
|
|||
|
QHash<QString, std::shared_ptr<StorySortHelper>> helper;
|
|||
|
for (auto& i : stories)
|
|||
|
helper[i->storyName()] = i;
|
|||
|
|
|||
|
auto auto_refer = [&](std::shared_ptr<StorySortHelper> 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<const example_novel::FragmentRefers>(access->element());
|
|||
|
if (!helper.contains(elm->storyRefer())) {
|
|||
|
throw new lib_parse::CheckException(QString(u8"Parse[0x0001]<5D><><EFBFBD><EFBFBD><EFBFBD>ߡ<EFBFBD>%1<><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڣ<EFBFBD>").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]<5D><><EFBFBD><EFBFBD><EFBFBD>ߡ<EFBFBD>%1<><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڡ<EFBFBD>%2<><32><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڣ<EFBFBD>").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);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void FragmentOrdersCheck::sort_cycle_check(const QList<std::shared_ptr<FragmentSortHelper>>& tracks, std::shared_ptr<FragmentSortHelper> current, int story_sort_source)
|
|||
|
{
|
|||
|
if (!current)
|
|||
|
return;
|
|||
|
|
|||
|
if (tracks.contains(current)) {
|
|||
|
QString error_cycle;
|
|||
|
for (auto& it : tracks)
|
|||
|
error_cycle += u8"->" + it->nodeBind()->element()->signature() + u8"\n";
|
|||
|
error_cycle += u8"->" + current->nodeBind()->element()->signature() + u8"<EFBFBD><EFBFBD>";
|
|||
|
|
|||
|
throw new lib_parse::CheckException(u8"Parse[0x0003]<5D><><EFBFBD><EFBFBD><EFBFBD>쳣<EFBFBD><ECB3A3>\n" + error_cycle);
|
|||
|
}
|
|||
|
|
|||
|
auto nlist = tracks;
|
|||
|
|
|||
|
if (current->nodeType() == example_novel::FragmentSortHelper::Type::REFER) {
|
|||
|
decltype (current->siblings()) fork_list;
|
|||
|
for (auto& vit : current->siblings()) {
|
|||
|
if (vit->storySort() <= story_sort_source)
|
|||
|
fork_list << vit;
|
|||
|
}
|
|||
|
|
|||
|
for (auto& fork : fork_list) {
|
|||
|
sort_cycle_check(nlist, fork, story_sort_source);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
nlist.append(peaks_appoint_element(current));
|
|||
|
sort_cycle_check(nlist, current->next(), story_sort_source);
|
|||
|
}
|
|||
|
|
|||
|
std::shared_ptr<FragmentSortHelper> example_novel::FragmentOrdersCheck::peaks_appoint_element(std::shared_ptr<FragmentSortHelper> refer_n)
|
|||
|
{
|
|||
|
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<const ast_gen::ElementAccess> root) const {
|
|||
|
std::function<QList<std::shared_ptr<const ast_gen::ElementAccess>>(std::shared_ptr<const ast_gen::ElementAccess>)> peak_story =
|
|||
|
[&](std::shared_ptr<const ast_gen::ElementAccess> pnode) -> QList<std::shared_ptr<const ast_gen::ElementAccess>> {
|
|||
|
QList<std::shared_ptr<const ast_gen::ElementAccess>> 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<const ast_gen::ElementAccess> itema, std::shared_ptr<const ast_gen::ElementAccess> itemb) -> bool {
|
|||
|
auto storya = std::dynamic_pointer_cast<const example_novel::StoryDefine>(itema->element());
|
|||
|
auto storyb = std::dynamic_pointer_cast<const example_novel::StoryDefine>(itemb->element());
|
|||
|
return storya->sort() < storyb->sort();
|
|||
|
});
|
|||
|
|
|||
|
for (auto& sit : stories) {
|
|||
|
auto story_sort = std::make_shared<StorySortHelper>(sit);
|
|||
|
const_cast<FragmentOrdersCheck*>(this)->stories_list << story_sort;
|
|||
|
|
|||
|
auto children = sit->children();
|
|||
|
std::shared_ptr<FragmentSortHelper> 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<FragmentSortHelper>(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;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// <20>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
int prev_sort = 0;
|
|||
|
for (auto& s : stories_list) {
|
|||
|
if (s->sortValue() < 1)
|
|||
|
throw new lib_parse::CheckException(u8"Parse[0x0006]<5D><><EFBFBD>¡<EFBFBD>%1<><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1<><31>");
|
|||
|
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]<5D><><EFBFBD>¡<EFBFBD>%1<><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¡<EFBFBD>%2<><32><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD>").arg(s->storyName()).arg(prev->storyName()));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const_cast<FragmentOrdersCheck*>(this)->elements_link_build(this->stories_list);
|
|||
|
|
|||
|
for (auto& s : this->stories_list)
|
|||
|
const_cast<FragmentOrdersCheck*>(this)->sort_cycle_check(QList<std::shared_ptr<FragmentSortHelper>>(), s->fragmentSort(), s->sortValue());
|
|||
|
}
|
|||
|
|
|||
|
StorySortHelper::StorySortHelper(std::shared_ptr<const ast_gen::ElementAccess> story_bind) {
|
|||
|
this->story_bind = story_bind;
|
|||
|
this->fragments_bind = nullptr;
|
|||
|
}
|
|||
|
|
|||
|
std::shared_ptr<const example_novel::StoryDefine> StorySortHelper::storyElement() const {
|
|||
|
return std::dynamic_pointer_cast<const example_novel::StoryDefine>(story_bind->element());
|
|||
|
}
|
|||
|
|
|||
|
QString StorySortHelper::storyName() const { return storyElement()->name(); }
|
|||
|
|
|||
|
int StorySortHelper::sortValue() const
|
|||
|
{
|
|||
|
return storyElement()->sort();
|
|||
|
}
|
|||
|
|
|||
|
std::shared_ptr<FragmentSortHelper> StorySortHelper::fragmentSort() const {
|
|||
|
return this->fragments_bind;
|
|||
|
}
|
|||
|
|
|||
|
void StorySortHelper::attachFragmentSort(std::shared_ptr<FragmentSortHelper> refer) {
|
|||
|
this->fragments_bind = refer;
|
|||
|
}
|
|||
|
|
|||
|
std::shared_ptr<FragmentSortHelper> 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<const example_novel::FragmentDefine>(temp_ptr->nodeBind()->element());
|
|||
|
if (node->name() == name)
|
|||
|
return temp_ptr;
|
|||
|
}
|
|||
|
temp_ptr = temp_ptr->next();
|
|||
|
} while (temp_ptr);
|
|||
|
|
|||
|
return nullptr;
|
|||
|
}
|
|||
|
|