WsParser_VS/libParse/parse_novel.cpp

532 lines
16 KiB
C++
Raw Normal View History

2024-03-17 07:58:28 +00:00
#include "parse_novel.h"
#include <ast_novel.h>
#include <iterator>
2024-06-15 01:18:33 +00:00
#include <QTime>
2024-03-17 07:58:28 +00:00
using namespace lib_parse;
2024-03-17 07:58:28 +00:00
using namespace example_novel;
using namespace ast_basic;
using namespace ast_gen;
using namespace lib_syntax;
using namespace example_novel;
2025-02-15 12:25:51 +00:00
void ElementsCache::clearCache() {
node_cache.clear();
}
std::shared_ptr<const SyntaxElement> ElementsCache::appendToCache(std::shared_ptr<const SyntaxElement> named_node) {
auto mixed_key = QString("%1<%2>").arg(named_node->signature()).arg(named_node->typeMark());
if (node_cache.contains(mixed_key))
2025-03-29 09:53:28 +00:00
throw new CheckException(QString("节点命名重复:%1").arg(mixed_key));
2025-02-15 12:25:51 +00:00
node_cache[mixed_key] = named_node;
return nullptr;
}
std::shared_ptr<const SyntaxElement> ElementsCache::getNamedNodeBy(int paramType, const QString& signature) const {
auto mixed_key = QString("%1<%2>").arg(signature).arg(paramType);
if (!node_cache.contains(mixed_key))
return nullptr;
return node_cache[mixed_key];
}
2025-05-16 17:23:29 +00:00
void FragmentExistsCheck::nodes_regist(std::shared_ptr<ElementsCache> cache, std::shared_ptr<const ast_gen::ElementAccess> target) {
2025-02-15 12:25:51 +00:00
if (!target->element()->isAnonymous())
cache->appendToCache(target->element());
for (auto item : target->children())
nodes_regist(cache, item);
}
void FragmentExistsCheck::exists_check(std::shared_ptr<ElementsCache> root, std::shared_ptr<const ElementAccess> target) const {
2025-03-29 09:53:28 +00:00
if (target->element()->typeMark() == (int) NovelNode::FragmentRefers) {
auto refer = std::dynamic_pointer_cast<const FragmentRefers>(target->element());
auto signature = refer->storyRefer() + "&" + refer->sliceRefer();
if (!root->getNamedNodeBy((int) NovelNode::FragmentSlice, signature))
2025-02-15 12:25:51 +00:00
throw new SyntaxException(QString("CheckError[0x0005]系统中不包含指定签名的节点:%1<type%2>{%3:(%4)}")
2025-03-29 09:53:28 +00:00
.arg(signature).arg((int) NovelNode::FragmentRefers).arg(refer->signature()).arg(refer->filePath()));
2024-03-17 07:58:28 +00:00
}
for (auto& xit : target->children()) {
exists_check(root, xit);
}
}
2025-05-16 17:23:29 +00:00
FragmentExistsCheck::FragmentExistsCheck()
:_nodes_cache(std::make_shared<ElementsCache>()) {
}
2025-02-15 15:47:42 +00:00
2024-06-19 14:45:55 +00:00
void FragmentExistsCheck::validCheck(std::shared_ptr<const ElementAccess> root) const {
2025-02-15 12:25:51 +00:00
const_cast<FragmentExistsCheck*>(this)->nodes_regist(this->_nodes_cache, root);
this->exists_check(this->_nodes_cache, root);
2024-03-17 07:58:28 +00:00
}
2024-06-15 08:09:19 +00:00
QString FragmentExistsCheck::name() const {
2025-02-15 12:25:51 +00:00
return "情节引用有效性检查器";
2024-03-17 07:58:28 +00:00
}
2025-02-15 15:47:42 +00:00
QList<std::shared_ptr<PointGraphHelper>> PointGraphCheck::refers_cycle_check(
2025-02-15 12:25:51 +00:00
std::shared_ptr<PointGraphHelper> item, QList<std::shared_ptr<PointGraphHelper>> prevs) const {
2024-06-15 08:52:16 +00:00
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;
}
}
2025-02-15 12:25:51 +00:00
return QList<std::shared_ptr<PointGraphHelper>>();
2024-06-15 08:52:16 +00:00
}
2025-02-15 15:47:42 +00:00
void PointGraphCheck::setElement(std::shared_ptr<PointGraphHelper> inst) {
2024-06-15 08:09:19 +00:00
elements_store[inst->nodePeer()->signature()] = inst;
2024-03-17 07:58:28 +00:00
}
2025-02-15 15:47:42 +00:00
QList<std::shared_ptr<const PointGraphHelper>> PointGraphCheck::pointsSequence() const {
2024-06-20 14:13:06 +00:00
return fragments_sort_list;
}
2025-02-15 15:47:42 +00:00
std::shared_ptr<PointGraphHelper> PointGraphCheck::getElement(const QString& signature) const {
2024-06-15 08:09:19 +00:00
return elements_store[signature];
2024-03-17 07:58:28 +00:00
}
2025-02-15 15:47:42 +00:00
QList<std::shared_ptr<PointGraphHelper>> PointGraphCheck::getHangoutNodes() {
2025-02-15 12:25:51 +00:00
QList<std::shared_ptr<PointGraphHelper>> values;
2024-03-17 07:58:28 +00:00
2024-06-15 08:09:19 +00:00
for (auto node_item : elements_store) {
if (!node_item->inDegree())
values.append(node_item);
2024-03-17 07:58:28 +00:00
}
2024-06-15 08:09:19 +00:00
for (auto inst : values) {
auto name = inst->nodePeer()->signature();
elements_store.remove(name);
2024-03-17 07:58:28 +00:00
}
2024-06-15 08:09:19 +00:00
return values;
2024-03-17 07:58:28 +00:00
}
2025-02-15 15:47:42 +00:00
bool PointGraphCheck::nodeDismantle(std::shared_ptr<PointGraphHelper> inst) {
2024-06-15 08:09:19 +00:00
bool flag = false;
2024-03-17 07:58:28 +00:00
2024-06-15 08:09:19 +00:00
for (auto item : inst->nextList()) {
item->inDegree()--;
flag = true;
2024-03-17 07:58:28 +00:00
}
2024-06-15 08:09:19 +00:00
return flag;
2024-05-04 15:34:21 +00:00
}
2025-02-15 15:47:42 +00:00
void PointGraphCheck::validCheck(std::shared_ptr<const ElementAccess> root) const {
const_cast<PointGraphCheck*>(this)->fragments_sort_list.clear();
auto self = std::const_pointer_cast<PointGraphCheck>(this->shared_from_this());
2024-06-20 14:13:06 +00:00
2025-03-28 14:52:33 +00:00
// 提取所有故事线
2024-06-19 14:45:55 +00:00
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;
2024-03-17 07:58:28 +00:00
2025-02-15 12:25:51 +00:00
auto type_mark = (NovelNode) root->element()->typeMark();
2024-06-15 08:09:19 +00:00
if (type_mark == NovelNode::StoryDefine) {
return_temp << root;
2024-03-17 07:58:28 +00:00
}
2024-06-15 08:09:19 +00:00
for (auto child : root->children()) {
return_temp.append(story_peak(child));
2024-03-17 07:58:28 +00:00
}
2024-06-15 08:09:19 +00:00
return return_temp;
2025-02-15 12:25:51 +00:00
};
2024-03-17 07:58:28 +00:00
2025-03-28 14:52:33 +00:00
// 提取所有节点定义
std::function<QList<std::shared_ptr<const ElementAccess>>(std::shared_ptr<const ElementAccess>)> points_extract
= [&](std::shared_ptr<const ElementAccess> story) {
2025-02-15 12:25:51 +00:00
QList<std::shared_ptr<const ElementAccess>> return_temp;
2024-03-17 07:58:28 +00:00
2025-02-15 12:25:51 +00:00
auto story_children = story->children();
2025-03-28 14:52:33 +00:00
for (auto ins : story_children) {
switch (ins->element()->typeMark()) {
2025-03-29 09:53:28 +00:00
case (int) NovelNode::FragmentSlice:
2025-03-28 14:52:33 +00:00
return_temp << ins;
break;
default:
return_temp << points_extract(ins);
break;
}
}
return return_temp;
};
// 提取节点内包含的引用节点
std::function<QList<std::shared_ptr<const ElementAccess>>(std::shared_ptr<const ElementAccess>)> refers_within
= [&](std::shared_ptr<const ElementAccess> defs) {
QList<std::shared_ptr<const ElementAccess>> return_temp;
2025-02-15 12:25:51 +00:00
2025-03-28 14:52:33 +00:00
auto x_children = defs->children();
for (auto ins : x_children) {
switch (ins->element()->typeMark()) {
2025-03-29 09:53:28 +00:00
case (int) NovelNode::FragmentRefers:
2025-03-28 14:52:33 +00:00
return_temp << ins;
break;
default:
return_temp << refers_within(ins);
break;
}
}
2025-02-15 12:25:51 +00:00
return return_temp;
};
2025-02-15 15:47:42 +00:00
2025-02-15 12:25:51 +00:00
// 获取所有故事线
auto all_story = story_peak(root);
// 注册图节点
for (auto story : all_story) {
auto point_items = points_extract(story);
// 构建情节节点列表
for (auto point_primitive : point_items) {
2025-03-29 09:53:28 +00:00
auto target_node = std::dynamic_pointer_cast<const FragmentSlice>(point_primitive->element());
2025-03-28 14:52:33 +00:00
auto finst = std::make_shared<PointGraphHelper>(target_node);
self->setElement(finst);
2024-06-15 08:09:19 +00:00
}
}
2024-03-17 07:58:28 +00:00
2025-03-28 14:52:33 +00:00
// 获取绑定节点名称
auto get_name = [](std::shared_ptr<const ElementAccess> node)->QString {
switch (node->element()->typeMark()) {
2025-05-16 17:23:29 +00:00
case (int) NovelNode::FragmentSlice:
{
2025-03-29 09:53:28 +00:00
auto def_node = std::dynamic_pointer_cast<const FragmentSlice>(node->element());
2025-03-28 14:52:33 +00:00
return def_node->signature();
}break;
2025-05-16 17:23:29 +00:00
case (int) NovelNode::FragmentRefers:
{
2025-03-29 09:53:28 +00:00
auto ref_node = std::dynamic_pointer_cast<const FragmentRefers>(node->element());
2025-03-28 14:52:33 +00:00
return ref_node->referSignature();
}break;
}
return QString();
};
2025-02-15 12:25:51 +00:00
// 构建图连接
2024-06-15 08:09:19 +00:00
for (auto story : all_story) {
2025-02-15 12:25:51 +00:00
// 过滤获取情节节点
2025-03-28 14:52:33 +00:00
auto point_items = points_extract(story);
2024-06-15 08:09:19 +00:00
2025-03-28 14:52:33 +00:00
// 构建完整图结构:串联定义节点的顺序
2025-02-15 12:25:51 +00:00
for (auto fidx = 1; fidx < point_items.size(); fidx++) {
auto tail_name = get_name(point_items[fidx - 1]);
auto head_name = get_name(point_items[fidx]);
2024-06-15 08:09:19 +00:00
auto tail_helper = getElement(tail_name);
auto head_helper = getElement(head_name);
tail_helper->appendNext(head_helper);
head_helper->inDegree()++;
2024-03-17 07:58:28 +00:00
}
2025-03-28 14:52:33 +00:00
// 构建完整图结构:串联引用节点的顺序
2025-05-16 17:23:29 +00:00
for (auto point : point_items) {
2025-03-28 14:52:33 +00:00
auto first_name = get_name(point);
auto first_helper = getElement(first_name);
auto refers_nodes = refers_within(point);
for (auto refer : refers_nodes) {
auto second_name = get_name(refer);
auto second_helper = getElement(second_name);
first_helper->appendNext(second_helper);
second_helper->inDegree()++;
}
}
2024-03-17 07:58:28 +00:00
}
2025-02-15 12:25:51 +00:00
// 获取拓扑排序序列
2024-06-15 08:09:19 +00:00
auto values = self->getHangoutNodes();
for (auto idx = 0; idx < values.size(); ++idx) {
auto target = values[idx];
2024-05-04 15:34:21 +00:00
2024-06-15 08:09:19 +00:00
self->nodeDismantle(target);
auto x_values = self->getHangoutNodes();
values.append(x_values);
2024-05-04 15:34:21 +00:00
}
2024-03-17 07:58:28 +00:00
2025-02-15 12:25:51 +00:00
// 理论上不应该有残余
2024-06-15 08:52:16 +00:00
if (elements_store.size()) {
for (auto node : elements_store.values()) {
auto cycle_link = refers_cycle_check(node);
2025-02-15 12:25:51 +00:00
QString error_msg = "CheckError[0x0006]情节引用存在环形结构:\n";
2024-06-15 08:52:16 +00:00
for (auto n : cycle_link) {
2025-02-15 12:25:51 +00:00
error_msg += QString("%1->").arg(n->nodePeer()->signature());
2024-06-15 08:52:16 +00:00
}
if (cycle_link.size())
throw new CheckException(error_msg);
2024-06-15 08:52:16 +00:00
}
}
2024-06-20 14:13:06 +00:00
for (auto& inst : values)
2025-02-15 15:47:42 +00:00
const_cast<PointGraphCheck*>(this)->fragments_sort_list.append(inst);
2024-03-17 07:58:28 +00:00
}
2025-02-15 15:47:42 +00:00
QString PointGraphCheck::name() const {
2025-05-16 17:23:29 +00:00
return "情节网络引用检查器";
2024-03-17 07:58:28 +00:00
}
PointGraphHelper::PointGraphHelper(std::shared_ptr<const FragmentSlice> node) : node_peer(node) {
}
2024-03-17 07:58:28 +00:00
2025-03-29 09:53:28 +00:00
std::shared_ptr<const FragmentSlice> PointGraphHelper::nodePeer() const {
2024-06-15 08:09:19 +00:00
return this->node_peer;
2024-03-17 07:58:28 +00:00
}
2025-02-15 12:25:51 +00:00
void PointGraphHelper::appendNext(std::shared_ptr<PointGraphHelper> node) {
2024-06-15 08:09:19 +00:00
this->next_nodes.append(node);
2024-03-17 07:58:28 +00:00
}
2025-02-15 12:25:51 +00:00
QList<std::shared_ptr<PointGraphHelper>> PointGraphHelper::nextList() const {
2024-06-15 08:09:19 +00:00
return next_nodes;
2024-03-17 07:58:28 +00:00
}
2025-02-15 12:25:51 +00:00
uint& PointGraphHelper::inDegree() {
2024-06-15 08:09:19 +00:00
return this->indegree;
2024-03-17 07:58:28 +00:00
}
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();
2025-02-15 12:25:51 +00:00
switch ((NovelNode) type_code) {
2025-05-16 17:23:29 +00:00
case NovelNode::GlobalElement:
{
2025-02-15 12:25:51 +00:00
auto children = pnode->children();
for (auto& cinst : children) {
values.append(valid_docs_peak(cinst));
}
}break;
2025-05-16 17:23:29 +00:00
case NovelNode::Document:
{
2025-02-15 12:25:51 +00:00
auto elms_set = pnode->children();
2025-02-15 12:25:51 +00:00
decltype(elms_set) story_set;
std::copy_if(elms_set.begin(), elms_set.end(),
std::back_inserter(story_set), [](std::shared_ptr<const ElementAccess> e) {
return e->element()->typeMark() == (int) NovelNode::StoryDefine;
});
2024-06-20 14:13:06 +00:00
2025-02-15 12:25:51 +00:00
if (story_set.size()) {
values.append(pnode);
2024-06-20 14:13:06 +00:00
2025-02-15 12:25:51 +00:00
auto first_elm = elms_set.at(0);
if (first_elm->element()->typeMark() != (int) NovelNode::RankDeclaration)
throw new CheckException(QString("CheckError[0x0007]具有故事节点的文档必须在第一行指定排序(%1").arg(pnode->element()->path()));
}
}break;
2025-02-15 12:25:51 +00:00
default:
break;
}
return values;
}
2025-02-15 12:25:51 +00:00
QString StoryOrderCheck::name() const {
return "故事序列有效性检查器";
}
2025-02-15 12:25:51 +00:00
void StoryOrderCheck::validCheck(std::shared_ptr<const ElementAccess> root) const {
const_cast<StoryOrderCheck*>(this)->sort_index = 1;
auto story_docs = valid_docs_peak(root);
2025-02-15 12:25:51 +00:00
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());
2025-02-15 12:25:51 +00:00
if (page_rank >= elm_xa->rankNumber())
throw new CheckException(QString("CheckError[0x0009]文档排序声明数字必须大于0不同文档的排序不能重复{%1}").arg(elm_xa->path()));
page_rank = elm_xa->rankNumber();
}
2025-02-15 12:25:51 +00:00
// 故事节点排序
2024-06-20 14:13:06 +00:00
auto story_node_sort = [](std::shared_ptr<const ElementAccess> doc_node, int start_index) -> int {
auto childs = doc_node->children();
2024-06-20 14:13:06 +00:00
for (auto& inst : childs) {
2025-02-15 12:25:51 +00:00
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;
2025-02-15 12:25:51 +00:00
};
int ranks_number = 1;
2024-06-20 14:13:06 +00:00
for (auto& story : story_docs)
ranks_number = story_node_sort(story, ranks_number);
}
2025-05-16 17:23:29 +00:00
std::shared_ptr<FragmentNode> FragmentLayerCheck::_sets_fill(std::shared_ptr<const ElementAccess> node) {
switch ((NovelNode) node->element()->typeMark()) {
case NovelNode::FragmentSlice:
{
auto wins = std::make_shared<FragmentNode>(node);
this->_node_set[node->element()->signature()] = wins;
return wins;
}break;
case NovelNode::StoryDefine:
{
QList<std::shared_ptr<FragmentNode>> list;
for (auto nis : node->children()) {
auto ptr = _sets_fill(nis);
if (ptr) list << ptr;
}
for (auto node = ++list.begin(); node != list.end(); ++node) {
auto prev = *(node - 1);
auto curr = *node;
prev->appendNext(curr);
}
if (list.size())
this->_story_start << list.first();
}
break;
default:
for (auto nis : node->children())
_sets_fill(nis);
break;
}
return nullptr;
}
void FragmentLayerCheck::_refers_rebuild(std::shared_ptr<const FragmentNode> node) {
auto fragm = std::static_pointer_cast<const FragmentSlice>(node->bind()->element());
2025-05-16 17:23:29 +00:00
for (auto node_t : fragm->children()) {
2025-05-17 11:05:07 +00:00
auto refn = std::dynamic_pointer_cast<const FragmentRefers>(node_t);
if(refn){
auto target_node = _node_set[refn->referSignature()];
std::const_pointer_cast<FragmentNode>(node)->appendNext(target_node);
}
2025-05-16 17:23:29 +00:00
}
}
void FragmentLayerCheck::node_relayer(std::shared_ptr<FragmentNode> node, int curr_num) {
if (node->layerNumber() < curr_num) {
node->setLayer(curr_num);
for (auto nis : node->referNodes())
node_relayer(nis, curr_num + 1);
}
}
/// <summary>
/// 层级确认
/// </summary>
/// <param name="node">故事线</param>
void FragmentLayerCheck::layer_check(std::shared_ptr<const ElementAccess> node) {
switch ((NovelNode) node->element()->typeMark()) {
case NovelNode::StoryDefine:
story_layer_check(node);
break;
default:
2025-05-17 11:05:07 +00:00
for(auto ins : node->children())
layer_check(ins);
break;
}
}
void FragmentLayerCheck::story_layer_check(std::shared_ptr<const ast_gen::ElementAccess> story) {
auto fragms_list = story->children();
2025-05-17 11:05:07 +00:00
decltype(fragms_list) real_elms;
std::copy_if(fragms_list.begin(), fragms_list.end(), std::back_inserter(real_elms),
[](std::shared_ptr<const ast_gen::ElementAccess> ins) { return ins->element()->typeMark() == (int) NovelNode::FragmentSlice; });
for (auto curr = ++real_elms.begin(); curr != real_elms.end(); ++curr) {
auto prev = curr - 1;
auto curr_sign = (*curr)->element()->signature();
auto prev_sign = (*prev)->element()->signature();
sibling_element_compair(_node_set[prev_sign], _node_set[curr_sign]);
}
}
void FragmentLayerCheck::sibling_element_compair(std::shared_ptr<const FragmentNode> prev, std::shared_ptr<const FragmentNode> curr) {
auto prev_childs = prev->referNodes();
auto curr_childs = curr->referNodes();
QList<int> prev_layers;
std::transform(prev_childs.begin(), prev_childs.end(), std::back_inserter(prev_layers),
[](std::shared_ptr<const FragmentNode> ins) { return ins->layerNumber(); });
QList<int> next_layers;
std::transform(curr_childs.begin(), curr_childs.end(), std::back_inserter(next_layers),
[](std::shared_ptr<const FragmentNode> ins) { return ins->layerNumber(); });
auto min0 = *std::min_element(prev_layers.begin(), prev_layers.end());
auto max1 = *std::max_element(next_layers.begin(), next_layers.end());
2025-05-17 11:05:07 +00:00
if (next_layers.size() && min0 > max1) {
decltype(prev_childs) tempx;
std::copy_if(curr_childs.begin(), curr_childs.end(), std::back_inserter(tempx),
[=](std::shared_ptr<const FragmentNode> ins) { return ins->layerNumber() >= min0; });
QStringList names;
std::transform(tempx.begin(), tempx.end(), std::back_inserter(names),
[=](std::shared_ptr<const FragmentNode> ins) { return ins->bind()->element()->signature(); });
throw new CheckException(QString("CheckError[0x0009]情节时间序错误!%1->%2\n\t\t%3->{%4}")
.arg(prev->bind()->element()->signature()).arg(curr->bind()->element()->signature())
.arg(curr->bind()->element()->signature(), names.join(",")));
}
}
2025-05-16 17:23:29 +00:00
QString FragmentLayerCheck::name() const {
return "情节时间层级校验器";
}
void FragmentLayerCheck::validCheck(std::shared_ptr<const ast_gen::ElementAccess> root) const {
auto chk = const_cast<FragmentLayerCheck*>(this);
chk->_sets_fill(root);
for (auto node : chk->_node_set)
chk->_refers_rebuild(node);
for (auto node : chk->_story_start)
chk->node_relayer(node);
chk->layer_check(root);
2025-05-16 17:23:29 +00:00
}
FragmentNode::FragmentNode(std::shared_ptr<const ElementAccess> bind) :_src_fragm(bind) {
2025-05-16 17:23:29 +00:00
}
std::shared_ptr<const ElementAccess> FragmentNode::bind() const {
return this->_src_fragm;
2025-05-16 17:23:29 +00:00
}
void FragmentNode::setLayer(int number) {
this->_layer_number = number;
}
int FragmentNode::layerNumber() const {
return this->_layer_number;
}
QList<std::shared_ptr<FragmentNode>> FragmentNode::referNodes() const {
return _next_fragms;
}
void FragmentNode::appendNext(std::shared_ptr<FragmentNode> ins) {
this->_next_fragms << ins;
}