WsParser_VS/libParse/parse_novel.cpp

319 lines
9.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "parse_novel.h"
#include <ast_novel.h>
#include <iterator>
#include <QTime>
using namespace lib_parse;
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 GlobalElement> root,
std::shared_ptr<const ElementAccess> target) const {
if (target->element()->typeMark() == (int)NovelNode::PointRefers) {
auto refer = std::dynamic_pointer_cast<const PointRefers>(target->element());
auto signature = refer->storyRefer() + u8"&" + refer->fragmentRefer();
if (!root->getNamedNodeBy((int)NovelNode::PointDefines, signature))
throw new SyntaxException(QString(u8"CheckError[0x0005]系统中不包含指定签名的节点:%1<type%2>{%3:(%4)}")
.arg(signature).arg((int)NovelNode::PointDefines).arg(refer->signature()).arg(refer->filePath()));
}
for (auto& xit : target->children()) {
exists_check(root, xit);
}
}
void FragmentExistsCheck::validCheck(std::shared_ptr<const ElementAccess> root) const {
this->exists_check(std::dynamic_pointer_cast<const GlobalElement>(root->element()), root);
}
QString FragmentExistsCheck::name() const {
return u8"情节引用有效性检查器";
}
QList<std::shared_ptr<FragmentGraphHelper>> FragmentGraphCheck::refers_cycle_check(
std::shared_ptr<FragmentGraphHelper> item, QList<std::shared_ptr<FragmentGraphHelper>> 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<std::shared_ptr<FragmentGraphHelper>>();
}
void FragmentGraphCheck::setElement(std::shared_ptr<FragmentGraphHelper> inst)
{
elements_store[inst->nodePeer()->signature()] = inst;
}
QList<std::shared_ptr<const FragmentGraphHelper>> FragmentGraphCheck::fragmentsSequence() const {
return fragments_sort_list;
}
std::shared_ptr<FragmentGraphHelper> FragmentGraphCheck::getElement(const QString& signature) const
{
return elements_store[signature];
}
QList<std::shared_ptr<FragmentGraphHelper>> FragmentGraphCheck::getHangoutNodes() {
QList<std::shared_ptr<FragmentGraphHelper>> 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<FragmentGraphHelper> inst) {
bool flag = false;
for (auto item : inst->nextList()) {
item->inDegree()--;
flag = true;
}
return flag;
}
void FragmentGraphCheck::validCheck(std::shared_ptr<const ElementAccess> root) const
{
const_cast<FragmentGraphCheck*>(this)->fragments_sort_list.clear();
std::function<QList<std::shared_ptr<const ElementAccess>>(std::shared_ptr<const ElementAccess>)> story_peak
= [&](std::shared_ptr<const ElementAccess> root)->QList<std::shared_ptr<const ElementAccess>> {
QList<std::shared_ptr<const ElementAccess>> 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<FragmentGraphCheck>(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::PointDefines: {
auto target_node = std::dynamic_pointer_cast<const FragmentDefine>(frag_primitive->element());
auto finst = std::make_shared<FragmentGraphHelper>(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::PointDefines:
case (int)NovelNode::PointRefers:
break;
default:
fragment_items.removeAt(idx);
idx--;
break;
}
}
auto get_name = [](std::shared_ptr<const ElementAccess> node)->QString {
switch (node->element()->typeMark()) {
case (int)NovelNode::PointDefines: {
auto def_node = std::dynamic_pointer_cast<const FragmentDefine>(node->element());
return def_node->signature();
}break;
case (int)NovelNode::PointRefers: {
auto ref_node = std::dynamic_pointer_cast<const PointRefers>(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"CheckError[0x0006]情节引用存在环形结构:\n";
for (auto n : cycle_link) {
error_msg += QString(u8"%1->").arg(n->nodePeer()->signature());
}
if (cycle_link.size())
throw new CheckException(error_msg);
}
}
for (auto& inst : values)
const_cast<FragmentGraphCheck*>(this)->fragments_sort_list.append(inst);
}
QString FragmentGraphCheck::name() const {
return u8"情节网络有效性检查器";
}
FragmentGraphHelper::FragmentGraphHelper(std::shared_ptr<const FragmentDefine> node) : node_peer(node) {}
std::shared_ptr<const FragmentDefine> FragmentGraphHelper::nodePeer() const
{
return this->node_peer;
}
void FragmentGraphHelper::appendNext(std::shared_ptr<FragmentGraphHelper> node) {
this->next_nodes.append(node);
}
QList<std::shared_ptr<FragmentGraphHelper>> FragmentGraphHelper::nextList() const
{
return next_nodes;
}
uint& FragmentGraphHelper::inDegree()
{
return this->indegree;
}
QList<std::shared_ptr<const ElementAccess>> StoryOrderCheck::valid_docs_peak(std::shared_ptr<const ElementAccess> pnode) const {
QList<std::shared_ptr<const ElementAccess>> values;
auto type_code = pnode->element()->typeMark();
switch ((NovelNode)type_code) {
case NovelNode::GlobalElement: {
auto children = pnode->children();
for (auto& cinst : children) {
values.append(valid_docs_peak(cinst));
}
}break;
case NovelNode::Document: {
auto storys_collection = pnode->children();
bool story_exists = false;
for (auto& syntax_elm : storys_collection) {
if (syntax_elm->element()->typeMark() == (int)NovelNode::StoryDefine) {
story_exists = true;
break;
}
}
if (story_exists) {
auto first_elm = storys_collection.at(0);
values.append(pnode);
if (first_elm->element()->typeMark() != (int)NovelNode::RankDeclaration)
throw new CheckException(QString(u8"CheckError[0x0007]具有故事节点的文档必须在第一行指定排序(%1").arg(pnode->element()->path()));
}
}break;
default:
break;
}
return values;
}
QString StoryOrderCheck::name() const
{
return u8"故事序列有效性检查器";
}
void StoryOrderCheck::validCheck(std::shared_ptr<const ElementAccess> root) const
{
const_cast<StoryOrderCheck*>(this)->sort_index = 1;
auto story_docs = valid_docs_peak(root);
std::sort(story_docs.begin(), story_docs.end(), [](std::shared_ptr<const ElementAccess> adoc, std::shared_ptr<const ElementAccess> bdoc) {
auto elm_xa = std::dynamic_pointer_cast<const RankDeclare>(adoc->children().first()->element());
auto elm_xb = std::dynamic_pointer_cast<const RankDeclare>(bdoc->children().first()->element());
return elm_xa->rankNumber() < elm_xb->rankNumber();
});
// page_rank valid
int page_rank = 0;
for (auto& item : story_docs) {
auto elm_xa = std::dynamic_pointer_cast<const RankDeclare>(item->children().first()->element());
if (page_rank >= elm_xa->rankNumber()) {
throw new CheckException(QString(u8"CheckError[0x0009]文档排序声明数字必须大于0不同文档的排序不能重复{%1}").arg(elm_xa->path()));
}
}
// 故事节点排序
auto story_node_sort = [](std::shared_ptr<const ElementAccess> doc_node, int start_index) -> int {
auto childs = doc_node->children();
for (auto& inst : childs) {
if (inst->element()->typeMark() == (int)NovelNode::StoryDefine) {
auto cast_inst = std::dynamic_pointer_cast<const StoryDefine>(inst->element());
std::const_pointer_cast<StoryDefine>(cast_inst)->setSort(start_index++);
}
}
return start_index;
};
int ranks_number = 1;
for (auto& story : story_docs)
ranks_number = story_node_sort(story, ranks_number);
}