Compare commits
No commits in common. "master" and "dev" have entirely different histories.
|
@ -3,8 +3,3 @@
|
|||
x64/*
|
||||
*/bin/*
|
||||
*/obj/*
|
||||
.fake
|
||||
.DS_Store
|
||||
bin/*
|
||||
build/*
|
||||
out/*
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "macos-clang-x64",
|
||||
"includePath": [
|
||||
"/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mloc",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "macos-clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(ArgsParser CXX)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
|
||||
find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
add_library(ArgsParser SHARED
|
||||
argsparser.cpp
|
||||
)
|
||||
|
||||
message("ArgsParser::RUNTIME_PATH=${RUNTIME_PATH}")
|
||||
|
||||
set_target_properties(ArgsParser PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${RUNTIME_PATH}")
|
||||
set_target_properties(ArgsParser PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${RUNTIME_PATH}")
|
||||
set_target_properties(ArgsParser PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${RUNTIME_PATH}")
|
||||
set_target_properties(ArgsParser PROPERTIES OUTPUT_NAME "ArgsParser.${BUILD_TYPE_MARK}")
|
||||
|
||||
target_compile_definitions(ArgsParser PUBLIC ARGSPARSER_LIB)
|
||||
target_link_libraries(ArgsParser Qt5::Core)
|
|
@ -107,18 +107,10 @@ bool FloatOption::parse(const QList<QString> args) {
|
|||
MatchMode::MatchMode(int mode_code, const QString& mode)
|
||||
:_means_explain(mode), code_store(mode_code) { }
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
class inner_exception : public std::exception {
|
||||
private:
|
||||
QByteArray _message;
|
||||
|
||||
public:
|
||||
inner_exception(const QString &msg)
|
||||
:_message(msg.toUtf8()){}
|
||||
virtual const char* what() const noexcept{
|
||||
return _message.data();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @brief 获取模式代码
|
||||
* @return 模式代码
|
||||
*/
|
||||
|
||||
MatchMode& MatchMode::operator<<(std::shared_ptr<IArgvPack> unit) {
|
||||
if(unit->paramType() == ParamType::FloatParam){
|
||||
|
@ -127,7 +119,7 @@ MatchMode& MatchMode::operator<<(std::shared_ptr<IArgvPack> unit) {
|
|||
if (u_exist->paramType() == ParamType::FloatParam) {
|
||||
auto u_cast = std::dynamic_pointer_cast<__FloatArgvImpls>(u_exist);
|
||||
if (u_cast->bindKey() == unit_in->bindKey())
|
||||
throw new inner_exception("重复设置选项");
|
||||
throw new std::exception("重复设置选项");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="AstImport.fs" />
|
||||
<Compile Include="HtmlStruct.fs" />
|
||||
<Compile Include="FmtStruct.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -5,19 +5,11 @@ open System.Linq
|
|||
|
||||
module AstImport =
|
||||
/// 带有地址的对象
|
||||
type AstObject(bind: XmlElement) =
|
||||
type AstObject() =
|
||||
class
|
||||
member this.astXML() = bind
|
||||
member this.rows() =
|
||||
let xmle = bind.SelectSingleNode("tokens/token") :?> XmlElement
|
||||
int(xmle.GetAttribute "row")
|
||||
|
||||
abstract member address:unit -> string
|
||||
default this.address():string = "mem_" + string(this.GetHashCode ())
|
||||
|
||||
abstract member filePath:unit -> string
|
||||
default this.filePath():string = ""
|
||||
|
||||
abstract member members:unit -> AstObject list
|
||||
default this.members(): AstObject list = []
|
||||
end
|
||||
|
@ -42,7 +34,7 @@ open System.Linq
|
|||
/// TextWord
|
||||
type TextItem(bind: XmlElement) =
|
||||
class
|
||||
inherit AstObject(bind)
|
||||
inherit AstObject()
|
||||
member this.content():string =
|
||||
bind.GetAttribute "text"
|
||||
|
||||
|
@ -62,7 +54,7 @@ open System.Linq
|
|||
/// 引用节点
|
||||
type FragmentRef(bind: XmlElement, texts: TextItem list) =
|
||||
class
|
||||
inherit AstObject(bind)
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = FragmentRef(bind, [])
|
||||
|
||||
member this.sliceRef() =
|
||||
|
@ -97,7 +89,7 @@ open System.Linq
|
|||
/// 情节节点
|
||||
type FragmentSlice(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject(bind)
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = FragmentSlice(bind, [])
|
||||
|
||||
member this.name() =
|
||||
|
@ -111,8 +103,6 @@ open System.Linq
|
|||
override this.members(): AstObject list = objs
|
||||
override this.address (): string =
|
||||
bind.GetAttribute "address"
|
||||
override this.filePath (): string =
|
||||
bind.GetAttribute "file-path"
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): SliceChildType list =
|
||||
match child with
|
||||
|
@ -144,7 +134,7 @@ open System.Linq
|
|||
/// 故事节点
|
||||
type StoryDef(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject(bind)
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = StoryDef(bind, [])
|
||||
|
||||
member this.name() =
|
||||
|
@ -160,8 +150,6 @@ open System.Linq
|
|||
override this.members(): AstObject list = objs
|
||||
override this.address (): string =
|
||||
bind.GetAttribute "address"
|
||||
override this.filePath (): string =
|
||||
bind.GetAttribute "file-path"
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): StoryChildType list =
|
||||
match child with
|
||||
|
@ -193,7 +181,7 @@ open System.Linq
|
|||
/// 章节节点
|
||||
type ArticleDef(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject(bind)
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = ArticleDef(bind, [])
|
||||
|
||||
member this.name() =
|
||||
|
@ -238,7 +226,7 @@ open System.Linq
|
|||
/// 卷宗节点
|
||||
type VolumeDef(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject(bind)
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = VolumeDef(bind, [])
|
||||
|
||||
member this.name() =
|
||||
|
@ -256,8 +244,6 @@ open System.Linq
|
|||
override this.members(): AstObject list = objs
|
||||
override this.address (): string =
|
||||
bind.GetAttribute "address"
|
||||
override this.filePath (): string =
|
||||
bind.GetAttribute "file-path"
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): VolumeChildType list =
|
||||
match child with
|
||||
|
@ -284,26 +270,13 @@ open System.Linq
|
|||
|
||||
end
|
||||
|
||||
type RankDef(bind: XmlElement) =
|
||||
class
|
||||
inherit AstObject(bind)
|
||||
|
||||
member this.sort():int32 =
|
||||
int32(bind.GetAttribute "rank")
|
||||
override this.filePath (): string =
|
||||
bind.GetAttribute "doc-path"
|
||||
end
|
||||
|
||||
type ProgramChildType = |Volume of VolumeDef |Story of StoryDef |Rank of RankDef
|
||||
type ProgramChildType = |Volume of VolumeDef |Story of StoryDef
|
||||
/// 程序节点
|
||||
type Program(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject(bind)
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = Program(bind, [])
|
||||
|
||||
member this.dirPath() =
|
||||
bind.GetAttribute "dir_src"
|
||||
|
||||
member this.time() =
|
||||
bind.GetAttribute "time"
|
||||
member this.children() = objs
|
||||
|
@ -312,7 +285,6 @@ open System.Linq
|
|||
match it with
|
||||
|Story s -> s :> AstObject
|
||||
|Volume v -> v :> AstObject
|
||||
|Rank r -> r:> AstObject
|
||||
)
|
||||
Program(bind, objs @items)
|
||||
|
||||
|
@ -325,7 +297,6 @@ open System.Linq
|
|||
let d = match child.Name with
|
||||
| "volume" -> Some(Volume(VolumeDef.GenerateVolumeDef(child).Value))
|
||||
| "story" -> Some(Story(StoryDef.GenerateStoryDef(child).Value))
|
||||
| "rank" -> Some(Rank(RankDef(child :?> XmlElement)))
|
||||
| _ -> None
|
||||
match d with
|
||||
|Some value -> value::Program.GenerateFromChildSibling(child.NextSibling)
|
||||
|
@ -338,7 +309,6 @@ open System.Linq
|
|||
let conv data = match data with
|
||||
|Volume d -> d:>AstObject
|
||||
|Story d -> d :> AstObject
|
||||
|Rank d -> d:> AstObject
|
||||
Program(ast, mbrs |> List.map conv)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,226 +0,0 @@
|
|||
namespace FmtStruct
|
||||
|
||||
open System.IO
|
||||
open AstAccess
|
||||
open HtmlStruct
|
||||
|
||||
module FmtEntry =
|
||||
// rank反序列化
|
||||
let rank_fmt(node: AstImport.AstObject): string =
|
||||
let domx = node :?> AstImport.RankDef
|
||||
$"#排序 {domx.sort()}\n"
|
||||
|
||||
// 提取相同的类型元素
|
||||
let rec same_collect<'T when 'T:>Present.IDomUnit>
|
||||
(nodes: Present.IDomUnit list): Present.IDomUnit list * Present.IDomUnit list =
|
||||
|
||||
if nodes.Length = 0 then
|
||||
[], []
|
||||
else
|
||||
match nodes.Head with
|
||||
| :? 'T ->
|
||||
let tn, rest = same_collect<'T>(nodes.Tail)
|
||||
nodes.Head::tn, rest
|
||||
| _ -> [], nodes
|
||||
|
||||
|
||||
// 分类两种不同的类型元素
|
||||
let rec same_fold<'T1,'T2 when 'T1:> Present.IDomUnit and 'T2:> Present.IDomUnit>
|
||||
(nodes: Present.IDomUnit list): Present.IDomUnit list list =
|
||||
let first_list, rest_0 = same_collect<'T1>(nodes)
|
||||
let second_list, rest_1 = same_collect<'T2>(rest_0)
|
||||
|
||||
let list = match rest_1 with
|
||||
|[] -> first_list::[second_list]
|
||||
| _ -> first_list::[second_list]@same_fold<'T1, 'T2>(rest_1)
|
||||
list |> List.filter(fun slist -> slist.Length > 0)
|
||||
|
||||
// 字符串格式化
|
||||
let rec text_fmt(prefix:string)(line_prev: int32)(nodes: Content.TextContent list): string =
|
||||
match nodes with
|
||||
| [] -> ""
|
||||
| _ ->
|
||||
let obj_text = (nodes.Head :> Present.IDomUnit).object()
|
||||
let this_text = (obj_text :?> AstImport.TextItem).content()
|
||||
if obj_text.rows() = line_prev then
|
||||
" " + this_text + text_fmt prefix line_prev nodes.Tail
|
||||
else
|
||||
$"\n{prefix}" + this_text + text_fmt prefix (obj_text.rows()) nodes.Tail
|
||||
|
||||
|
||||
// 格式化Refer:Node
|
||||
let slice_ref_fmt(prefix:string)(node: Content.FragmentRefer): string =
|
||||
let objref = (node:> Present.IDomUnit).object():?> AstImport.FragmentRef
|
||||
|
||||
let childs = (node:> Present.IContainer).children()
|
||||
let text_childs, rest = same_collect<Content.TextContent>(childs)
|
||||
assert(rest.Length = 0)
|
||||
|
||||
let text_type_childs = text_childs|> List.map(fun n-> n:?> Content.TextContent)
|
||||
let sections = text_fmt (prefix+" ") (objref.rows()) text_type_childs
|
||||
|
||||
$"\n{prefix}{{@情节 {objref.storyRef()}&{objref.sliceRef()}{sections}}}"
|
||||
|
||||
|
||||
// 格式化Slice:Node
|
||||
let slice_def_fmt(prefix:string)(node: Content.FragmentSlice): string =
|
||||
let obj_def = (node:> Present.IDomUnit).object():?> AstImport.FragmentSlice
|
||||
|
||||
let childs = (node:> Present.IContainer).children()
|
||||
let same_groups_set = same_fold<Content.TextContent, Content.FragmentRefer>(childs)
|
||||
let contents = same_groups_set |> List.map(fun same_set ->
|
||||
if same_set.Length = 0 then
|
||||
""
|
||||
else
|
||||
match same_set.Head with
|
||||
| :? Content.FragmentRefer ->
|
||||
let strx = same_set|> List.map(fun n ->
|
||||
slice_ref_fmt (prefix+" ") (n:?> Content.FragmentRefer)
|
||||
)
|
||||
strx |> List.reduce(fun a b -> a + "\n" + b)
|
||||
| :? Content.TextContent ->
|
||||
let typed_set = same_set|>List.map(fun fn->fn:?>Content.TextContent)
|
||||
text_fmt (prefix+" ") (obj_def.rows()) typed_set
|
||||
| _ -> failwith "mismatch"
|
||||
)
|
||||
let subs = match contents with
|
||||
| [] -> ""
|
||||
| _ -> contents|> List.reduce(fun a b -> a + "\n" + b)
|
||||
$"\n{prefix}{{情节 {obj_def.name()}{subs}\n{prefix}}}"
|
||||
|
||||
|
||||
// 格式化Story:Node
|
||||
let story_def_fmt(node: Content.StoryDefine): string =
|
||||
let obj_story = (node:> Present.IDomUnit).object():?> AstImport.StoryDef
|
||||
|
||||
let childs = (node:> Present.IContainer).children()
|
||||
let same_groups_set = same_fold<Content.TextContent, Content.FragmentSlice>(childs)
|
||||
let contents = same_groups_set |> List.map(fun same_set ->
|
||||
if same_set.Length = 0 then
|
||||
""
|
||||
else
|
||||
match same_set.Head with
|
||||
| :? Content.FragmentSlice ->
|
||||
let strx = same_set|> List.map(fun n ->
|
||||
slice_def_fmt " " (n:?> Content.FragmentSlice)
|
||||
)
|
||||
strx |> List.reduce(fun a b -> a + "\n" + b)
|
||||
| :? Content.TextContent ->
|
||||
let typed_set = same_set|>List.map(fun fn->fn:?>Content.TextContent)
|
||||
text_fmt " " (obj_story.rows()) typed_set
|
||||
| _ -> failwith "mismatch-storydef"
|
||||
)
|
||||
let subs = match contents with
|
||||
| [] -> ""
|
||||
| _ -> contents|> List.reduce(fun a b -> a + "\n" + b)
|
||||
$"\n{{故事 {obj_story.name()}{subs}\n}}"
|
||||
|
||||
|
||||
// 格式化Article:Node
|
||||
let article_def_fmt(prefix:string)(node: Content.ArticleDefine): string =
|
||||
let obj_article = (node:> Present.IDomUnit).object():?> AstImport.ArticleDef
|
||||
|
||||
let childs = (node:> Present.IContainer).children()
|
||||
let same_groups_set = same_fold<Content.TextContent, Content.FragmentRefer>(childs)
|
||||
let contents = same_groups_set |> List.map(fun same_set ->
|
||||
if same_set.Length = 0 then
|
||||
""
|
||||
else
|
||||
match same_set.Head with
|
||||
| :? Content.FragmentRefer ->
|
||||
let strx = same_set|> List.map(fun n ->
|
||||
slice_ref_fmt (prefix+" ") (n:?> Content.FragmentRefer)
|
||||
)
|
||||
strx |> List.reduce(fun a b -> a + "\n" + b)
|
||||
| :? Content.TextContent ->
|
||||
let typed_set = same_set|>List.map(fun fn->fn:?>Content.TextContent)
|
||||
text_fmt (prefix+" ") (obj_article.rows()) typed_set
|
||||
| _ -> failwith "mismatch"
|
||||
)
|
||||
let subs = match contents with
|
||||
| [] -> ""
|
||||
| _ -> contents|> List.reduce(fun a b -> a + "\n" + b)
|
||||
$"\n{prefix}{{章节 {obj_article.name()}{subs}\n{prefix}}}"
|
||||
|
||||
|
||||
// 格式化Volume:Node
|
||||
let volume_def_fmt(node: Content.VolumeDefine): string =
|
||||
let obj_volume = (node:> Present.IDomUnit).object():?> AstImport.VolumeDef
|
||||
|
||||
let childs = (node:> Present.IContainer).children()
|
||||
let same_groups_set = same_fold<Content.TextContent, Content.ArticleDefine>(childs)
|
||||
let contents = same_groups_set |> List.map(fun same_set ->
|
||||
if same_set.Length = 0 then
|
||||
""
|
||||
else
|
||||
match same_set.Head with
|
||||
| :? Content.ArticleDefine ->
|
||||
let strx = same_set|> List.map(fun n ->
|
||||
article_def_fmt " " (n:?> Content.ArticleDefine)
|
||||
)
|
||||
strx |> List.reduce(fun a b -> a + "\n" + b)
|
||||
| :? Content.TextContent ->
|
||||
let typed_set = same_set |> List.map(fun fn->fn:?>Content.TextContent)
|
||||
text_fmt " " (obj_volume.rows()) typed_set
|
||||
| _ -> failwith "mismatch-volumedef"
|
||||
)
|
||||
let subs = match contents with
|
||||
| [] -> ""
|
||||
| _ -> contents|> List.reduce(fun a b -> a + "\n" + b)
|
||||
$"\n{{分卷 {obj_volume.name()}{subs}\n}}"
|
||||
|
||||
|
||||
let document_def_fmt(path:string)(nodes: Present.IDomUnit list): unit =
|
||||
let head_str, rest_nodes=match nodes.Head with
|
||||
| :? Content.RankDefine ->
|
||||
rank_fmt(nodes.Head.object()), nodes.Tail
|
||||
| _ -> "", nodes
|
||||
let sorted_nodes = rest_nodes|> List.sortBy (fun a->a.object().rows())
|
||||
let nodes_str = sorted_nodes|> List.map(fun nx ->
|
||||
match nx with
|
||||
| :? Content.VolumeDefine as vdef ->
|
||||
volume_def_fmt vdef
|
||||
| :? Content.StoryDefine as sdef->
|
||||
story_def_fmt sdef
|
||||
| _ -> failwith "error-doc-child"
|
||||
)
|
||||
let xcontent = head_str + (nodes_str|> List.reduce(fun a b -> a + "\n" + b))
|
||||
use wr = new StreamWriter(path,false)
|
||||
wr.Write(xcontent)
|
||||
printfn $"- {path}文档格式化完成。"
|
||||
|
||||
|
||||
|
||||
let program_def_fmt(dir:string)(nodes: Present.IDomUnit list): unit =
|
||||
let ranks = nodes|> List.filter(fun n -> n:?Content.RankDefine)
|
||||
|
||||
ranks|> List.iter(fun rankn ->
|
||||
let rank_o = rankn.object() :?> AstImport.RankDef
|
||||
let file_path = rank_o.filePath()
|
||||
|
||||
let nodes_within = nodes|> List.filter(fun n ->
|
||||
match n with
|
||||
| :? Content.StoryDefine ->
|
||||
n.object().filePath() = file_path
|
||||
| :? Content.VolumeDefine ->
|
||||
n.object().filePath() = file_path
|
||||
| _ -> false)
|
||||
document_def_fmt (Path.Combine(dir, file_path)) (rankn::nodes_within)
|
||||
)
|
||||
|
||||
let nodes_hangout = nodes|> List.filter(fun n ->
|
||||
let rank_paths = ranks|> List.map(fun n -> n.object().filePath())
|
||||
match n with
|
||||
| :? Content.VolumeDefine ->
|
||||
not(List.contains (n.object().filePath()) rank_paths)
|
||||
| _ -> false
|
||||
)
|
||||
|
||||
let path_hangout = nodes_hangout|> List.map(fun n -> n.object().filePath())
|
||||
|> List.distinct
|
||||
|
||||
path_hangout |> List.iter(fun path ->
|
||||
let nodes_within = nodes_hangout|> List.filter(fun n -> n.object().filePath() = path)
|
||||
document_def_fmt (Path.Combine(dir, path)) nodes_within
|
||||
)
|
||||
|
|
@ -269,13 +269,6 @@ open System.IO
|
|||
)
|
||||
VolumeDefine(defs, childs)
|
||||
|
||||
type RankDefine(defs: AstImport.RankDef) =
|
||||
class
|
||||
interface Present.IDomUnit with
|
||||
member this.name(): string =
|
||||
raise (System.NotImplementedException())
|
||||
member this.object(): AstImport.AstObject = defs
|
||||
end
|
||||
|
||||
type UnitGenerate(root: AstImport.AstObject) =
|
||||
class
|
||||
|
@ -303,8 +296,6 @@ open System.IO
|
|||
result_nodes@[(refs_depth, ArticleDefine(defs, childs))]
|
||||
| :? AstImport.VolumeDef as defs ->
|
||||
result_nodes@[(refs_depth, VolumeDefine(defs, childs))]
|
||||
| :? AstImport.RankDef as defs ->
|
||||
result_nodes@[refs_depth, RankDefine(defs)]
|
||||
| :? AstImport.Program -> result_nodes
|
||||
| _ -> failwith "match error"
|
||||
|
||||
|
@ -951,11 +942,11 @@ open System.IO
|
|||
|
||||
// 故事线声明
|
||||
let story_decl = story_lines|> List.map(fun story ->
|
||||
$"""node_{story.address()}[label="{story.name()}" shape="cds" tooltip="{story.filePath()}"]
|
||||
$"""node_{story.address()}[label="{story.name()}" shape="cds"]
|
||||
""")|> List.reduce(fun a b -> a + b)
|
||||
// 情节节点声明
|
||||
let points_decl = fragment_defs |> List.map(fun (_, node_def) ->
|
||||
$"""node_{node_def.address()}[label="{node_def.name()}" shape="rect" tooltip="{node_def.filePath()}"]
|
||||
$"""node_{node_def.address()}[label="{node_def.name()}" shape="rect"]
|
||||
""")|> List.reduce(fun a b -> a + b)
|
||||
// 所有的节点声明
|
||||
let nodes_decl = story_decl + points_decl
|
||||
|
@ -968,7 +959,7 @@ open System.IO
|
|||
let vhead = nexts.Head
|
||||
match vhead with
|
||||
| :? AstImport.FragmentSlice as slice ->
|
||||
$"""node_{node_curr.address()}->node_{vhead.address()}[label="{story_nm}" tooltip="{story_nm}" arrowhead="diamond"]
|
||||
$"""node_{node_curr.address()}->node_{vhead.address()}[label="{story_nm}"]
|
||||
"""::node_chains story_nm slice nexts.Tail
|
||||
| _ -> node_chains story_nm node_curr nexts.Tail
|
||||
let arrows_decl = story_lines|> List.map(fun story -> node_chains (story.name()) story (story.children()))
|
||||
|
@ -980,25 +971,21 @@ open System.IO
|
|||
$"{a.Value.name()}&{b.name()}", b.address())
|
||||
|
||||
// 故事线之间的节点连线
|
||||
let towards_prim = fragment_defs|> List.map(fun (_, defn) ->
|
||||
let towards_arrs = fragment_defs|> List.map(fun (_, defn) ->
|
||||
let node_refs = defn.children() |> List.filter(fun v -> v:? AstImport.FragmentRef)
|
||||
|> List.map(fun v -> v:?> AstImport.FragmentRef)
|
||||
|
||||
node_refs|> List.map(fun nref ->
|
||||
let node_name = $"""{nref.storyRef()}&{nref.sliceRef()}"""
|
||||
let _, address_target = node_map|> List.filter(fun (a,_)-> a = node_name)|> List.item 0
|
||||
$"""node_{defn.address()}->node_{address_target}[style="dotted" arrowhead="open"]
|
||||
$"""node_{defn.address()}->node_{address_target}[style="dotted"]
|
||||
"""
|
||||
)
|
||||
)
|
||||
|> List.reduce(fun al bl-> al @ bl)
|
||||
|> List.reduce(fun a b -> a + b)
|
||||
let all_arrows = arrows_decl + towards_arrs
|
||||
|
||||
let all_arrows =
|
||||
if towards_prim.IsEmpty then
|
||||
arrows_decl
|
||||
else
|
||||
let towards_arrs = towards_prim |> List.reduce(fun a b -> a + b)
|
||||
arrows_decl + towards_arrs
|
||||
|
||||
$"""digraph node_relates{{
|
||||
rankdir=LR
|
||||
|
@ -1091,9 +1078,7 @@ open System.IO
|
|||
|> List.map(fun v -> v, (v.children()|> List.filter(fun v-> v:? AstImport.FragmentRef))) // 获取文章节点和他的引用线
|
||||
|> List.filter(fun (_, al)-> al.Length > 0)
|
||||
|
||||
let refers_prim=
|
||||
if not rst.IsEmpty then
|
||||
rst |> List.map(fun (a, refsa) ->
|
||||
let refers = rst|> List.map(fun (a, refsa) ->
|
||||
refsa|> List.map(fun refn ->
|
||||
let refx = refn :?> AstImport.FragmentRef
|
||||
let target_name = $"""{refx.storyRef()}&{refx.sliceRef()}"""
|
||||
|
@ -1103,13 +1088,7 @@ open System.IO
|
|||
)
|
||||
)
|
||||
|> List.reduce (fun a b -> a @ b)
|
||||
else []
|
||||
|
||||
let refers =
|
||||
if refers_prim.IsEmpty then
|
||||
""
|
||||
else
|
||||
refers_prim |> List.reduce (fun a b -> a + b)
|
||||
|> List.reduce (fun a b -> a + b)
|
||||
|
||||
$"""graph{{ label="{gname}" {clusters_desc} {refers} }}"""
|
||||
|
||||
|
|
|
@ -2,13 +2,31 @@
|
|||
open HtmlStruct.Content
|
||||
open System.Xml
|
||||
open HtmlStruct.Assemble
|
||||
open HtmlStruct.Content
|
||||
open HtmlStruct.Present
|
||||
open System.IO
|
||||
open System.Text
|
||||
open System
|
||||
open System.Diagnostics
|
||||
open FmtStruct.FmtEntry
|
||||
|
||||
let html_generate (file_in:FileInfo) (dir_o:DirectoryInfo): unit =
|
||||
let args = System.Environment.GetCommandLineArgs()|> Array.toList
|
||||
|
||||
if args.Length = 2 && args.Item(1) = "--help" then
|
||||
System.Console.WriteLine("AstConv.exe -file xast文件路径 -odir 输出文件夹路径")
|
||||
exit 0
|
||||
|
||||
if args.Length <> 5 then
|
||||
failwith "程序调用参数错误:AstConv.exe -file xast文件路径 -odir 输出文件夹路径"
|
||||
|
||||
let file_in, dir_o = match args.Item(1), args.Item(3) with
|
||||
| "-file","-odir" ->
|
||||
if not(FileInfo(args.Item 2).Exists) then
|
||||
failwith "指定xast文件不存在"
|
||||
if not(DirectoryInfo(args.Item 4).Exists) then
|
||||
failwith "指定输出文件夹不存在"
|
||||
FileInfo(args.Item 2), DirectoryInfo(args.Item 4)
|
||||
| _ -> failwith "程序调用参数错误:AstConv.exe -file xast文件路径 -odir 输出文件夹路径"
|
||||
|
||||
let out_dir = Uri(dir_o.FullName)
|
||||
|
||||
let doc = XmlDocument()
|
||||
|
@ -59,53 +77,3 @@ let html_generate (file_in:FileInfo) (dir_o:DirectoryInfo): unit =
|
|||
stream2.Write(graph2_code)
|
||||
stream2.Flush()
|
||||
Process.Start("dot", $"""-Tsvg -o{Path.Combine(dir_o.FullName, "volume_display.svg")} {Path.Combine(dir_o.FullName, "volume_display.dot")}""") |> ignore
|
||||
|
||||
let source_format (file_in:FileInfo): unit =
|
||||
let doc = XmlDocument()
|
||||
doc.Load(file_in.FullName)
|
||||
|
||||
let prog = Program.GenerateFrom(doc)
|
||||
let entry = AstVisitEntry(prog)
|
||||
let visitor = UnitGenerate(prog)
|
||||
entry.visitWith(visitor) |> ignore
|
||||
|
||||
// 获取内容节点
|
||||
let nodes = visitor.contents()
|
||||
program_def_fmt (prog.dirPath()) nodes
|
||||
|
||||
|
||||
|
||||
let args = System.Environment.GetCommandLineArgs()|> Array.toList
|
||||
// 参数校验
|
||||
match args.Length with
|
||||
| 2 when args.Item(1) = "--help" ->
|
||||
printfn "AstConv.exe --file xast文件路径 --html 输出文件夹路径\n\t构建HTML透视文档。"
|
||||
printfn "AstConv.exe --file xast文件路径 --format\n\t格式化所有源文件。"
|
||||
exit 0
|
||||
|
||||
// 格式化
|
||||
| 4 when args.Item(1) = "--file" && args.Item(3) = "--format" ->
|
||||
if not(FileInfo(args.Item 2).Exists) then
|
||||
printfn "Arguments-Error:指定xast文件不存在"
|
||||
exit 0
|
||||
source_format(FileInfo(args.Item 2)) |> ignore
|
||||
|
||||
// html生成
|
||||
| 5 when args.Item(1) = "--file" && args.Item(3) = "--html" ->
|
||||
if not(FileInfo(args.Item 2).Exists) then
|
||||
printfn "Arguments-Error:指定xast文件不存在"
|
||||
exit 0
|
||||
if not(DirectoryInfo(args.Item 4).Exists) then
|
||||
printfn "Arguments-Error:指定输出文件夹不存在"
|
||||
exit 0
|
||||
|
||||
let xfile, xdir = FileInfo(args.Item 2), DirectoryInfo(args.Item 4)
|
||||
// 构建html页面
|
||||
html_generate xfile xdir
|
||||
exit 0
|
||||
|
||||
| _ ->
|
||||
printfn "命令调用格式错误:"
|
||||
printfn "AstConv.exe --file xast文件路径 --html 输出文件夹路径\n\t构建HTML透视文档。"
|
||||
printfn "AstConv.exe --file xast文件路径 --format\n\t格式化所有源文件。"
|
||||
exit 0
|
|
@ -2,7 +2,7 @@
|
|||
"profiles": {
|
||||
"AstConv": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "--file \"E:/storyline.xast\" --html \"E:/html\""
|
||||
"commandLineArgs": "-file \"E:/storyline.xast\" -odir \"E:/\""
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(WsNovelParser)
|
||||
|
||||
set(CMAKE_PREFIX_PATH "/Users/ws/Qt5.12.4/5.12.4/clang_64/lib/cmake")
|
||||
|
||||
# 准备开发环境 ======================================
|
||||
set(BUILD_TYPE_MARK "$<IF:$<CONFIG:Debug>,0,1>")
|
||||
set(SOLUTION_ROOT "${CMAKE_CURRENT_LIST_DIR}")
|
||||
set(RUNTIME_PATH "$<IF:$<CONFIG:Debug>,${CMAKE_CURRENT_LIST_DIR}/out,${CMAKE_CURRENT_LIST_DIR}/out>")
|
||||
|
||||
|
||||
# 配置开发环境 ======================================
|
||||
find_package(Qt5 COMPONENTS Core Xml REQUIRED)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
add_subdirectory(./ArgsParser)
|
|
@ -1,20 +0,0 @@
|
|||
// For more information see https://aka.ms/fsharp-console-apps
|
||||
|
||||
type MarkX() =
|
||||
class
|
||||
abstract member some:unit-> unit
|
||||
default this.some() =
|
||||
printfn "Hello World!"
|
||||
end
|
||||
|
||||
type SubMark() =
|
||||
class
|
||||
inherit MarkX()
|
||||
|
||||
override this.some (): unit =
|
||||
printfn "Substract"
|
||||
end
|
||||
|
||||
|
||||
let code = SubMark()
|
||||
code.some()
|
|
@ -1,12 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -40,8 +40,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CoreTest", "CoreTest\CoreTe
|
|||
EndProject
|
||||
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "AstConv", "AstConv\AstConv.fsproj", "{0C77216C-6484-4C94-BE06-D5D9FF18EA81}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TestProject", "TestProject\TestProject.fsproj", "{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -136,18 +134,6 @@ Global
|
|||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|x86.Build.0 = Release|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Release|x64.Build.0 = Release|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{08F9F7F7-CDB4-4644-92A3-99C41A77CD90}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -113,12 +113,12 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="astprint.cpp" />
|
||||
<ClCompile Include="htmlprint.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="novelparser.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="astprint.h" />
|
||||
<ClInclude Include="htmlprint.h" />
|
||||
<ClInclude Include="novelparser.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<ClCompile Include="novelparser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="astprint.cpp">
|
||||
<ClCompile Include="htmlprint.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<ClInclude Include="novelparser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="astprint.h">
|
||||
<ClInclude Include="htmlprint.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerWorkingDirectory>$(SolutionDir)$(Platform)\$(Configuration)\</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerCommandArguments>--path "E:\CustomNovels\科学+修仙+创造世界" --dest F:\novelout</LocalDebuggerCommandArguments>
|
||||
<LocalDebuggerCommandArguments>--path "D:/Projects/Cpp/WsNovelParser/x64/test_file/" --dest E:\</LocalDebuggerCommandArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerCommandArguments>--path "D:\Projects\Cpp\WsNovelParser\x64\test_file" --dest E:\</LocalDebuggerCommandArguments>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "astprint.h"
|
||||
#include "htmlprint.h"
|
||||
#include <QDir>
|
||||
#include <QDomElement>
|
||||
|
||||
|
@ -86,9 +86,6 @@ bool printer::AstGenerate::visit(std::shared_ptr<const ast_gen::ElementAccess> s
|
|||
|
||||
dom_slice.setAttribute("name", slice_node->name());
|
||||
dom_slice.setAttribute("address", (qulonglong) slice_node.get());
|
||||
dom_slice.setAttribute("file-path", src_root.relativeFilePath(slice_node->filePath()));
|
||||
|
||||
append_tokens(dom_slice, slice_node);
|
||||
}break;
|
||||
case NovelNode::TextSection:
|
||||
{
|
|
@ -14,7 +14,7 @@
|
|||
#include <argsparser.h>
|
||||
|
||||
#include "novelparser.h"
|
||||
#include "astprint.h"
|
||||
#include "htmlprint.h"
|
||||
|
||||
using namespace example_novel;
|
||||
using namespace std;
|
||||
|
|
|
@ -13,7 +13,6 @@ NovelParser::NovelParser() {
|
|||
checker_list << std::make_shared<FragmentExistsCheck>();
|
||||
checker_list << std::make_shared<StoryOrderCheck>();
|
||||
checker_list << std::make_shared<PointGraphCheck>();
|
||||
checker_list << std::make_shared<FragmentLayerCheck>();
|
||||
|
||||
analyzer_ref = std::make_shared<Analyzer>(checker_list);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ std::shared_ptr<const SyntaxElement> ElementsCache::getNamedNodeBy(int paramType
|
|||
return node_cache[mixed_key];
|
||||
}
|
||||
|
||||
void FragmentExistsCheck::nodes_regist(std::shared_ptr<ElementsCache> cache, std::shared_ptr<const ast_gen::ElementAccess> target) {
|
||||
void example_novel::FragmentExistsCheck::nodes_regist(std::shared_ptr<ElementsCache> cache, std::shared_ptr<const ast_gen::ElementAccess> target) {
|
||||
if (!target->element()->isAnonymous())
|
||||
cache->appendToCache(target->element());
|
||||
|
||||
|
@ -53,9 +53,8 @@ void FragmentExistsCheck::exists_check(std::shared_ptr<ElementsCache> root, std:
|
|||
}
|
||||
}
|
||||
|
||||
FragmentExistsCheck::FragmentExistsCheck()
|
||||
:_nodes_cache(std::make_shared<ElementsCache>()) {
|
||||
}
|
||||
example_novel::FragmentExistsCheck::FragmentExistsCheck()
|
||||
:_nodes_cache(std::make_shared<ElementsCache>()) { }
|
||||
|
||||
void FragmentExistsCheck::validCheck(std::shared_ptr<const ElementAccess> root) const {
|
||||
const_cast<FragmentExistsCheck*>(this)->nodes_regist(this->_nodes_cache, root);
|
||||
|
@ -201,13 +200,11 @@ void PointGraphCheck::validCheck(std::shared_ptr<const ElementAccess> root) cons
|
|||
// 获取绑定节点名称
|
||||
auto get_name = [](std::shared_ptr<const ElementAccess> node)->QString {
|
||||
switch (node->element()->typeMark()) {
|
||||
case (int) NovelNode::FragmentSlice:
|
||||
{
|
||||
case (int) NovelNode::FragmentSlice: {
|
||||
auto def_node = std::dynamic_pointer_cast<const FragmentSlice>(node->element());
|
||||
return def_node->signature();
|
||||
}break;
|
||||
case (int) NovelNode::FragmentRefers:
|
||||
{
|
||||
case (int) NovelNode::FragmentRefers: {
|
||||
auto ref_node = std::dynamic_pointer_cast<const FragmentRefers>(node->element());
|
||||
return ref_node->referSignature();
|
||||
}break;
|
||||
|
@ -275,11 +272,10 @@ void PointGraphCheck::validCheck(std::shared_ptr<const ElementAccess> root) cons
|
|||
}
|
||||
|
||||
QString PointGraphCheck::name() const {
|
||||
return "情节网络引用检查器";
|
||||
return "情节网络有效性检查器";
|
||||
}
|
||||
|
||||
PointGraphHelper::PointGraphHelper(std::shared_ptr<const FragmentSlice> node) : node_peer(node) {
|
||||
}
|
||||
PointGraphHelper::PointGraphHelper(std::shared_ptr<const FragmentSlice> node) : node_peer(node) { }
|
||||
|
||||
std::shared_ptr<const FragmentSlice> PointGraphHelper::nodePeer() const {
|
||||
return this->node_peer;
|
||||
|
@ -302,16 +298,14 @@ QList<std::shared_ptr<const ElementAccess>> StoryOrderCheck::valid_docs_peak(std
|
|||
auto type_code = pnode->element()->typeMark();
|
||||
|
||||
switch ((NovelNode) type_code) {
|
||||
case NovelNode::GlobalElement:
|
||||
{
|
||||
case NovelNode::GlobalElement: {
|
||||
auto children = pnode->children();
|
||||
for (auto& cinst : children) {
|
||||
values.append(valid_docs_peak(cinst));
|
||||
}
|
||||
}break;
|
||||
|
||||
case NovelNode::Document:
|
||||
{
|
||||
case NovelNode::Document: {
|
||||
auto elms_set = pnode->children();
|
||||
|
||||
decltype(elms_set) story_set;
|
||||
|
@ -377,162 +371,3 @@ void StoryOrderCheck::validCheck(std::shared_ptr<const ElementAccess> root) cons
|
|||
for (auto& story : story_docs)
|
||||
ranks_number = story_node_sort(story, ranks_number);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (list.size()) {
|
||||
for (auto nitr = ++list.begin(); nitr != list.end(); nitr++) {
|
||||
auto prev = *(nitr - 1);
|
||||
prev->appendNext(*nitr);
|
||||
}
|
||||
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());
|
||||
for (auto node_t : fragm->children()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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:
|
||||
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();
|
||||
auto story_nm = story->element()->signature();
|
||||
|
||||
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; });
|
||||
|
||||
if (real_elms.size())
|
||||
for (auto curr = ++real_elms.begin(); curr != real_elms.end(); ++curr) {
|
||||
auto prev_it = curr - 1;
|
||||
auto curr_it = curr;
|
||||
for (; curr_it != real_elms.end(); ++curr_it) {
|
||||
auto curr_sign = (*curr_it)->element()->signature();
|
||||
auto prev_sign = (*prev_it)->element()->signature();
|
||||
sibling_element_compair(story_nm, _node_set[prev_sign], _node_set[curr_sign]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FragmentLayerCheck::sibling_element_compair(const QString& story, std::shared_ptr<const FragmentNode> prev, std::shared_ptr<const FragmentNode> curr) {
|
||||
auto prev_childs_o = prev->referNodes();
|
||||
auto curr_childs_o = curr->referNodes();
|
||||
auto vpeak = [=](std::shared_ptr<const FragmentNode> ins) { return !ins->bind()->element()->signature().startsWith(story); };
|
||||
|
||||
decltype(prev_childs_o) prev_childs;
|
||||
std::copy_if(prev_childs_o.begin(), prev_childs_o.end(), std::back_inserter(prev_childs), vpeak);
|
||||
decltype(curr_childs_o) curr_childs;
|
||||
std::copy_if(curr_childs_o.begin(), curr_childs_o.end(), std::back_inserter(curr_childs), vpeak);
|
||||
|
||||
if (!curr_childs.size() || !prev_childs.size())
|
||||
return;
|
||||
|
||||
auto max_e0 = *std::max_element(prev_childs.begin(), prev_childs.end(),
|
||||
[](std::shared_ptr<const FragmentNode> a, std::shared_ptr<const FragmentNode> b) {
|
||||
return a->layerNumber() < b->layerNumber();
|
||||
});
|
||||
auto min_e1 = *std::min_element(curr_childs.begin(), curr_childs.end(),
|
||||
[](std::shared_ptr<const FragmentNode> a, std::shared_ptr<const FragmentNode> b) {
|
||||
return a->layerNumber() < b->layerNumber();
|
||||
});
|
||||
|
||||
if (curr_childs.size() && max_e0->layerNumber() > min_e1->layerNumber()) {
|
||||
throw new CheckException(QString("CheckError[0x0009]情节时间序错误!%1 && %2\n\t\t%3->%4@%5\n\t\t%6->%7@%8")
|
||||
.arg(prev->bind()->element()->signature()).arg(curr->bind()->element()->signature())
|
||||
.arg(prev->bind()->element()->signature(), max_e0->bind()->element()->signature(), QString("%1").arg(max_e0->layerNumber()))
|
||||
.arg(curr->bind()->element()->signature(), min_e1->bind()->element()->signature(), QString("%1").arg(min_e1->layerNumber())));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
FragmentNode::FragmentNode(std::shared_ptr<const ElementAccess> bind) :_src_fragm(bind) {
|
||||
}
|
||||
|
||||
std::shared_ptr<const ElementAccess> FragmentNode::bind() const {
|
||||
return this->_src_fragm;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -108,59 +108,4 @@ namespace example_novel {
|
|||
QString name() const override;
|
||||
void validCheck(std::shared_ptr<const ast_gen::ElementAccess> root) const override;
|
||||
};
|
||||
|
||||
class FragmentNode : public std::enable_shared_from_this<FragmentNode> {
|
||||
private:
|
||||
std::shared_ptr<const ast_gen::ElementAccess> _src_fragm = nullptr;
|
||||
QList<std::shared_ptr<FragmentNode>> _next_fragms;
|
||||
int _layer_number = -1;
|
||||
|
||||
public:
|
||||
FragmentNode(std::shared_ptr<const ast_gen::ElementAccess> bind);
|
||||
std::shared_ptr<const ast_gen::ElementAccess> bind() const;
|
||||
|
||||
void setLayer(int number);
|
||||
int layerNumber() const;
|
||||
|
||||
QList<std::shared_ptr<FragmentNode>> referNodes() const;
|
||||
void appendNext(std::shared_ptr<FragmentNode> ins);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 情节时间顺序校验
|
||||
*/
|
||||
class LIBPARSE_EXPORT FragmentLayerCheck : public lib_parse::CheckProvider {
|
||||
private:
|
||||
QHash<QString, std::shared_ptr<FragmentNode>> _node_set;
|
||||
QList<std::shared_ptr<FragmentNode>> _story_start;
|
||||
|
||||
/**
|
||||
* @brief 故事线转换
|
||||
*/
|
||||
std::shared_ptr<FragmentNode> _sets_fill(std::shared_ptr<const ast_gen::ElementAccess> node);
|
||||
/// <summary>
|
||||
/// 引用网络重构
|
||||
/// </summary>
|
||||
/// <param name="node">传入情节定义结点</param>
|
||||
void _refers_rebuild(std::shared_ptr<const FragmentNode> node);
|
||||
|
||||
/// <summary>
|
||||
/// 节点层级重排
|
||||
/// </summary>
|
||||
/// <param name="node">目标结点</param>
|
||||
/// <param name="curr">目标层级</param>
|
||||
void node_relayer(std::shared_ptr<FragmentNode> node, int curr = 0);
|
||||
/// <summary>
|
||||
/// 层级确认
|
||||
/// </summary>
|
||||
/// <param name="node">故事线</param>
|
||||
void layer_check(std::shared_ptr<const ast_gen::ElementAccess> node);
|
||||
void story_layer_check(std::shared_ptr<const ast_gen::ElementAccess> story);
|
||||
void sibling_element_compair(const QString& story, std::shared_ptr<const FragmentNode> prev, std::shared_ptr<const FragmentNode> curr);
|
||||
|
||||
public:
|
||||
// 通过 CheckProvider 继承
|
||||
QString name() const override;
|
||||
void validCheck(std::shared_ptr<const ast_gen::ElementAccess> root) const override;
|
||||
};
|
||||
} // namespace example_novel
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(libSyntax)
|
||||
|
||||
set(CMAKE_PREFIX_PATH "~/Qt5.12.4/5.12.4/clang_64/lib/cmake")
|
||||
|
||||
find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
add_library(libSyntax
|
||||
libsyntax.cpp
|
||||
ast_basic.cpp
|
||||
ast_gen.cpp
|
||||
ast_novel.cpp
|
||||
libtokens.cpp
|
||||
syntax_novel.cpp
|
||||
tokens_novel.cpp
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
target_link_libraries(libSyntax Qt5::Core)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(libWords)
|
||||
|
||||
set(CMAKE_PREFIX_PATH "~/Qt5.12.4/5.12.4/clang_64/lib/cmake")
|
||||
|
||||
find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
add_library(libWords libwords.cpp)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
target_link_libraries(libWords Qt5::Core)
|
187
语法进化路线.md
187
语法进化路线.md
|
@ -1,187 +0,0 @@
|
|||
# 语法进化路线
|
||||
|
||||
## v1 软件设计
|
||||
### 实现目标
|
||||
1. 构建UI编辑软件
|
||||
2. 故事线展示
|
||||
3. 悬空节点筛选
|
||||
4. 可用节点展示
|
||||
5. 基于数据库
|
||||
|
||||
## v2 软件设计
|
||||
### 语法实例
|
||||
```
|
||||
#大纲 作品名称
|
||||
作品描述
|
||||
|
||||
#分卷 分卷名称
|
||||
分卷描述
|
||||
#脉络 故事名称
|
||||
故事叙述
|
||||
#节点 节点名称
|
||||
节点叙述
|
||||
@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
|
||||
#概念 分类名称
|
||||
分类叙述
|
||||
#节点 种类名称
|
||||
种类描述
|
||||
```
|
||||
### 实现目标
|
||||
1. 基于QTextDocument和行编辑,基于GUI
|
||||
2. 行格式与语义绑定
|
||||
|
||||
|
||||
## v3 软件设计
|
||||
### 语法实例
|
||||
```
|
||||
#故事 1 故事名称{
|
||||
故事叙述
|
||||
#节点 节点名称{
|
||||
节点叙述
|
||||
}
|
||||
@节点 故事名称&节点名称{
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
|
||||
#分卷 分卷名称{
|
||||
分卷叙述
|
||||
#章节 章节名称{
|
||||
@节点 故事名称&节点名称{
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### 实现目标
|
||||
1. 手动展开ANY/SEQUENCE/REPEAT语法逻辑,构建语法分析类库
|
||||
2. 分析类库集成入软件部件,非独立软件
|
||||
|
||||
## v4 软件设计
|
||||
### 语法实例
|
||||
```
|
||||
{故事 1 故事名称
|
||||
故事叙述
|
||||
{节点 节点名称
|
||||
节点叙述
|
||||
}
|
||||
{@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
|
||||
{分卷 分卷名称
|
||||
分卷叙述
|
||||
{章节 章节名称
|
||||
章节叙述
|
||||
{@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### 实现目标
|
||||
1. 软件独立化
|
||||
1. 使用宏和ANY/SEQUENCE/REPEAT结构编织语法,构建语法分析前端
|
||||
|
||||
## v5 软件设计
|
||||
### 语法实例
|
||||
```
|
||||
#排序 1
|
||||
{故事 故事名称
|
||||
故事叙述
|
||||
{节点 节点名称
|
||||
节点叙述
|
||||
}
|
||||
{@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
|
||||
{分卷 分卷名称
|
||||
分卷叙述
|
||||
{章节 章节名称
|
||||
章节叙述
|
||||
{@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### 实现目标
|
||||
#### v5.01
|
||||
1. 简化语法
|
||||
2. 编译直出HTML
|
||||
#### v5.02
|
||||
1. 编译直出XAST
|
||||
2. 另外构建软件负责XAST->HTML
|
||||
#### v5.03
|
||||
1. 使用模板语法替代宏
|
||||
|
||||
## v6 软件设计
|
||||
### 语法实例
|
||||
```
|
||||
#排序 1
|
||||
{故事 故事名称
|
||||
故事叙述
|
||||
{剧情 剧情名称
|
||||
剧情叙述
|
||||
{节点 节点名称
|
||||
节点叙述
|
||||
}
|
||||
|
||||
{@节点 故事名称&剧情名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{分卷 分卷名称
|
||||
分卷叙述
|
||||
{章节 章节名称
|
||||
章节叙述
|
||||
{@节点 故事名称&剧情名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### 实现目标
|
||||
1. 改进XAST->HTML
|
||||
2. 改进图示格式
|
||||
|
||||
## v7 软件设计
|
||||
### 语法实例
|
||||
```
|
||||
#排序 1
|
||||
{故事 故事名称
|
||||
故事叙述
|
||||
{节点 节点名称
|
||||
节点叙述
|
||||
{@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
{@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{分卷 分卷名称
|
||||
分卷叙述
|
||||
{章节 章节名称
|
||||
章节叙述
|
||||
{@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
{@节点 故事名称&节点名称
|
||||
引用叙述
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### 实现目标
|
||||
1. 改进XAST->HTML
|
||||
2. 改进图示格式
|
Loading…
Reference in New Issue