QtNovelUI/libParse/StoryBoardDocumentParser.cpp

251 lines
8.8 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 "StoryBoardDocumentParser.h"
#include "StoryChainDocumentParser.h"
using namespace Lex;
using namespace Parse;
using namespace Syntax;
using namespace Syntax::Defines;
using namespace Parse::Result;
NodeStoryBoard::NodeStoryBoard(Result::DocCore *doc, const QString &name)
: Result::NamedNode(name, doc, NODE_STORYBOARD, nullptr){}
void NodeStoryBoard::setIndex(const QString &val)
{
index_store = val;
}
QString NodeStoryBoard::index() const
{
return this->index_store;
}
int NodeStoryBoard::indexValue(bool &valid) const
{
return index_store.toInt(&valid);
}
bool NodeStoryBoard::check(QList<ErrorMessage> &reasons) const
{
auto nodes = doc()->core()->queryStoryBoard(name()[0]);
if(nodes.size() > 1){
ErrorMessage ins(this);
ins.Reason = "重复定义大纲";
ins.Text = name()[0];
ins.FilePath = doc()->filePath();
ins.CodeRow = refered().first()->row();
ins.CodeCol = refered().first()->column();
reasons << ins;
}
bool is_valid = false;
indexValue(is_valid);
if(!is_valid){
ErrorMessage msg(this);
msg.CodeRow = refered().first()->row();
msg.CodeCol = refered().first()->column();
msg.FilePath = doc()->filePath();
msg.Text = index();
msg.Reason = "指定故事编排索引格式错误";
reasons << msg;
return false;
}
return nodes.size() == 1;
}
QString NodeStoryBoard::toString() const
{
bool ignore;
QString des = "#故事 "+name()[0] + " " + QString("%1").arg(indexValue(ignore)) +" {";
for(auto n : children())
des += "\n" + n->toString();
des += "\n}";
return des;
}
NodeStoryFragmentRefer::NodeStoryFragmentRefer(NodeStoryBoard * const parent_node, const QString &name)
: Result::NamedNode(name, parent_node->doc(), NODE_FRAGMENTREFERENCE, parent_node) { fragment_name = name; }
void NodeStoryFragmentRefer::setUnit(const QString &name){
this->unit_name_store = name;
}
QString NodeStoryFragmentRefer::unit() const{
return this->unit_name_store;
}
QString NodeStoryFragmentRefer::fragment() const
{
return this->fragment_name;
}
bool NodeStoryFragmentRefer::check(QList<ErrorMessage> &reasons) const
{
auto unitx = doc()->core()->queryStoryUnit(unit());
if(!unitx.size()){
ErrorMessage ins(this);
ins.Reason = "指定的单元不存在";
ins.Text = unit();
ins.FilePath = doc()->filePath();
ins.CodeRow = refered().first()->row();
ins.CodeCol = refered().first()->column();
reasons << ins;
return false;
}
auto fragment = doc()->core()->queryStoryFragment(unitx[0], name()[0]);
if(!fragment.size()){
ErrorMessage ins(this);
ins.Reason = "指定的情节不存在";
ins.Text = unit() + "" + name()[0];
ins.FilePath = doc()->filePath();
ins.CodeRow = refered().first()->row();
ins.CodeCol = refered().first()->column();
reasons << ins;
}
return fragment.size();
}
QString NodeStoryFragmentRefer::toString() const
{
QString des = QString(depth(), ' ') + "@情节 " + name()[0] + " " + unit() + " {";
for(auto &c : children())
des += "\n" + QString(depth(), ' ') + c->toString();
return des + "\n"+QString(depth(), ' ') + "}";
}
QList<QString> NodeStoryFragmentRefer::name() const
{
return QList<QString>() << fragment_name << unit_name_store;
}
NodeStoryBoardParser::NodeStoryBoardParser(Result::ParseCore *core)
:Syntax::XSyntaxBase("情节引用"), project_ins(core)
{
set_common_expression("::换行前缀", {Elm("{换行符}"),Elm("{换行符}", true)});
auto rule = addRule("进入作品解析", 0, [this](const QList<LexResult> &seqs, int cnt)->ParseResult
{
auto mbunit = seqs[cnt-1];
auto nmunit = seqs[cnt-2];
auto defunit = seqs[cnt-3];
auto node = new NodeStoryBoard(docRef(), nmunit.Text);
node->setIndex(mbunit.Text);
refocusNode(node);
auto word0 = new Words(node, docRef(), nmunit.Text, nmunit.StartRow, nmunit.StartCol);
auto word1 = new Words(node, docRef(), defunit.Text, defunit.StartRow, defunit.StartCol);
auto word2 = new Words(node, docRef(), mbunit.Text, mbunit.StartRow, mbunit.StartCol);
docRef()->append(word0);
docRef()->append(word1);
docRef()->append(word2);
return ParseResult::SelfManipulate;
});
rule->addExpression("基础故事定义", {Elm("{故事定义}"), Elm("{描述文本}1"), Elm("{描述文本}2", true)});
rule->addExpression("拓展故事定义", {Exp("::换行前缀"), Exp("基础故事定义", true)});
rule = addRule("进入成分解析", 1, [this](const QList<LexResult> &seqs, int cnt)->ParseResult {
auto node = currNode();
auto word = new Words(node, docRef(), seqs[cnt - 1].Text, seqs[cnt - 1].StartRow, seqs[cnt - 1].StartCol);
docRef()->append(word);
return ParseResult::EnterNext;
});
rule->addExpression("基础成分解析", { Elm("{左界限}", true) });
rule->addExpression("拓展成分解析", { Exp("::换行前缀"), Exp("基础成分解析", true) });
rule = addRule("跳出成分解析", 2, [this](const QList<LexResult> &seqs, int cnt)->ParseResult {
auto node = currNode();
auto word = new Words(node, docRef(), seqs[cnt - 1].Text, seqs[cnt - 1].StartRow, seqs[cnt - 1].StartCol);
docRef()->append(word);
return ParseResult::Completed;
});
rule->addExpression("基础跳出解析", { Elm("{右界限}", true) });
rule->addExpression("拓展跳出解析", { Exp("::换行前缀"), Exp("基础跳出解析", true) });
addChild(QList<Syntax::SyntaxParser*>()
<< new NodeStoryPureTextDesGroupParser(this)
<< new NodeStoryFragmentReferParser(this));
}
Result::ParseCore *NodeStoryBoardParser::project() const{return project_ins;}
StoryBoardDocumentParser::StoryBoardDocumentParser(Result::ParseCore *core)
{
appendTokensDefine({
{"{故事定义}","#故事"},
{"{情节引用}", "@情节"},
{"{描述文本}", "[^#@\\{\\}\\n]+"},
{"{左界限}","\\{"},
{"{右界限}","\\}"},
{"{换行符}","\\n"},
}, "{无法识别}");
auto ins = new NodeStoryBoardParser(core);
appendParser(ins);
}
NodeStoryFragmentReferParser::NodeStoryFragmentReferParser(XSyntaxBase *parent)
: Syntax::XSyntaxBase("情节引用")
{
set_common_expression("::换行前缀", {Elm("{换行符}"), Elm("{换行符}", true)});
auto rule = addRule("进入情节引用", 0, [this, parent](const QList<LexResult> &seqs, int cnt)->ParseResult
{
auto unit_u = seqs[cnt-1];
auto name_u = seqs[cnt-2];
auto def_u = seqs[cnt-3];
auto pnode = static_cast<NodeStoryBoard*>(parent->currNode());
auto tnode = new NodeStoryFragmentRefer(pnode, name_u.Text);
tnode->setUnit(unit_u.Text);
pnode->appendChild(tnode);
refocusNode(tnode);
auto word0 = new Words(tnode, docRef(), def_u.Text, def_u.StartRow, def_u.StartCol);
auto word1 = new Words(tnode, docRef(), name_u.Text, name_u.StartRow, name_u.StartCol);
auto word2 = new Words(tnode, docRef(), unit_u.Text, unit_u.StartRow, unit_u.StartCol);
docRef()->append(word0);
docRef()->append(word1);
docRef()->append(word2);
return ParseResult::SelfManipulate;
});
rule->addExpression("基础情节定义", {Elm("{情节引用}"), Elm("{描述文本}1"), Elm("{描述文本}2", true)});
rule->addExpression("拓展情节定义", {Exp("::换行前缀"), Exp("基础情节定义", true)});
rule = addRule("进入成分解析", 1, [this](const QList<LexResult> &seqs, int cnt)->ParseResult {
auto node = currNode();
auto word = new Words(node, docRef(), seqs[cnt - 1].Text, seqs[cnt - 1].StartRow, seqs[cnt - 1].StartCol);
docRef()->append(word);
return ParseResult::EnterNext;
});
rule->addExpression("基础成分解析", { Elm("{左界限}", true) });
rule->addExpression("拓展成分解析", { Exp("::换行前缀"), Exp("基础成分解析", true) });
rule = addRule("跳出成分解析", 2, [this](const QList<LexResult> &seqs, int cnt)->ParseResult {
auto node = currNode();
auto word = new Words(node, docRef(), seqs[cnt - 1].Text, seqs[cnt - 1].StartRow, seqs[cnt - 1].StartCol);
docRef()->append(word);
return ParseResult::Completed;
});
rule->addExpression("基础跳出解析", { Elm("{右界限}", true) });
rule->addExpression("拓展跳出解析", { Exp("::换行前缀"), Exp("基础跳出解析", true) });
addChild(QList<Syntax::SyntaxParser*>() << new NodeStoryPureTextDesGroupParser(this));
}