update
This commit is contained in:
parent
74ce31b072
commit
872f874d22
|
@ -1,3 +1,5 @@
|
|||
*/x64/*
|
||||
.vs/*
|
||||
x64/*
|
||||
*/bin/*
|
||||
*/obj/*
|
|
@ -132,7 +132,7 @@ int MatchMode::modeCode() const {
|
|||
return code_store;
|
||||
}
|
||||
|
||||
QString MatchMode::usageString() const {
|
||||
QString MatchMode::usagestring() const {
|
||||
QString usage_string;
|
||||
for (auto& item : args_mode)
|
||||
usage_string += item->placeHolder() + " ";
|
||||
|
@ -140,7 +140,7 @@ QString MatchMode::usageString() const {
|
|||
return usage_string;
|
||||
}
|
||||
|
||||
QString MatchMode::explanString() const {
|
||||
QString MatchMode::explanstring() const {
|
||||
QStringList sections;
|
||||
sections << " " + _means_explain;
|
||||
sections << QString(" Switch:");
|
||||
|
@ -235,8 +235,8 @@ std::shared_ptr<IArgvPack> MatchMode::getUnitViaInitIndex(int pos) {
|
|||
QString ArgsParser::helperDoc() const {
|
||||
QString help_string;
|
||||
for (auto& mode : this->match_modes) {
|
||||
help_string += "Usage:" + mode->usageString() + "\n";
|
||||
help_string += mode->explanString() + "\n\n";
|
||||
help_string += "Usage:" + mode->usagestring() + "\n";
|
||||
help_string += mode->explanstring() + "\n\n";
|
||||
}
|
||||
return help_string;
|
||||
}
|
||||
|
|
|
@ -162,14 +162,14 @@ namespace args_parse {
|
|||
*
|
||||
* \return
|
||||
*/
|
||||
QString usageString() const;
|
||||
QString usagestring() const;
|
||||
|
||||
/**
|
||||
* 返回模式解析字符串.
|
||||
*
|
||||
* \return
|
||||
*/
|
||||
QString explanString() const;
|
||||
QString explanstring() const;
|
||||
|
||||
/**
|
||||
* 添加参数解析单元.
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="AstImport.fs" />
|
||||
<Compile Include="HtmlStruct.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,366 @@
|
|||
namespace AstAccess
|
||||
|
||||
open System.Xml
|
||||
open System.Linq
|
||||
|
||||
module AstImport =
|
||||
/// 带有地址的对象
|
||||
type AstObject() =
|
||||
class
|
||||
member this.address() = string(this.GetHashCode ())
|
||||
|
||||
abstract member members:unit -> AstObject list
|
||||
default this.members(): AstObject list = []
|
||||
end
|
||||
|
||||
let rec branch_map_conv (pnode: AstObject, childs: AstObject list) =
|
||||
match childs with
|
||||
| [] -> []
|
||||
| _ ->
|
||||
let head = childs.Head
|
||||
(head.address(), (head, pnode))::branch_map_conv(pnode, childs.Tail)@branch_map_conv(head, head.members())
|
||||
|
||||
let rec depth_seek(branchs: (string*(AstObject*AstObject))list, node: AstObject): int =
|
||||
let prev_nodes = branchs |> List.filter(fun (key, _) -> key.Equals(node.address()))
|
||||
match prev_nodes.Length with
|
||||
| 0 -> 0
|
||||
| _ ->
|
||||
let (_, (_, parent_node)) = prev_nodes.Head
|
||||
depth_seek(branchs, parent_node) + 1
|
||||
|
||||
/// TextWord
|
||||
type TextItem(bind: XmlElement) =
|
||||
class
|
||||
inherit AstObject()
|
||||
member this.content():string =
|
||||
bind.GetAttribute "text"
|
||||
|
||||
member this.row():int =
|
||||
let tokens_node = bind.ChildNodes.Cast<XmlNode>().Where(
|
||||
fun node -> node.Name.Equals "tokens").ElementAt(0)
|
||||
let token_bind = tokens_node.ChildNodes.Cast<XmlElement>().ElementAt(0)
|
||||
int(token_bind.GetAttribute "row")
|
||||
|
||||
static member GenerateText(text_opt: XmlNode): Option<TextItem> =
|
||||
match text_opt with
|
||||
| :? XmlElement as obj_t when obj_t.Name.Equals "text-section" ->
|
||||
Some(TextItem(obj_t))
|
||||
| _ -> None
|
||||
end
|
||||
|
||||
/// 引用节点
|
||||
type PointRef(bind: XmlElement, texts: TextItem list) =
|
||||
class
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = PointRef(bind, [])
|
||||
|
||||
member this.pointRef() =
|
||||
bind.GetAttribute "point"
|
||||
member this.sliceRef() =
|
||||
bind.GetAttribute "slice"
|
||||
member this.storyRef() =
|
||||
bind.GetAttribute "story"
|
||||
member this.appendChild(objs: TextItem list) =
|
||||
PointRef(bind, texts@objs)
|
||||
member this.children() =
|
||||
texts
|
||||
|
||||
override this.members(): AstObject list =
|
||||
texts |> List.map (fun it->it :> AstObject)
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): TextItem list =
|
||||
match child with
|
||||
| null -> []
|
||||
| _ ->
|
||||
match TextItem.GenerateText(child) with
|
||||
| Some text -> text::PointRef.GenerateFromChildSibling(child.NextSibling)
|
||||
| None -> PointRef.GenerateFromChildSibling(child.NextSibling)
|
||||
|
||||
static member GeneratePointRef(ref_opt: XmlNode): Option<PointRef> =
|
||||
match ref_opt with
|
||||
| :? XmlElement as refo when refo.Name.Equals "refer" ->
|
||||
let text_objects = PointRef.GenerateFromChildSibling(refo.FirstChild)
|
||||
Some(PointRef(refo, text_objects))
|
||||
| _ -> None
|
||||
end
|
||||
|
||||
/// 定义节点
|
||||
type PointDef(bind: XmlElement, texts: TextItem list) =
|
||||
class
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = PointDef(bind, [])
|
||||
|
||||
member this.name() =
|
||||
bind.GetAttribute "name"
|
||||
member this.appendChild(t: TextItem) =
|
||||
PointDef(bind, texts@[t])
|
||||
member this.children() =
|
||||
texts
|
||||
|
||||
override this.members(): AstObject list =
|
||||
texts |> List.map (fun it->it :> AstObject)
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): TextItem list =
|
||||
match child with
|
||||
| null -> []
|
||||
| _ ->
|
||||
match TextItem.GenerateText(child) with
|
||||
| Some text -> text::PointDef.GenerateFromChildSibling(child.NextSibling)
|
||||
| None -> PointDef.GenerateFromChildSibling(child.NextSibling)
|
||||
|
||||
static member GeneratePointDef(def_opt: XmlNode) : Option<PointDef> =
|
||||
match def_opt with
|
||||
| :? XmlElement as defo when defo.Name.Equals "point" ->
|
||||
let text_objs = PointDef.GenerateFromChildSibling(defo.FirstChild)
|
||||
Some(PointDef(defo, text_objs))
|
||||
| _ -> None
|
||||
|
||||
end
|
||||
|
||||
type SliceChildType = |Text of TextItem |Define of PointDef |Refer of PointRef
|
||||
/// 情节节点
|
||||
type SliceDef(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = SliceDef(bind, [])
|
||||
|
||||
member this.name() =
|
||||
bind.GetAttribute "name"
|
||||
member this.appendChild(o: SliceChildType) =
|
||||
match o with
|
||||
| Text t -> SliceDef(bind, objs@[t])
|
||||
| Define d -> SliceDef(bind, objs@[d])
|
||||
| Refer r -> SliceDef(bind, objs@[r])
|
||||
member this.children() = objs
|
||||
|
||||
override this.members(): AstObject list = objs
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): SliceChildType list =
|
||||
match child with
|
||||
| null -> []
|
||||
| _ ->
|
||||
let h = match child.Name with
|
||||
| "text-section" -> Some(Text(TextItem.GenerateText(child).Value))
|
||||
| "refer" -> Some(Refer(PointRef.GeneratePointRef(child).Value))
|
||||
| "point" -> Some(Define(PointDef.GeneratePointDef(child).Value))
|
||||
| _ -> None
|
||||
|
||||
match h with
|
||||
| Some value -> value::SliceDef.GenerateFromChildSibling(child.NextSibling)
|
||||
| _ -> SliceDef.GenerateFromChildSibling(child.NextSibling)
|
||||
|
||||
static member GenerateSliceDef(slice_opt: XmlNode): Option<SliceDef> =
|
||||
match slice_opt with
|
||||
| :? XmlElement as slice when slice.Name.Equals "slice" ->
|
||||
let mbrs = SliceDef.GenerateFromChildSibling(slice.FirstChild)
|
||||
let objs = mbrs |> List.map (
|
||||
fun o-> match o with
|
||||
|Define defs -> defs :> AstObject
|
||||
|Refer refs -> refs :> AstObject
|
||||
|Text text -> text :> AstObject
|
||||
)
|
||||
Some(SliceDef(slice, objs))
|
||||
| _ -> None
|
||||
end
|
||||
|
||||
type StoryChildType = |Text of TextItem |Slice of SliceDef
|
||||
/// 故事节点
|
||||
type StoryDef(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = StoryDef(bind, [])
|
||||
|
||||
member this.name() =
|
||||
bind.GetAttribute "name"
|
||||
member this.sort() =
|
||||
int(bind.GetAttribute "sort")
|
||||
member this.appendChild(o: StoryChildType) =
|
||||
match o with
|
||||
|Text t -> StoryDef(bind, objs@[t])
|
||||
|Slice s -> StoryDef(bind, objs@[s])
|
||||
member this.children() = objs
|
||||
|
||||
override this.members(): AstObject list = objs
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): StoryChildType list =
|
||||
match child with
|
||||
| null -> []
|
||||
| _ ->
|
||||
let h = match child.Name with
|
||||
| "text-section" -> Some(Text(TextItem.GenerateText(child).Value))
|
||||
| "slice" -> Some(Slice(SliceDef.GenerateSliceDef(child).Value))
|
||||
| _->None
|
||||
match h with
|
||||
| Some value -> value::StoryDef.GenerateFromChildSibling(child.NextSibling)
|
||||
| _ -> StoryDef.GenerateFromChildSibling(child.NextSibling)
|
||||
|
||||
static member GenerateStoryDef(story_opt: XmlNode): Option<StoryDef> =
|
||||
match story_opt with
|
||||
| :? XmlElement as story when story.Name.Equals "story" ->
|
||||
let children = StoryDef.GenerateFromChildSibling(story.FirstChild)
|
||||
let objs = children |> List.map (
|
||||
fun x ->
|
||||
match x with
|
||||
|Text valx -> valx :> AstObject
|
||||
|Slice valx -> valx :> AstObject
|
||||
)
|
||||
Some(StoryDef(story, objs))
|
||||
| _ -> None
|
||||
end
|
||||
|
||||
type ArticleChildType = |Text of TextItem |Refer of PointRef
|
||||
/// 章节节点
|
||||
type ArticleDef(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = ArticleDef(bind, [])
|
||||
|
||||
member this.name() =
|
||||
bind.GetAttribute "name"
|
||||
member this.children() = objs
|
||||
member this.appendChild(o: ArticleChildType list) =
|
||||
let conv item = match item with
|
||||
|Text t -> t :> AstObject
|
||||
|Refer r -> r :> AstObject
|
||||
|
||||
let items = o |> List.map conv
|
||||
ArticleDef(bind, objs@items)
|
||||
|
||||
override this.members(): AstObject list = objs
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): ArticleChildType list =
|
||||
match child with
|
||||
| null -> []
|
||||
| _ ->
|
||||
let data = match child.Name with
|
||||
| "text-section" -> Some(Text(TextItem.GenerateText(child).Value))
|
||||
| "refer" -> Some(Refer(PointRef.GeneratePointRef(child).Value))
|
||||
| _ -> None
|
||||
match data with
|
||||
| Some value -> value::ArticleDef.GenerateFromChildSibling(child.NextSibling)
|
||||
| None -> ArticleDef.GenerateFromChildSibling(child.NextSibling)
|
||||
|
||||
static member GenerateArticleDef(article_opt: XmlNode): Option<ArticleDef> =
|
||||
match article_opt with
|
||||
| :? XmlElement as article when article.Name.Equals "article" ->
|
||||
let mbrs = ArticleDef.GenerateFromChildSibling(article.FirstChild)
|
||||
let conv it = match it with
|
||||
|Text v -> v :> AstObject
|
||||
|Refer v -> v:> AstObject
|
||||
Some(ArticleDef(article, mbrs |> List.map conv))
|
||||
| _ -> None
|
||||
end
|
||||
|
||||
type VolumeChildType = |Text of TextItem |Article of ArticleDef
|
||||
/// 卷宗节点
|
||||
type VolumeDef(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = VolumeDef(bind, [])
|
||||
|
||||
member this.name() =
|
||||
bind.GetAttribute "name"
|
||||
member this.children() = objs
|
||||
member this.appendChild(o: VolumeChildType list) =
|
||||
let items = o |> List.map (
|
||||
fun it->
|
||||
match it with
|
||||
|Text t -> t :> AstObject
|
||||
|Article a -> a :> AstObject
|
||||
)
|
||||
VolumeDef(bind, objs@items)
|
||||
|
||||
override this.members(): AstObject list = objs
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): VolumeChildType list =
|
||||
match child with
|
||||
| null -> []
|
||||
| _ ->
|
||||
let data = match child.Name with
|
||||
| "text-section" -> Some(Text(TextItem.GenerateText(child).Value))
|
||||
| "article" -> Some(Article(ArticleDef.GenerateArticleDef(child).Value))
|
||||
| _ -> None
|
||||
match data with
|
||||
| Some value -> value::VolumeDef.GenerateFromChildSibling(child.NextSibling)
|
||||
| None -> VolumeDef.GenerateFromChildSibling(child.NextSibling)
|
||||
|
||||
static member GenerateVolumeDef(vol_opt: XmlNode): Option<VolumeDef> =
|
||||
match vol_opt with
|
||||
| :? XmlElement as volume when volume.Name.Equals "volume" ->
|
||||
let mbrs = VolumeDef.GenerateFromChildSibling(volume.FirstChild)
|
||||
let conv data = match data with
|
||||
|Text d -> d :> AstObject
|
||||
|Article d -> d:> AstObject
|
||||
Some(VolumeDef(volume, mbrs |> List.map conv))
|
||||
| _ -> None
|
||||
|
||||
|
||||
end
|
||||
|
||||
type ProgramChildType = |Volume of VolumeDef |Story of StoryDef
|
||||
/// 程序节点
|
||||
type Program(bind: XmlElement, objs: AstObject list) =
|
||||
class
|
||||
inherit AstObject()
|
||||
new(bind: XmlElement) = Program(bind, [])
|
||||
|
||||
member this.time() =
|
||||
bind.GetAttribute "time"
|
||||
member this.children() = objs
|
||||
member this.appendChild(o: ProgramChildType list) =
|
||||
let items = o |> List.map (fun it->
|
||||
match it with
|
||||
|Story s -> s :> AstObject
|
||||
|Volume v -> v :> AstObject
|
||||
)
|
||||
Program(bind, objs @items)
|
||||
|
||||
override this.members(): AstObject list = objs
|
||||
|
||||
static member GenerateFromChildSibling(child: XmlNode): ProgramChildType list =
|
||||
match child with
|
||||
| null -> []
|
||||
| _ ->
|
||||
let d = match child.Name with
|
||||
| "volume" -> Some(Volume(VolumeDef.GenerateVolumeDef(child).Value))
|
||||
| "story" -> Some(Story(StoryDef.GenerateStoryDef(child).Value))
|
||||
| _ -> None
|
||||
match d with
|
||||
|Some value -> value::Program.GenerateFromChildSibling(child.NextSibling)
|
||||
|None -> Program.GenerateFromChildSibling(child.NextSibling)
|
||||
|
||||
static member GenerateFrom(doc: XmlDocument) =
|
||||
let ast = doc.DocumentElement
|
||||
|
||||
let mbrs = Program.GenerateFromChildSibling(ast.FirstChild)
|
||||
let conv data = match data with
|
||||
|Volume d -> d:>AstObject
|
||||
|Story d -> d :> AstObject
|
||||
Program(ast, mbrs |> List.map conv)
|
||||
end
|
||||
|
||||
|
||||
type AstVisitor =
|
||||
interface
|
||||
abstract member visit:AstObject -> bool
|
||||
end
|
||||
|
||||
type AstVisitEntry(root: AstObject) =
|
||||
class
|
||||
/// 1:node
|
||||
/// 2: node
|
||||
/// 2: node
|
||||
/// 3: node
|
||||
/// 4: node
|
||||
/// ......
|
||||
member private this.visit_internal(nodes: AstObject list, visitor: AstVisitor): bool =
|
||||
match nodes.Length with
|
||||
| 0 -> true
|
||||
| _ ->
|
||||
this.visit_internal(nodes.Head.members(), visitor) && visitor.visit(nodes.Head) && this.visit_internal(nodes.Tail, visitor)
|
||||
|
||||
|
||||
member this.visitWith(visitor: AstVisitor): bool =
|
||||
this.visit_internal([root], visitor)
|
||||
|
||||
end
|
|
@ -0,0 +1,266 @@
|
|||
namespace HtmlStruct
|
||||
|
||||
open AstAccess
|
||||
open System.Xml
|
||||
open System
|
||||
|
||||
module Present =
|
||||
/// 可访问元素
|
||||
type Access(hrefs: string) =
|
||||
class
|
||||
member this.accessLink(): string =
|
||||
hrefs
|
||||
end
|
||||
|
||||
/// 回退访问元素
|
||||
type Backward(hrefs: string) =
|
||||
class
|
||||
member this.backwardLink(): string =
|
||||
hrefs
|
||||
end
|
||||
|
||||
/// 内容元素:分卷、章节、引用节点、故事线、情节、定义节点、引用节点
|
||||
type IDomUnit =
|
||||
interface
|
||||
abstract member name:unit -> string
|
||||
abstract member getHtml:XmlElement -> XmlElement
|
||||
end
|
||||
|
||||
/// 容器节点:分卷、章节、故事线、情节
|
||||
type IContainer =
|
||||
interface
|
||||
abstract member append:List<IDomUnit> -> IContainer
|
||||
end
|
||||
|
||||
/// 访问页面:概括页面、卷宗页面、故事线页面、节点汇总 =================================================
|
||||
type VolumePage(page_hrefs: string, volume: IDomUnit, childs: List<IDomUnit>) =
|
||||
class
|
||||
inherit Access(page_hrefs)
|
||||
new(page_hrefs, volume) = VolumePage(page_hrefs, volume, [])
|
||||
|
||||
interface IDomUnit with
|
||||
member this.name():string =
|
||||
volume.name()
|
||||
member this.getHtml(p: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface IContainer with
|
||||
member this.append(childs: List<IDomUnit>): IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
|
||||
type StoryPage(page_hrefs: string, story: IDomUnit, childs: List<IDomUnit>) =
|
||||
class
|
||||
inherit Access(page_hrefs)
|
||||
new(page_hrefs, story) = StoryPage(page_hrefs, story, [])
|
||||
|
||||
interface IDomUnit with
|
||||
member this.name():string =
|
||||
story.name()
|
||||
member this.getHtml(p: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface IContainer with
|
||||
member this.append(childs: List<IDomUnit>): IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
|
||||
type PointPage(page_hrefs: string, point: IDomUnit, refer_list: List<IDomUnit>) =
|
||||
class
|
||||
inherit Access(page_hrefs)
|
||||
new(page_hrefs, point) = PointPage(page_hrefs, point, [])
|
||||
|
||||
interface IDomUnit with
|
||||
member this.name():string =
|
||||
point.name()
|
||||
member this.getHtml(p: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface IContainer with
|
||||
member this.append(childs: List<IDomUnit>): IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
|
||||
|
||||
/// 内容节点 =========================================================================================
|
||||
module Content =
|
||||
type TextContent(word: AstImport.TextItem) =
|
||||
class
|
||||
interface Present.IDomUnit with
|
||||
member this.name(): string = ""
|
||||
member this.getHtml(pnode: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
|
||||
|
||||
type PointRefer(refs: AstImport.PointRef, items: List<Present.IDomUnit>) =
|
||||
class
|
||||
let ref_signature = $"@{refs.storyRef()}&{refs.sliceRef()}&{refs.pointRef()}"
|
||||
let lines = refs.children() |> List.map (fun x->x.content())
|
||||
|
||||
interface Present.IDomUnit with
|
||||
member this.name(): string =
|
||||
ref_signature
|
||||
member this.getHtml(pnode: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface Present.IContainer with
|
||||
member this.append(childs: List<Present.IDomUnit>): Present.IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
let refer_assemble (refn: AstImport.PointRef) : PointRefer =
|
||||
let texts = refn.children() |> List.map (fun dom -> TextContent(dom) :> Present.IDomUnit)
|
||||
PointRefer(refn, texts)
|
||||
|
||||
|
||||
type PointDefine(defs: AstImport.PointDef, items: List<Present.IDomUnit>) =
|
||||
class
|
||||
let lines = defs.children() |> List.map (fun x->x.content())
|
||||
|
||||
interface Present.IDomUnit with
|
||||
member this.name(): string =
|
||||
defs.name()
|
||||
member this.getHtml(pnode: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface Present.IContainer with
|
||||
member this.append(childs: List<Present.IDomUnit>): Present.IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
let point_assemble (defs: AstImport.PointDef) : PointDefine =
|
||||
let texts = defs.children() |> List.map (fun dom -> TextContent(dom) :> Present.IDomUnit)
|
||||
PointDefine(defs, texts)
|
||||
|
||||
|
||||
type SliceDefine(defs: AstImport.SliceDef, items: List<Present.IDomUnit>) =
|
||||
class
|
||||
interface Present.IDomUnit with
|
||||
member this.name(): string =
|
||||
defs.name()
|
||||
member this.getHtml(pnode: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface Present.IContainer with
|
||||
member this.append(childs: List<Present.IDomUnit>): Present.IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
let slice_assemble (defs: AstImport.SliceDef) : SliceDefine =
|
||||
let childs = defs.children()
|
||||
|> List.map<AstImport.AstObject,Present.IDomUnit>(fun data ->
|
||||
match data with
|
||||
| :? AstImport.PointRef as refs -> refer_assemble(refs)
|
||||
| :? AstImport.PointDef as defs -> point_assemble(defs)
|
||||
| :? AstImport.TextItem as text -> TextContent(text)
|
||||
| _ -> raise (System.NotImplementedException())
|
||||
)
|
||||
SliceDefine(defs, childs)
|
||||
|
||||
|
||||
type StoryDefine(defs: AstImport.StoryDef, childs: List<Present.IDomUnit>) =
|
||||
class
|
||||
interface Present.IDomUnit with
|
||||
member this.name(): string =
|
||||
defs.name()
|
||||
member this.getHtml(pnode: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface Present.IContainer with
|
||||
member this.append(childs: List<Present.IDomUnit>): Present.IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
let story_assemble (defs: AstImport.StoryDef): StoryDefine =
|
||||
let childs = defs.children()
|
||||
|> List.map<AstImport.AstObject, Present.IDomUnit>(fun data ->
|
||||
match data with
|
||||
| :? AstImport.SliceDef as defs -> slice_assemble(defs)
|
||||
| :? AstImport.TextItem as text -> TextContent(text)
|
||||
| _ -> raise (System.NotImplementedException())
|
||||
)
|
||||
StoryDefine(defs, childs)
|
||||
|
||||
|
||||
type ArticleDefine(defs: AstImport.ArticleDef, childs: List<Present.IDomUnit>) =
|
||||
class
|
||||
interface Present.IDomUnit with
|
||||
member this.name(): string =
|
||||
defs.name()
|
||||
member this.getHtml(pnode: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface Present.IContainer with
|
||||
member this.append(childs: List<Present.IDomUnit>): Present.IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
let article_assemble (defs: AstImport.ArticleDef) : ArticleDefine =
|
||||
let childs = defs.children()
|
||||
|> List.map<AstImport.AstObject, Present.IDomUnit>(fun data ->
|
||||
match data with
|
||||
| :? AstImport.TextItem as text -> TextContent(text)
|
||||
| :? AstImport.PointRef as refs -> refer_assemble(refs)
|
||||
| _ -> raise (System.NotImplementedException())
|
||||
)
|
||||
ArticleDefine(defs, childs)
|
||||
|
||||
|
||||
type VolumeDefine(defs: AstImport.VolumeDef, childs: List<Present.IDomUnit>) =
|
||||
class
|
||||
interface Present.IDomUnit with
|
||||
member this.name(): string =
|
||||
defs.name()
|
||||
member this.getHtml(pnode: XmlElement): XmlElement =
|
||||
raise (System.NotImplementedException())
|
||||
|
||||
interface Present.IContainer with
|
||||
member this.append(childs: List<Present.IDomUnit>): Present.IContainer =
|
||||
raise (System.NotImplementedException())
|
||||
end
|
||||
let volume_assemble (defs: AstImport.VolumeDef): VolumeDefine =
|
||||
let childs = defs.children()
|
||||
|> List.map<AstImport.AstObject, Present.IDomUnit>(fun data ->
|
||||
match data with
|
||||
| :? AstImport.TextItem as text -> TextContent(text)
|
||||
| :? AstImport.ArticleDef as defs -> article_assemble(defs)
|
||||
| _ -> raise (System.NotImplementedException())
|
||||
)
|
||||
VolumeDefine(defs, childs)
|
||||
|
||||
|
||||
type UnitGenerate(root: AstImport.AstObject) =
|
||||
class
|
||||
// ast 节点序列
|
||||
let forwards_map = AstImport.branch_map_conv(root, root.members())
|
||||
// 累积结果
|
||||
let mutable result_nodes: (int*Present.IDomUnit) list = []
|
||||
|
||||
interface AstImport.AstVisitor with
|
||||
member this.visit(obj: AstImport.AstObject): bool =
|
||||
let refs_depth = AstImport.depth_seek(forwards_map, obj)
|
||||
let childs = result_nodes |> List.filter (fun (depth, _) -> depth > refs_depth)
|
||||
|> List.map(fun (_, object) -> object)
|
||||
|
||||
let datas = match obj with
|
||||
| :? AstImport.TextItem as text ->
|
||||
(refs_depth, TextContent(text) :> Present.IDomUnit)::result_nodes
|
||||
| :? AstImport.PointRef as refs ->
|
||||
(refs_depth, PointRefer(refs, childs))::result_nodes
|
||||
| :? AstImport.PointDef as defs ->
|
||||
(refs_depth, PointDefine(defs, childs))::result_nodes
|
||||
| :? AstImport.SliceDef as defs ->
|
||||
(refs_depth, SliceDefine(defs, childs))::result_nodes
|
||||
| :? AstImport.StoryDef as defs ->
|
||||
(refs_depth, StoryDefine(defs, childs))::result_nodes
|
||||
| :? AstImport.ArticleDef as defs ->
|
||||
(refs_depth, ArticleDefine(defs, childs))::result_nodes
|
||||
| :? AstImport.VolumeDef as defs ->
|
||||
(refs_depth, VolumeDefine(defs, childs))::result_nodes
|
||||
| :? AstImport.Program -> result_nodes
|
||||
| _ -> raise (System.NotImplementedException())
|
||||
|
||||
result_nodes <- datas
|
||||
if refs_depth > 0 then
|
||||
result_nodes <- result_nodes |> List.filter(fun (depth, _) -> depth <= refs_depth)
|
||||
true
|
||||
|
||||
member this.contents() =
|
||||
result_nodes |> List.map(fun (_, obj) -> obj)
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
open AstAccess.AstImport
|
||||
open HtmlStruct.Content
|
||||
open System.Xml
|
||||
|
||||
let doc = XmlDocument()
|
||||
doc.Load("E:/storyline.xast")
|
||||
|
||||
let prog = Program.GenerateFrom(doc)
|
||||
|
||||
let entry = AstVisitEntry(prog)
|
||||
let visitor = UnitGenerate(prog)
|
||||
entry.visitWith(visitor) |> ignore
|
||||
|
||||
for it in visitor.contents() do
|
||||
printfn $"Name:{it.name()}"
|
|
@ -38,62 +38,102 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CoreTest", "CoreTest\CoreTe
|
|||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19} = {EF557F71-99AA-4F2B-A5F5-1A4518A11C19}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AstConv", "AstConv\AstConv.fsproj", "{0C77216C-6484-4C94-BE06-D5D9FF18EA81}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Debug|x64.Build.0 = Debug|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Debug|x86.Build.0 = Debug|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Release|Any CPU.Build.0 = Release|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Release|x64.ActiveCfg = Release|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Release|x64.Build.0 = Release|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Release|x86.ActiveCfg = Release|x64
|
||||
{1EF577E8-D92D-4926-9207-1567137BB672}.Release|x86.Build.0 = Release|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|x64.Build.0 = Debug|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Debug|x86.Build.0 = Debug|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|Any CPU.Build.0 = Release|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|x64.ActiveCfg = Release|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|x64.Build.0 = Release|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|x86.ActiveCfg = Release|x64
|
||||
{EF557F71-99AA-4F2B-A5F5-1A4518A11C19}.Release|x86.Build.0 = Release|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x64.Build.0 = Debug|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Debug|x86.Build.0 = Debug|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|Any CPU.Build.0 = Release|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x64.ActiveCfg = Release|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x64.Build.0 = Release|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x86.ActiveCfg = Release|x64
|
||||
{C3AADEB5-3695-4DF4-B8E1-D37F928F3B2F}.Release|x86.Build.0 = Release|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x64.Build.0 = Debug|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Debug|x86.Build.0 = Debug|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|Any CPU.Build.0 = Release|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x64.ActiveCfg = Release|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x64.Build.0 = Release|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x86.ActiveCfg = Release|x64
|
||||
{1FF80476-26C9-42FB-BFF6-D587C4941964}.Release|x86.Build.0 = Release|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Debug|x64.Build.0 = Debug|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Debug|x86.Build.0 = Debug|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Release|Any CPU.Build.0 = Release|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Release|x64.ActiveCfg = Release|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Release|x64.Build.0 = Release|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Release|x86.ActiveCfg = Release|x64
|
||||
{386F6D42-C6EB-4973-9511-181472391B21}.Release|x86.Build.0 = Release|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|x64.Build.0 = Debug|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Debug|x86.Build.0 = Debug|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|Any CPU.Build.0 = Release|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|x64.ActiveCfg = Release|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|x64.Build.0 = Release|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|x86.ActiveCfg = Release|x64
|
||||
{9B3EEB2A-26D7-4B2C-B890-505715283400}.Release|x86.Build.0 = Release|x64
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C77216C-6484-4C94-BE06-D5D9FF18EA81}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -6,708 +6,9 @@ using namespace example_novel;
|
|||
using namespace printer;
|
||||
using namespace lib_parse;
|
||||
|
||||
Access::Access(std::shared_ptr<const ast_gen::ElementAccess> handle)
|
||||
:access_handle(handle) {
|
||||
}
|
||||
|
||||
std::shared_ptr<const ast_gen::ElementAccess> Access::accessPeers() const {
|
||||
return access_handle;
|
||||
}
|
||||
|
||||
void Access::setPageRefers(const QString& href) {
|
||||
this->summary_refer_store = href;
|
||||
}
|
||||
|
||||
QString Access::pageRefers() const {
|
||||
return this->summary_refer_store;
|
||||
}
|
||||
|
||||
Element::Element(std::shared_ptr<const ast_gen::ElementAccess> handle) :Access(handle) {
|
||||
}
|
||||
|
||||
void printer::Element::setSliceRefer(const QString& href) {
|
||||
this->refer_store = href;
|
||||
}
|
||||
|
||||
QString printer::Element::sliceRefers() const {
|
||||
return refer_store;
|
||||
}
|
||||
|
||||
Group::Group(std::shared_ptr<const ast_gen::ElementAccess> handle) : Access(handle) {
|
||||
}
|
||||
|
||||
void Group::append(std::shared_ptr<Element> elm) {
|
||||
element_store.append(elm);
|
||||
}
|
||||
|
||||
QList<std::shared_ptr<Element>> Group::elements() const {
|
||||
return this->element_store;
|
||||
}
|
||||
|
||||
std::shared_ptr<Element> printer::Group::getElement(const QString& signature) const {
|
||||
for (auto& it : elements()) {
|
||||
if (it->accessPeers()->element()->signature() == signature)
|
||||
return it;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StoryLine::StoryLine(std::shared_ptr<const ast_gen::ElementAccess> handle) :Group(handle) {
|
||||
}
|
||||
|
||||
void StoryLine::buildPageHTML(QDomElement& parent) const {
|
||||
auto syntax_access = this->accessPeers();
|
||||
auto storyline_inst = std::dynamic_pointer_cast<const StoryDefine>(syntax_access->element());
|
||||
|
||||
auto doc = parent.ownerDocument();
|
||||
auto dom_storyline = doc.createElement("div");
|
||||
parent.appendChild(dom_storyline);
|
||||
|
||||
auto dom_title = doc.createElement("h1");
|
||||
dom_title.appendChild(doc.createTextNode(storyline_inst->name()));
|
||||
dom_storyline.appendChild(dom_title);
|
||||
|
||||
for (auto& inst_c : syntax_access->children()) {
|
||||
switch ((NovelNode) inst_c->element()->typeMark()) {
|
||||
case NovelNode::TextSection:
|
||||
{
|
||||
auto text_inst = std::dynamic_pointer_cast<const TextSection>(inst_c->element());
|
||||
auto dom_p = doc.createElement("p");
|
||||
dom_p.appendChild(doc.createTextNode(text_inst->content()));
|
||||
dom_storyline.appendChild(dom_p);
|
||||
}break;
|
||||
case NovelNode::PointRefers:
|
||||
case NovelNode::PointDefines:
|
||||
{
|
||||
auto element_inst = this->getElement(inst_c->element()->signature());
|
||||
element_inst->buildSliceHTML(dom_storyline);
|
||||
}break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StoryVolume::StoryVolume(std::shared_ptr<const ast_gen::ElementAccess> handle) : Group(handle) {
|
||||
}
|
||||
|
||||
void StoryVolume::buildPageHTML(QDomElement& parent) const {
|
||||
auto syntax_access = this->accessPeers();
|
||||
auto volume_inst = std::dynamic_pointer_cast<const VolumeDefine>(syntax_access->element());
|
||||
|
||||
auto doc_inst = parent.ownerDocument();
|
||||
auto dom_volume = doc_inst.createElement("div");
|
||||
parent.appendChild(dom_volume);
|
||||
|
||||
auto dom_title = doc_inst.createElement("h1");
|
||||
dom_title.appendChild(doc_inst.createTextNode(volume_inst->name()));
|
||||
dom_volume.appendChild(dom_title);
|
||||
|
||||
std::function<void(QDomElement&, const QList<std::shared_ptr<const ast_gen::ElementAccess>>&)> rich_refer_build =
|
||||
[&](QDomElement& parent_element, const QList<std::shared_ptr<const ast_gen::ElementAccess>> children) {
|
||||
for (auto& child : children) {
|
||||
auto doc_ins = parent_element.ownerDocument();
|
||||
switch ((NovelNode) child->element()->typeMark()) {
|
||||
case NovelNode::TextSection:
|
||||
{
|
||||
auto text_inst = std::dynamic_pointer_cast<const TextSection>(child->element());
|
||||
auto dom_p = doc_ins.createElement("p");
|
||||
dom_p.appendChild(doc_ins.createTextNode(text_inst->content()));
|
||||
parent_element.appendChild(dom_p);
|
||||
}break;
|
||||
case NovelNode::ArticleDefine:
|
||||
{
|
||||
auto article_inst = std::dynamic_pointer_cast<const ArticleDefine>(child->element());
|
||||
auto article_group = doc_ins.createElement("div");
|
||||
auto article_head = doc_ins.createElement("h2");
|
||||
article_head.appendChild(doc_ins.createTextNode(article_inst->name() + "{"));
|
||||
article_group.appendChild(article_head);
|
||||
rich_refer_build(article_group, child->children());
|
||||
article_group.appendChild(doc_ins.createTextNode("}"));
|
||||
parent_element.appendChild(article_group);
|
||||
}break;
|
||||
case NovelNode::PointRefers:
|
||||
{
|
||||
auto fragment_inst = std::dynamic_pointer_cast<const PointRefers>(child->element());
|
||||
auto refer_inst = this->getElement(fragment_inst->signature());
|
||||
refer_inst->buildSliceHTML(parent_element);
|
||||
}break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rich_refer_build(dom_volume, syntax_access->children());
|
||||
}
|
||||
|
||||
FragmentRef::FragmentRef(std::shared_ptr<const ast_gen::ElementAccess> handle) : Element(handle) {
|
||||
}
|
||||
|
||||
void printer::FragmentRef::setHost(std::shared_ptr<Fragment> frag_inst) {
|
||||
this->host_inst = frag_inst;
|
||||
}
|
||||
|
||||
std::shared_ptr<Fragment> printer::FragmentRef::hostFragment() const {
|
||||
return this->host_inst.lock();
|
||||
}
|
||||
|
||||
void FragmentRef::buildSliceHTML(QDomElement& dom_parent) const {
|
||||
auto syntax_access = this->accessPeers();
|
||||
auto refer_element = std::dynamic_pointer_cast<const PointRefers>(syntax_access->element());
|
||||
|
||||
auto jump_to_host = this->hostFragment()->pageRefers();
|
||||
auto doc = dom_parent.ownerDocument();
|
||||
|
||||
auto dom_reference = doc.createElement("div");
|
||||
dom_reference.setAttribute("id", QString::number((qulonglong) refer_element.get()));
|
||||
dom_parent.appendChild(dom_reference);
|
||||
|
||||
auto dom_title = doc.createElement("h2");
|
||||
dom_reference.appendChild(dom_title);
|
||||
|
||||
auto dom_href = doc.createElement("a");
|
||||
dom_href.appendChild(doc.createTextNode(refer_element->referSignature()));
|
||||
dom_href.setAttribute("href", "file:///" + jump_to_host);
|
||||
dom_title.appendChild(dom_href);
|
||||
|
||||
std::function<void(QDomElement&, const QList<std::shared_ptr<const ast_gen::ElementAccess>>&)> rich_refer_build =
|
||||
[&](QDomElement& parent_element, const QList<std::shared_ptr<const ast_gen::ElementAccess>> children) {
|
||||
for (auto& child : children) {
|
||||
auto doc_ins = parent_element.ownerDocument();
|
||||
switch ((NovelNode) child->element()->typeMark()) {
|
||||
case NovelNode::TextSection:
|
||||
{
|
||||
auto text_inst = std::dynamic_pointer_cast<const TextSection>(child->element());
|
||||
auto dom_p = doc_ins.createElement("p");
|
||||
dom_p.appendChild(doc_ins.createTextNode(text_inst->content()));
|
||||
parent_element.appendChild(dom_p);
|
||||
}break;
|
||||
case NovelNode::ArticleDefine:
|
||||
{
|
||||
auto article_inst = std::dynamic_pointer_cast<const ArticleDefine>(child->element());
|
||||
auto article_group = doc_ins.createElement("div");
|
||||
auto article_head = doc_ins.createElement("h2");
|
||||
article_head.appendChild(doc_ins.createTextNode(article_inst->name() + "{"));
|
||||
article_group.appendChild(article_head);
|
||||
rich_refer_build(article_group, child->children());
|
||||
article_group.appendChild(doc_ins.createTextNode("}"));
|
||||
parent_element.appendChild(article_group);
|
||||
}break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rich_refer_build(dom_reference, syntax_access->children());
|
||||
}
|
||||
|
||||
void FragmentRef::buildPageHTML(QDomElement& parent) const {
|
||||
auto syntax_access = this->accessPeers();
|
||||
auto refer_element = std::dynamic_pointer_cast<const PointRefers>(syntax_access->element());
|
||||
|
||||
auto doc = parent.ownerDocument();
|
||||
|
||||
auto refers_dom = doc.createElement("div");
|
||||
parent.appendChild(refers_dom);
|
||||
|
||||
auto title_block = doc.createElement("h2");
|
||||
refers_dom.appendChild(title_block);
|
||||
auto title_refer = doc.createElement("a");
|
||||
title_refer.appendChild(doc.createTextNode(refer_element->signature()));
|
||||
title_refer.setAttribute("href", "file:///" + this->sliceRefers());
|
||||
title_block.appendChild(title_refer);
|
||||
|
||||
std::function<void(QList<std::shared_ptr<const ast_gen::ElementAccess>>)> build_cascade =
|
||||
[&](QList<std::shared_ptr<const ast_gen::ElementAccess>> children_items) {
|
||||
for (auto child : children_items) {
|
||||
if (child->element()->typeMark() == (int) NovelNode::TextSection) {
|
||||
auto text_inst = std::dynamic_pointer_cast<const TextSection>(child->element());
|
||||
auto p = doc.createElement("p");
|
||||
p.appendChild(doc.createTextNode(text_inst->content()));
|
||||
refers_dom.appendChild(p);
|
||||
}
|
||||
else {
|
||||
build_cascade(child->children());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
build_cascade(syntax_access->children());
|
||||
}
|
||||
|
||||
Fragment::Fragment(std::shared_ptr<const ast_gen::ElementAccess> handle) : Element(handle) {
|
||||
}
|
||||
|
||||
void Fragment::appendRefers(std::shared_ptr<FragmentRef> inst) {
|
||||
this->additionals_store.append(inst);
|
||||
inst->setHost(std::static_pointer_cast<Fragment>(this->shared_from_this()));
|
||||
}
|
||||
|
||||
QList<std::shared_ptr<FragmentRef>> Fragment::additionals() const {
|
||||
return this->additionals_store;
|
||||
}
|
||||
|
||||
void Fragment::buildSliceHTML(QDomElement& parent) const {
|
||||
auto syntax_access = this->accessPeers();
|
||||
auto fragment_inst = std::dynamic_pointer_cast<const PointDefines>(syntax_access->element());
|
||||
|
||||
auto doc = parent.ownerDocument();
|
||||
auto dom_fragment = doc.createElement("div");
|
||||
dom_fragment.setAttribute("id", QString::number((qulonglong) fragment_inst.get()));
|
||||
parent.appendChild(dom_fragment);
|
||||
|
||||
auto dom_title = doc.createElement("h2");
|
||||
dom_fragment.appendChild(dom_title);
|
||||
|
||||
auto dom_href = doc.createElement("a");
|
||||
dom_href.appendChild(doc.createTextNode(fragment_inst->name()));
|
||||
dom_href.setAttribute("href", "file:///" + this->pageRefers());
|
||||
dom_title.appendChild(dom_href);
|
||||
|
||||
for (auto& inst_c : syntax_access->children()) {
|
||||
if (NovelNode::TextSection == (NovelNode) inst_c->element()->typeMark()) {
|
||||
auto text_inst = std::dynamic_pointer_cast<const TextSection>(inst_c->element());
|
||||
auto dom_p = doc.createElement("p");
|
||||
dom_p.appendChild(doc.createTextNode(text_inst->content()));
|
||||
dom_fragment.appendChild(dom_p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Fragment::buildPageHTML(QDomElement& parent) const {
|
||||
auto syntax_access = this->accessPeers();
|
||||
auto fragment_inst = std::dynamic_pointer_cast<const PointDefines>(syntax_access->element());
|
||||
|
||||
auto doc = parent.ownerDocument();
|
||||
auto dom_fragment = doc.createElement("div");
|
||||
parent.appendChild(dom_fragment);
|
||||
|
||||
auto dom_title = doc.createElement("h1");
|
||||
dom_fragment.appendChild(dom_title);
|
||||
|
||||
auto dom_href = doc.createElement("a");
|
||||
dom_href.appendChild(doc.createTextNode(fragment_inst->signature()));
|
||||
dom_href.setAttribute("href", "file:///" + this->sliceRefers());
|
||||
dom_title.appendChild(dom_href);
|
||||
|
||||
for (auto& inst_c : syntax_access->children()) {
|
||||
if (NovelNode::TextSection == (NovelNode) inst_c->element()->typeMark()) {
|
||||
auto text_inst = std::dynamic_pointer_cast<const TextSection>(inst_c->element());
|
||||
auto dom_p = doc.createElement("p");
|
||||
dom_p.appendChild(doc.createTextNode(text_inst->content()));
|
||||
dom_fragment.appendChild(dom_p);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& it : this->additionals()) {
|
||||
it->buildPageHTML(dom_fragment);
|
||||
}
|
||||
}
|
||||
|
||||
#include <ast_novel.h>
|
||||
void tools_printer::build_fragments(std::shared_ptr<const ast_gen::ElementAccess> novel_root) {
|
||||
if (novel_root->element()->typeMark() == (int) NovelNode::PointDefines) {
|
||||
auto inst = std::make_shared<Fragment>(novel_root);
|
||||
auto name = novel_root->element()->signature();
|
||||
this->fragment_defines[name] = inst;
|
||||
}
|
||||
|
||||
for (auto& inst_c : novel_root->children()) {
|
||||
build_fragments(inst_c);
|
||||
}
|
||||
}
|
||||
|
||||
void tools_printer::build_refers_network(std::shared_ptr<const ast_gen::ElementAccess> novel_node) {
|
||||
switch ((NovelNode) novel_node->element()->typeMark()) {
|
||||
case NovelNode::StoryDefine:
|
||||
{
|
||||
auto storyinst = std::make_shared<StoryLine>(novel_node);
|
||||
this->storyline_defines[novel_node->element()->signature()] = storyinst;
|
||||
build_storyline(storyinst);
|
||||
}return;
|
||||
case NovelNode::VolumeDefine:
|
||||
{
|
||||
auto volumeinst = std::make_shared<StoryVolume>(novel_node);
|
||||
this->volume_defines[novel_node->element()->signature()] = volumeinst;
|
||||
build_volumeline(volumeinst);
|
||||
}return;
|
||||
}
|
||||
|
||||
for (auto& inst_c : novel_node->children())
|
||||
build_refers_network(inst_c);
|
||||
}
|
||||
|
||||
void tools_printer::build_storyline(std::shared_ptr<StoryLine> line, std::shared_ptr<const ast_gen::ElementAccess> novel_node) {
|
||||
if (!novel_node) {
|
||||
for (auto& inst_c : line->accessPeers()->children()) {
|
||||
build_storyline(line, inst_c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch ((NovelNode) novel_node->element()->typeMark()) {
|
||||
case NovelNode::PointDefines:
|
||||
{
|
||||
auto inst = this->fragment_defines[novel_node->element()->signature()];
|
||||
line->append(inst);
|
||||
}return;
|
||||
case NovelNode::PointRefers:
|
||||
{
|
||||
auto refer_node = std::dynamic_pointer_cast<const PointRefers>(novel_node->element());
|
||||
auto refer_fragment = this->fragment_defines[refer_node->referSignature()];
|
||||
auto inst = std::make_shared<FragmentRef>(novel_node);
|
||||
refer_fragment->appendRefers(inst);
|
||||
line->append(inst);
|
||||
}return;
|
||||
}
|
||||
|
||||
for (auto& inst_c : novel_node->children())
|
||||
build_storyline(line, inst_c);
|
||||
}
|
||||
}
|
||||
|
||||
void tools_printer::build_volumeline(std::shared_ptr<StoryVolume> volume, std::shared_ptr<const ast_gen::ElementAccess> novel_node) {
|
||||
if (!novel_node) {
|
||||
for (auto& inst_c : volume->accessPeers()->children())
|
||||
build_volumeline(volume, inst_c);
|
||||
}
|
||||
else {
|
||||
if (NovelNode::PointRefers == (NovelNode) novel_node->element()->typeMark()) {
|
||||
auto refer_node = std::dynamic_pointer_cast<const PointRefers>(novel_node->element());
|
||||
auto refer_fragment = this->fragment_defines[refer_node->referSignature()];
|
||||
auto inst = std::make_shared<FragmentRef>(novel_node);
|
||||
refer_fragment->appendRefers(inst);
|
||||
volume->append(inst);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& inst_c : novel_node->children())
|
||||
build_volumeline(volume, inst_c);
|
||||
}
|
||||
}
|
||||
|
||||
void tools_printer::fragments_anchors_define(const QList<std::shared_ptr<Fragment>>& list, const QDir& root_dir) {
|
||||
auto path = root_dir.filePath("fragments");
|
||||
if (!QDir(path).exists())
|
||||
root_dir.mkdir("fragments");
|
||||
QDir target_dir(path);
|
||||
|
||||
for (auto& it : list) {
|
||||
auto address_x = QString::number((qulonglong) it->accessPeers()->element().get());
|
||||
it->setPageRefers(target_dir.absoluteFilePath(QString("%1.html").arg(address_x)));
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void(const QList<std::shared_ptr<Element>>&, const QString&)> refers_refresh =
|
||||
[&](const QList<std::shared_ptr<Element>>& items, const QString& summary_href) {
|
||||
for (auto& item : items) {
|
||||
auto element_addr = QString::number((qulonglong) item->accessPeers()->element().get());
|
||||
item->setSliceRefer(summary_href + "#" + element_addr);
|
||||
}
|
||||
};
|
||||
|
||||
void tools_printer::storylines_anchors_define(const QList<std::shared_ptr<StoryLine>>& list, const QDir& root_dir) {
|
||||
auto path = root_dir.filePath("storylines");
|
||||
if (!QDir(path).exists())
|
||||
root_dir.mkdir("storylines");
|
||||
QDir target_dir(path);
|
||||
|
||||
for (auto& it : list) {
|
||||
auto address_x = QString::number((qulonglong) it->accessPeers()->element().get());
|
||||
auto page_address = target_dir.absoluteFilePath(QString("%1.html").arg(address_x));
|
||||
it->setPageRefers(page_address);
|
||||
refers_refresh(it->elements(), page_address);
|
||||
}
|
||||
}
|
||||
|
||||
void tools_printer::volumes_anchors_define(const QList<std::shared_ptr<StoryVolume>>& list, const QDir& root_dir) {
|
||||
auto path = root_dir.filePath("volumes");
|
||||
if (!QDir(path).exists())
|
||||
root_dir.mkdir("volumes");
|
||||
QDir target_dir(path);
|
||||
|
||||
for (auto& it : list) {
|
||||
auto address_x = QString::number((qulonglong) it->accessPeers()->element().get());
|
||||
auto page_address = target_dir.absoluteFilePath(QString("%1.html").arg(address_x));
|
||||
it->setPageRefers(page_address);
|
||||
refers_refresh(it->elements(), page_address);
|
||||
}
|
||||
}
|
||||
|
||||
auto get_node_name = [](const std::shared_ptr<Access> item) {
|
||||
return "node_" + QString::number((qulonglong) item->accessPeers()->element().get());
|
||||
};
|
||||
|
||||
QString printer::tools_printer::storylines_paint(const QList<std::shared_ptr<StoryLine>>& lines) {
|
||||
QHash<QString, std::shared_ptr<Access>> node_records;
|
||||
QString nodes_description;
|
||||
for (auto& story : lines) {
|
||||
auto story_elem = std::dynamic_pointer_cast<const example_novel::StoryDefine>(story->accessPeers()->element());
|
||||
node_records[story_elem->signature()] = story;
|
||||
nodes_description += get_node_name(story) + QString("[fillcolor=pink,label=\"%1{%2}\",shape=\"cds\"]\n").arg(story_elem->name()).arg(story_elem->sort());
|
||||
|
||||
for (auto& frag : story->elements()) {
|
||||
auto fragment_peers = frag->accessPeers()->element();
|
||||
if (fragment_peers->typeMark() == (int) example_novel::NovelNode::PointDefines) {
|
||||
auto fragment_elem = std::dynamic_pointer_cast<const example_novel::PointDefines>(fragment_peers);
|
||||
auto node_name = fragment_elem->signature();
|
||||
node_records[node_name] = frag;
|
||||
|
||||
nodes_description += get_node_name(frag) + QString("[label=\"{%2}::%1\",shape=\"rect\"]\n")
|
||||
.arg(fragment_elem->name()).arg(story_elem->sort());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString arrows_link;
|
||||
for (auto& story : lines) {
|
||||
auto story_elem = std::dynamic_pointer_cast<const example_novel::StoryDefine>(story->accessPeers()->element());
|
||||
|
||||
QString previous_node = get_node_name(story);
|
||||
for (auto& frag : story->elements()) {
|
||||
if (example_novel::NovelNode::PointDefines == (example_novel::NovelNode) frag->accessPeers()->element()->typeMark()) {
|
||||
arrows_link += previous_node + "->" + get_node_name(frag) + QString("[label=\"%1{%2}\"]\n")
|
||||
.arg(story_elem->name()).arg(story_elem->sort());
|
||||
previous_node = get_node_name(frag);
|
||||
}
|
||||
else if (example_novel::NovelNode::PointRefers == (example_novel::NovelNode) frag->accessPeers()->element()->typeMark()) {
|
||||
auto frag_refer = std::dynamic_pointer_cast<const example_novel::PointRefers>(frag->accessPeers()->element());
|
||||
auto frag_src = node_records[frag_refer->referSignature()];
|
||||
arrows_link += previous_node + "->" + get_node_name(frag_src) + QString("[label=\"%1{%2}\"]\n")
|
||||
.arg(story_elem->name()).arg(story_elem->sort());
|
||||
previous_node = get_node_name(frag_src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QString("digraph{ rankdir = LR \n node[style=filled] \n %1\n %2 }").arg(nodes_description).arg(arrows_link);
|
||||
}
|
||||
|
||||
QString printer::tools_printer::volumes_paint(const QList<std::shared_ptr<StoryVolume>>& vols, const QList<std::shared_ptr<StoryLine>>& lines) {
|
||||
QHash<QString, std::shared_ptr<Element>> node_records;
|
||||
|
||||
QString clusters_description;
|
||||
for (auto& story : lines) {
|
||||
QString nodes_description;
|
||||
for (auto& frag : story->elements()) {
|
||||
auto fragment_peers = frag->accessPeers()->element();
|
||||
if (fragment_peers->typeMark() == (int) example_novel::NovelNode::PointDefines) {
|
||||
auto fragment_elem = std::dynamic_pointer_cast<const example_novel::PointDefines>(fragment_peers);
|
||||
node_records[fragment_elem->signature()] = frag;
|
||||
nodes_description += get_node_name(frag) + QString("[label=\"%1\",shape=\"ellipse\"]\n").arg(fragment_elem->name());
|
||||
}
|
||||
}
|
||||
|
||||
auto story_elem = std::dynamic_pointer_cast<const example_novel::StoryDefine>(story->accessPeers()->element());
|
||||
clusters_description += QString("subgraph cluster_%1 { label=%3 \n %2 }")
|
||||
.arg((qulonglong) story_elem.get()).arg(nodes_description).arg(story_elem->name());
|
||||
}
|
||||
|
||||
|
||||
auto article_cluster = [&node_records](const std::shared_ptr<const ast_gen::ElementAccess> article_access, QList<QString>& arrows_out)->QString {
|
||||
QString nodes_description;
|
||||
for (auto& fragment_access : article_access->children()) {
|
||||
if (fragment_access->element()->typeMark() == (int) example_novel::NovelNode::PointRefers) {
|
||||
auto refer_fragment = std::dynamic_pointer_cast<const example_novel::PointRefers>(fragment_access->element());
|
||||
nodes_description += QString("fragment_%1[label=\"%2\",shape=\"plaintext\"]\n")
|
||||
.arg((qulonglong) refer_fragment.get()).arg(refer_fragment->sliceRefer());
|
||||
auto symbo_refer = node_records[refer_fragment->referSignature()];
|
||||
arrows_out << QString("fragment_%1 -- %2[color=\"red\"]\n").arg((qulonglong) refer_fragment.get()).arg(get_node_name(symbo_refer));
|
||||
}
|
||||
}
|
||||
auto article_define = std::dynamic_pointer_cast<const example_novel::ArticleDefine>(article_access->element());
|
||||
return QString("subgraph cluster_%1{ label=%2 \n %3 }\n").arg((qulonglong) article_access->element().get())
|
||||
.arg(article_define->name()).arg(nodes_description);
|
||||
};
|
||||
|
||||
QString arrows_link;
|
||||
for (auto& vol : vols) {
|
||||
QString members_description;
|
||||
for (auto& eref : vol->accessPeers()->children()) {
|
||||
QList<QString> arrows_temp;
|
||||
switch ((example_novel::NovelNode) eref->element()->typeMark()) {
|
||||
case example_novel::NovelNode::ArticleDefine:
|
||||
members_description += article_cluster(eref, arrows_temp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (auto& arrow : arrows_temp) {
|
||||
arrows_link += arrow;
|
||||
}
|
||||
}
|
||||
|
||||
auto volume_elem = std::dynamic_pointer_cast<const example_novel::VolumeDefine>(vol->accessPeers()->element());
|
||||
clusters_description += QString("subgraph cluster_%1 { label=%3 \n %2 }")
|
||||
.arg((qulonglong) volume_elem.get()).arg(members_description).arg(volume_elem->name());
|
||||
}
|
||||
|
||||
return QString("graph scale{ %1 \n %2}").arg(clusters_description).arg(arrows_link);
|
||||
}
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QTime>
|
||||
#include <QDebug>
|
||||
void printer::tools_printer::plain_html_output(const std::shared_ptr<const ast_gen::ElementAccess> access_ptr, const QDir& destination_dir) const {
|
||||
QTime time_stamp = QTime::currentTime();
|
||||
auto tool = *this;
|
||||
tool.build_fragments(access_ptr);
|
||||
tool.build_refers_network(access_ptr);
|
||||
|
||||
tool.fragments_anchors_define(tool.fragment_defines.values(), destination_dir);
|
||||
tool.storylines_anchors_define(tool.storyline_defines.values(), destination_dir);
|
||||
tool.volumes_anchors_define(tool.volume_defines.values(), destination_dir);
|
||||
|
||||
std::function<void(std::shared_ptr<const printer::Access>)> html_output =
|
||||
[](std::shared_ptr<const printer::Access> inst) {
|
||||
auto target_path = inst->pageRefers();
|
||||
QFile tfile(target_path);
|
||||
if (tfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QDomDocument doc_inst(QDomImplementation().createDocumentType("html", QString(), QString()));
|
||||
auto html = doc_inst.createElement("html");
|
||||
doc_inst.appendChild(html);
|
||||
|
||||
auto body = doc_inst.createElement("body");
|
||||
html.appendChild(body);
|
||||
|
||||
inst->buildPageHTML(body);
|
||||
|
||||
QTextStream tout(&tfile);
|
||||
doc_inst.save(tout, 2);
|
||||
tout.flush();
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& node : tool.fragment_defines)
|
||||
html_output(node);
|
||||
for (auto& node : tool.storyline_defines)
|
||||
html_output(node);
|
||||
for (auto& node : tool.volume_defines)
|
||||
html_output(node);
|
||||
|
||||
QDir::setCurrent(destination_dir.canonicalPath());
|
||||
auto dot_src = tool.storylines_paint(tool.storyline_defines.values());
|
||||
QFile dot_file(QDir::current().filePath("relates.dot"));
|
||||
if (dot_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream txt(&dot_file);
|
||||
txt.setCodec("UTF-8");
|
||||
txt << dot_src;
|
||||
txt.flush();
|
||||
}
|
||||
system("dot -Tsvg relates.dot -o relates.svg");
|
||||
|
||||
auto vols_src = tool.volumes_paint(tool.volume_defines.values(), tool.storyline_defines.values());
|
||||
QFile vols_file(QDir::current().filePath("volumes_group.dot"));
|
||||
if (vols_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream txt(&vols_file);
|
||||
txt.setCodec("UTF-8");
|
||||
txt << vols_src;
|
||||
txt.flush();
|
||||
}
|
||||
system("fdp -Tsvg volumes_group.dot -o volumes_group.svg");
|
||||
|
||||
|
||||
{
|
||||
QFile tfile("./index.html");
|
||||
if (tfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QDomDocument doc_inst(QDomImplementation().createDocumentType("html", QString(), QString()));
|
||||
auto html = doc_inst.createElement("html");
|
||||
doc_inst.appendChild(html);
|
||||
|
||||
auto body = doc_inst.createElement("body");
|
||||
html.appendChild(body);
|
||||
|
||||
auto dom_storyline = doc_inst.createElement("div");
|
||||
auto dom_storyline_title = doc_inst.createElement("h2");
|
||||
dom_storyline_title.appendChild(doc_inst.createTextNode("故事脉络"));
|
||||
dom_storyline.appendChild(dom_storyline_title);
|
||||
body.appendChild(dom_storyline);
|
||||
|
||||
auto lines = tool.storyline_defines.values();
|
||||
std::sort(lines.begin(), lines.end(), [](std::shared_ptr<printer::StoryLine> a, std::shared_ptr<printer::StoryLine> b)->bool {
|
||||
auto a_elm = std::dynamic_pointer_cast<const example_novel::StoryDefine>(a->accessPeers()->element());
|
||||
auto b_elm = std::dynamic_pointer_cast<const example_novel::StoryDefine>(b->accessPeers()->element());
|
||||
return a_elm->sort() < b_elm->sort();
|
||||
});
|
||||
for (auto& inst_line : lines) {
|
||||
auto dom_line = doc_inst.createElement("p");
|
||||
dom_storyline.appendChild(dom_line);
|
||||
|
||||
auto line_href = doc_inst.createElement("a");
|
||||
line_href.setAttribute("href", "file:///" + inst_line->pageRefers());
|
||||
auto a_elm = std::dynamic_pointer_cast<const example_novel::StoryDefine>(inst_line->accessPeers()->element());
|
||||
line_href.appendChild(doc_inst.createTextNode(QString("%1.%2").arg(a_elm->sort()).arg(a_elm->signature())));
|
||||
dom_line.appendChild(line_href);
|
||||
}
|
||||
|
||||
auto dom_volume = doc_inst.createElement("div");
|
||||
auto dom_volume_title = doc_inst.createElement("h2");
|
||||
dom_volume_title.appendChild(doc_inst.createTextNode("分卷内容"));
|
||||
dom_volume.appendChild(dom_volume_title);
|
||||
body.appendChild(dom_volume);
|
||||
|
||||
for (auto& inst_volume : tool.volume_defines) {
|
||||
auto dom_volume_ref = doc_inst.createElement("p");
|
||||
dom_volume.appendChild(dom_volume_ref);
|
||||
|
||||
auto volume_href = doc_inst.createElement("a");
|
||||
volume_href.setAttribute("href", "file:///" + inst_volume->pageRefers());
|
||||
volume_href.appendChild(doc_inst.createTextNode(inst_volume->accessPeers()->element()->signature()));
|
||||
dom_volume_ref.appendChild(volume_href);
|
||||
}
|
||||
|
||||
auto dom_fragment = doc_inst.createElement("div");
|
||||
auto dom_fragment_title = doc_inst.createElement("h2");
|
||||
dom_fragment_title.appendChild(doc_inst.createTextNode("情节集合"));
|
||||
dom_fragment.appendChild(dom_fragment_title);
|
||||
body.appendChild(dom_fragment);
|
||||
|
||||
auto table_cube = doc_inst.createElement("table");
|
||||
dom_fragment.appendChild(table_cube);
|
||||
|
||||
int row_ctrl = 0;
|
||||
QDomElement elm_row;
|
||||
for (auto& inst_frag : tool.fragment_defines) {
|
||||
if (row_ctrl++ % 4 == 0) {
|
||||
elm_row = doc_inst.createElement("tr");
|
||||
table_cube.appendChild(elm_row);
|
||||
}
|
||||
|
||||
auto dom_fragment_ref = doc_inst.createElement("td");
|
||||
elm_row.appendChild(dom_fragment_ref);
|
||||
|
||||
auto frag_href = doc_inst.createElement("a");
|
||||
frag_href.setAttribute("href", "file:///" + inst_frag->pageRefers());
|
||||
frag_href.appendChild(doc_inst.createTextNode(inst_frag->accessPeers()->element()->signature()));
|
||||
dom_fragment_ref.appendChild(frag_href);
|
||||
}
|
||||
|
||||
auto dom_relate = doc_inst.createElement("div");
|
||||
auto dom_relate_title = doc_inst.createElement("h2");
|
||||
dom_relate_title.appendChild(doc_inst.createTextNode("联系图"));
|
||||
dom_relate.appendChild(dom_relate_title);
|
||||
body.appendChild(dom_relate);
|
||||
|
||||
auto img = doc_inst.createElement("img");
|
||||
img.setAttribute("src", "file:///" + QDir::current().filePath("relates.svg"));
|
||||
dom_relate.appendChild(img);
|
||||
dom_relate.appendChild(doc_inst.createElement("br"));
|
||||
img = doc_inst.createElement("img");
|
||||
img.setAttribute("src", "file:///" + QDir::current().filePath("volumes_group.svg"));
|
||||
dom_relate.appendChild(img);
|
||||
|
||||
QTextStream tout(&tfile);
|
||||
doc_inst.save(tout, 2);
|
||||
tout.flush();
|
||||
}
|
||||
}
|
||||
|
||||
auto current_stamp = QTime::currentTime();
|
||||
qDebug().noquote() << QString("%html构建消耗时间:%1 ms。").arg(time_stamp.msecsTo(current_stamp));
|
||||
qDebug().noquote() << "%编译成功:" << destination_dir.absoluteFilePath("index.html");
|
||||
}
|
||||
|
||||
void printer::AstGenerate::append_tokens(QDomElement _elm, std::shared_ptr<const ast_gen::SyntaxElement> inst) {
|
||||
auto dom_tokens = doc.createElement("tokens");
|
||||
|
|
|
@ -8,175 +8,6 @@
|
|||
#include <parse_novel.h>
|
||||
|
||||
namespace printer {
|
||||
/**
|
||||
* 概括页面
|
||||
* 故事分卷汇总
|
||||
* 故事脉络汇总
|
||||
* 故事脉络关系图.
|
||||
*
|
||||
* 故事脉络发展页面
|
||||
* 故事剧情节点汇总
|
||||
* 内容展示
|
||||
*
|
||||
* 剧情节点汇总页面
|
||||
* 引用来源汇总
|
||||
* 各节点内容展示
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* @brief 所有可访问元素的基类:卷宗、章节、故事线、剧情、节点、引用等
|
||||
*/
|
||||
class Access : public std::enable_shared_from_this<Access> {
|
||||
public:
|
||||
Access(std::shared_ptr<const ast_gen::ElementAccess> handle);
|
||||
virtual ~Access() = default;
|
||||
|
||||
/*
|
||||
* @brief 获取绑定的语法元素
|
||||
* @return 元素内存指针
|
||||
*/
|
||||
std::shared_ptr<const ast_gen::ElementAccess> accessPeers() const;
|
||||
|
||||
/*
|
||||
* @brief 设置汇总页面路径
|
||||
* @param href 页面路径
|
||||
*/
|
||||
void setPageRefers(const QString& href);
|
||||
QString pageRefers() const;
|
||||
|
||||
/*
|
||||
* @brief 获取汇总页面的HTML
|
||||
*/
|
||||
virtual void buildPageHTML(QDomElement& doc) const = 0;
|
||||
|
||||
private:
|
||||
std::shared_ptr<const ast_gen::ElementAccess> access_handle;
|
||||
QString summary_refer_store;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief 可访问片段元素:故事片段本篇,故事片段引用
|
||||
*/
|
||||
class Element : public Access {
|
||||
public:
|
||||
Element(std::shared_ptr<const ast_gen::ElementAccess> handle);
|
||||
virtual ~Element() = default;
|
||||
|
||||
/*
|
||||
* @brief 设置片段URL,从故事汇总页面跳转回出处页面
|
||||
*/
|
||||
virtual void setSliceRefer(const QString& href);
|
||||
virtual QString sliceRefers() const;
|
||||
|
||||
/*
|
||||
* @brief 获取故事片段出处的节点HTML
|
||||
*/
|
||||
virtual void buildSliceHTML(QDomElement &doc) const = 0;
|
||||
|
||||
private:
|
||||
QString refer_store;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief 可访问集合的基类:故事线、剧情节点、故事卷宗
|
||||
*/
|
||||
class Group : public Access {
|
||||
public:
|
||||
Group(std::shared_ptr<const ast_gen::ElementAccess> handle);
|
||||
virtual ~Group() = default;
|
||||
|
||||
void append(std::shared_ptr<Element> elm);
|
||||
QList<std::shared_ptr<Element>> elements() const;
|
||||
std::shared_ptr<Element> getElement(const QString& signature) const;
|
||||
|
||||
private:
|
||||
QList<std::shared_ptr<Element>> element_store;
|
||||
};
|
||||
|
||||
class StoryLine : public Group {
|
||||
public:
|
||||
StoryLine(std::shared_ptr<const ast_gen::ElementAccess> handle);
|
||||
|
||||
// 通过 Group 继承
|
||||
void buildPageHTML(QDomElement& doc) const override;
|
||||
|
||||
};
|
||||
|
||||
class StoryVolume : public Group {
|
||||
public:
|
||||
StoryVolume(std::shared_ptr<const ast_gen::ElementAccess> handle);
|
||||
|
||||
// 通过 Group 继承
|
||||
void buildPageHTML(QDomElement& doc) const override;
|
||||
|
||||
};
|
||||
class Fragment;
|
||||
/*
|
||||
* @brief 情节片段引用定义
|
||||
*/
|
||||
class FragmentRef : public Element {
|
||||
public:
|
||||
FragmentRef(std::shared_ptr<const ast_gen::ElementAccess> handle);
|
||||
|
||||
void setHost(std::shared_ptr<Fragment> frag_inst);
|
||||
std::shared_ptr<Fragment> hostFragment() const;
|
||||
|
||||
// 通过 Access 继承
|
||||
void buildPageHTML(QDomElement& doc) const override;
|
||||
|
||||
// 通过 Element 继承
|
||||
void buildSliceHTML(QDomElement& doc) const override;
|
||||
|
||||
private:
|
||||
std::weak_ptr<Fragment> host_inst;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief 情节片段本篇定义,存储情节引用定义
|
||||
*/
|
||||
class Fragment : public Element{
|
||||
private:
|
||||
QList<std::shared_ptr<FragmentRef>> additionals_store;
|
||||
|
||||
public:
|
||||
Fragment(std::shared_ptr<const ast_gen::ElementAccess> handle);
|
||||
|
||||
void appendRefers(std::shared_ptr<FragmentRef> inst);
|
||||
QList<std::shared_ptr<FragmentRef>> additionals() const;
|
||||
|
||||
// 通过 Access 继承
|
||||
void buildPageHTML(QDomElement& doc) const override;
|
||||
|
||||
// 通过 Element 继承
|
||||
void buildSliceHTML(QDomElement& doc) const override;
|
||||
};
|
||||
|
||||
|
||||
class tools_printer {
|
||||
public:
|
||||
QHash<QString, std::shared_ptr<Fragment>> fragment_defines;
|
||||
QHash<QString, std::shared_ptr<StoryLine>> storyline_defines;
|
||||
QHash<QString, std::shared_ptr<StoryVolume>> volume_defines;
|
||||
|
||||
public:
|
||||
void build_fragments(std::shared_ptr<const ast_gen::ElementAccess> novel_root);
|
||||
|
||||
void build_refers_network(std::shared_ptr<const ast_gen::ElementAccess> novel_node);
|
||||
|
||||
void build_storyline(std::shared_ptr<StoryLine> line, std::shared_ptr<const ast_gen::ElementAccess> novel_node = nullptr);
|
||||
void build_volumeline(std::shared_ptr<StoryVolume> line, std::shared_ptr<const ast_gen::ElementAccess> novel_node = nullptr);
|
||||
|
||||
void fragments_anchors_define(const QList<std::shared_ptr<Fragment>> &list, const QDir &destdir);
|
||||
void storylines_anchors_define(const QList<std::shared_ptr<StoryLine>> &list, const QDir &destdir);
|
||||
void volumes_anchors_define(const QList<std::shared_ptr<StoryVolume>> &list, const QDir &destdir);
|
||||
|
||||
QString storylines_paint(const QList<std::shared_ptr<StoryLine>> &lines);
|
||||
QString volumes_paint(const QList<std::shared_ptr<StoryVolume>> &vols, const QList<std::shared_ptr<StoryLine>> &lines);
|
||||
|
||||
void plain_html_output(const std::shared_ptr<const ast_gen::ElementAccess> root, const QDir &destinationdir) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Ast输出构建器.
|
||||
*/
|
||||
|
|
|
@ -34,8 +34,7 @@ int main(int argc, char* argv[]) {
|
|||
args_parser << build_mode;
|
||||
*build_mode << make_shared<IndexParam>("nsc", "程序名称")
|
||||
<< make_shared<FloatKeyValue>("path", "指定源代码目录")
|
||||
<< make_shared<FloatKeyValue>("dest", "指定生成目录")
|
||||
<< make_shared<FloatOption>("html", "生成html文件格式取代AST", true);
|
||||
<< make_shared<FloatKeyValue>("dest", "指定生成目录");
|
||||
|
||||
|
||||
auto p_result = args_parser.parse(argc, argv);
|
||||
|
@ -49,7 +48,6 @@ int main(int argc, char* argv[]) {
|
|||
{
|
||||
auto src_dir = dynamic_pointer_cast<FloatKeyValue>(p_result->getUnitViaKey("path"));
|
||||
auto dst_dir = dynamic_pointer_cast<FloatKeyValue>(p_result->getUnitViaKey("dest"));
|
||||
auto html_opt = dynamic_pointer_cast<FloatOption>(p_result->getUnitViaKey("html"));
|
||||
|
||||
auto source_dir = QDir(src_dir->value().toString());
|
||||
if (!source_dir.exists()) {
|
||||
|
@ -93,11 +91,7 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
if (html_opt->value().toInt() == 1 && access_ptr) {
|
||||
printer::tools_printer tool;
|
||||
tool.plain_html_output(access_ptr, destination_dir);
|
||||
}
|
||||
else if (access_ptr) {
|
||||
if (access_ptr) {
|
||||
QTime time_stamp = QTime::currentTime();
|
||||
lib_parse::VisitEntry control;
|
||||
auto visitor = make_shared<printer::AstGenerate>(source_dir);
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace lib_syntax {
|
|||
MatchCursor(std::shared_ptr<const MatchCursor> other_ptr);
|
||||
virtual ~MatchCursor() = default;
|
||||
|
||||
bool operator>(const MatchCursor & other) const;
|
||||
bool operator>(const MatchCursor& other) const;
|
||||
|
||||
virtual std::shared_ptr<const MatchCursor> previous() const;
|
||||
virtual QString filePath() const;
|
||||
|
@ -195,7 +195,8 @@ namespace lib_syntax {
|
|||
std::shared_ptr<const lib_token::ITokenProcess> _define_peers;
|
||||
|
||||
public:
|
||||
__token_match_impl(std::shared_ptr<const lib_token::ITokenProcess> define) : _define_peers(define) { }
|
||||
__token_match_impl(std::shared_ptr<const lib_token::ITokenProcess> define) : _define_peers(define) {
|
||||
}
|
||||
|
||||
// IBasicRule interface
|
||||
public:
|
||||
|
@ -293,7 +294,8 @@ namespace lib_syntax {
|
|||
class ElementRule : public ExprRule {
|
||||
public:
|
||||
ElementRule(const QString& rule_name)
|
||||
:ExprRule(rule_name, mark), _children_store(std::make_shared<R>()) { }
|
||||
:ExprRule(rule_name, mark), _children_store(std::make_shared<R>()) {
|
||||
}
|
||||
|
||||
virtual QList<std::shared_ptr<const IBasicRule>> children() const {
|
||||
return QList<std::shared_ptr<const IBasicRule>>() << this->_children_store;
|
||||
|
@ -337,16 +339,10 @@ namespace lib_syntax {
|
|||
[](std::shared_ptr<const MatchCursor> ins) { return !ins->parseFailure(); });
|
||||
}
|
||||
|
||||
if (!branch_procs.size())
|
||||
branch_procs = nbranch;
|
||||
|
||||
|
||||
decltype(nbranch) results_fnl;
|
||||
for (auto curs : branch_procs) {
|
||||
if (curs->parseFailure()) {
|
||||
results_fnl.append(curs);
|
||||
}
|
||||
else {
|
||||
// 表达式匹配结尾
|
||||
if (branch_procs.size()) {
|
||||
decltype(nbranch) results_fnl;
|
||||
for (auto curs : branch_procs) {
|
||||
auto t_end = curs->token();
|
||||
auto w_end = curs->words();
|
||||
|
||||
|
@ -363,9 +359,11 @@ namespace lib_syntax {
|
|||
break;
|
||||
}
|
||||
}
|
||||
return results_fnl;
|
||||
}
|
||||
|
||||
return results_fnl;
|
||||
// 匹配失败
|
||||
return branch_procs;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
Loading…
Reference in New Issue