From 61940a2f34a127b35e7a208ccb7c59f39e4b5ae5 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Sat, 7 Jan 2023 23:25:42 +0100 Subject: [PATCH] fix non-section cross-doc number range ordering --- doc/examples.md | 9 ++- scanner/resolution.go | 3 +- src/examples.mdg | 6 +- statements/sectionref/n_sectionref.go | 2 +- statements/toc/n_toc.go | 2 +- tree/resolution.go | 73 ++++++++++++------ tree/tree.go | 104 ++++++++++++++++---------- 7 files changed, 129 insertions(+), 70 deletions(-) diff --git a/doc/examples.md b/doc/examples.md index e5dafe0..6b16916 100644 --- a/doc/examples.md +++ b/doc/examples.md @@ -1,7 +1,10 @@ ## 4 Examples -This document shows example for the generator syntax +This document shows examples for the generator syntax - -### 4.1 Filestructure +     [2-a A typical source tree](syntax.md#tree)
+     [2-b A typical source document](syntax.md#example)
+     [2-c Anchors in scoped environments](syntax.md#anchors)
+     [2-d The Figure Number Range used in this Documentation](syntax.md#nr)
+     [3-a Explicit Table of Contents for Linked Documents](statements.md#reftoc)
diff --git a/scanner/resolution.go b/scanner/resolution.go index a340cee..c93fc0d 100644 --- a/scanner/resolution.go +++ b/scanner/resolution.go @@ -374,10 +374,11 @@ func LinkFor(ri RefInfo, preferred ...string) utils2.Link { type Unscoped interface { GetDocument() Document GetParentDocument() Document + GetRootContext() ResolutionContext GetDocumentForLink(l utils2.Link) Document NextId(typ string) labels.Rule - RequestDocument(link utils2.Link, d Document) error + RequestDocument(link utils2.Link, location Location) error RequestNumberRange(typ string) GetNumberRange(typ string) NumberRange SetNumberRangeFor(d Document, id TaggedId, typ string, nr NumberRange) HierarchyLabel diff --git a/src/examples.mdg b/src/examples.mdg index 5d890b1..da1d575 100644 --- a/src/examples.mdg +++ b/src/examples.mdg @@ -1,5 +1,5 @@ {{section /examples}}Examples -This document shows example for the {{link #/syntax}}generator syntax{{endlink}} -{{section filestructure}}Filestructure -{{endsection}} +This document shows examples for the {{link #/syntax}}generator syntax{{endlink}} + +{{toc example}} {{endsection}} \ No newline at end of file diff --git a/statements/sectionref/n_sectionref.go b/statements/sectionref/n_sectionref.go index da68d81..e978063 100644 --- a/statements/sectionref/n_sectionref.go +++ b/statements/sectionref/n_sectionref.go @@ -109,7 +109,7 @@ func (n *sectionrefnode) Register(ctx scanner.ResolutionContext) error { return err } ctx.SetNodeContext(n, nctx) - err = ctx.RequestDocument(nctx.GetLink(), ctx.GetDocument()) + err = ctx.RequestDocument(nctx.GetLink(), n.Location()) if err != nil { return err } diff --git a/statements/toc/n_toc.go b/statements/toc/n_toc.go index 1b8d9ff..7ea74eb 100644 --- a/statements/toc/n_toc.go +++ b/statements/toc/n_toc.go @@ -135,7 +135,7 @@ func (n *tocnode) Emit(ctx scanner.ResolutionContext) error { } } } else { - list = TreeTOCIds(ctx, n.typ) + list = TreeTOCIds(ctx.GetRootContext(), n.typ) } if len(list) == 0 { diff --git a/tree/resolution.go b/tree/resolution.go index c3ebe3a..2733959 100644 --- a/tree/resolution.go +++ b/tree/resolution.go @@ -47,14 +47,14 @@ func (r *resolvedRef) Anchor() string { var _ scanner.ResolvedRef = (*resolvedRef)(nil) type StructInfo struct { - document scanner.Document - ranges map[string]scanner.NumberRange + docinfo *DocumentInfo + ranges map[string]scanner.NumberRange } -func NewStructInfo(d scanner.Document) *StructInfo { +func NewStructInfo(di *DocumentInfo) *StructInfo { return &StructInfo{ - document: d, - ranges: map[string]scanner.NumberRange{}, + docinfo: di, + ranges: map[string]scanner.NumberRange{}, } } @@ -65,14 +65,14 @@ type NumberRangeInfo struct { } type RootInfo struct { - document scanner.Document - ranges map[string]*NumberRangeInfo + docinfo *DocumentInfo + ranges map[string]*NumberRangeInfo } -func NewRootInfo(d scanner.Document) *RootInfo { +func NewRootInfo(di *DocumentInfo) *RootInfo { return &RootInfo{ - document: d, - ranges: map[string]*NumberRangeInfo{}, + docinfo: di, + ranges: map[string]*NumberRangeInfo{}, } } @@ -133,7 +133,7 @@ func (i *DocumentInfo) Emit(w scanner.Writer, target string) error { } func (i *DocumentInfo) IsRoot() bool { - return i.rootinfo.document == i.document + return i.rootinfo.docinfo == i } func (i *DocumentInfo) Walk(f scanner.Resolver) error { @@ -294,6 +294,35 @@ type unresolved struct { err error } +type docref struct { + location scanner.Location + docinfo *DocumentInfo + link utils2.Link +} +type docrefs struct { + order []*docref + links map[utils2.Link]*docref +} + +func newDocRefs() *docrefs { + return &docrefs{ + links: map[utils2.Link]*docref{}, + } +} + +func (r *docrefs) Add(link utils2.Link, loc scanner.Location) error { + if cur := r.links[link]; cur != nil { + return fmt.Errorf("%s: document ref %q already requested by %s", loc, link, cur.location) + } + cur := &docref{ + location: loc, + link: link, + } + r.order = append(r.order, cur) + r.links[link] = cur + return nil +} + type ResolutionContext struct { scope ids @@ -303,7 +332,8 @@ type ResolutionContext struct { docinfo *DocumentInfo - docrefs map[utils2.Link]scanner.Document + docrefs *docrefs + numberranges utils2.Set[string] writer scanner.Writer target string @@ -317,9 +347,9 @@ func NewResolutionContext(res *Resolution, di *DocumentInfo) *ResolutionContext ctx := &ResolutionContext{ resolution: res, docinfo: di, + docrefs: newDocRefs(), ids: scanner.Ids{}, callstack: scanner.NewCallStack(), - docrefs: map[utils2.Link]scanner.Document{}, numberranges: utils2.Set[string]{}, } ctx.scope = scanner.NewScope(res, res, ctx, di.document, "") @@ -351,7 +381,7 @@ func (r *ResolutionContext) GetParentDocument() scanner.Document { if p == nil { return nil } - return p.document + return p.docinfo.document } func (r *ResolutionContext) GetDocumentForLink(l utils2.Link) scanner.Document { @@ -373,13 +403,8 @@ func (c *ResolutionContext) RequestNumberRange(typ string) { c.numberranges.Add(typ) } -func (c *ResolutionContext) RequestDocument(link utils2.Link, d scanner.Document) error { - r := c.docrefs[link] - if r != nil { - return fmt.Errorf("document ref %q already requested by %s", link, d.GetRefPath()) - } - c.docrefs[link] = d - return nil +func (c *ResolutionContext) RequestDocument(link utils2.Link, loc scanner.Location) error { + return c.docrefs.Add(link, loc) } func (r *ResolutionContext) LookupTag(typ string, tag string) scanner.NodeContext { @@ -412,6 +437,10 @@ func (r *ResolutionContext) SetNumberRangeFor(d scanner.Document, id scanner.Tag return next.Current() } +func (r *ResolutionContext) GetRootContext() scanner.ResolutionContext { + return r.docinfo.rootinfo.docinfo.context +} + func (r *ResolutionContext) GetLabelInfosForType(typ string) map[labels.LabelId]scanner.TreeLabelInfo { result := map[labels.LabelId]scanner.TreeLabelInfo{} for _, id := range r.scope.GetIdsForType(typ) { @@ -438,7 +467,7 @@ func (r *ResolutionContext) appendIdsForType(typ string, result map[labels.Label result[id] = info } for _, di := range r.resolution.documents { - if di.structinfo != nil && di.structinfo.document == r.docinfo.document { + if di.structinfo != nil && di.structinfo.docinfo == r.docinfo { di.context.appendIdsForType(typ, result) } } diff --git a/tree/tree.go b/tree/tree.go index 41a5b12..04d98e3 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -152,35 +152,39 @@ func (t *tree) ResolveBlocks(res *Resolution) error { } func (t *tree) ResolveStructural(res *Resolution) error { + found := map[scanner.Document]*docref{} for _, di := range res.documents { - for l, d := range di.context.docrefs { + for l, ref := range di.context.docrefs.links { var target scanner.Document if l.IsTag() { ri := res.refindex[l] if ri == nil { - return fmt.Errorf("structural tag reference %q in %s cannot be resolved", l, d.Source()) + return fmt.Errorf("%s: structural tag reference %q cannot be resolved", ref.location, di.Source()) } target = ri.Context().GetDocument() } else { target = t.documents[l.Path()] if target == nil { - return fmt.Errorf("structural document reference %q in %s cannot be resolved", l, d.Source()) + return fmt.Errorf("%s: structural document reference %q cannot be resolved", ref.location, di.Source()) } } - di := res.documents[target.GetRefPath()] - if di.structinfo != nil { - return fmt.Errorf("duplicate structural usage of document %s: %s and %s", target.Source(), di.structinfo.document.Source(), d.Source()) + ti := res.documents[target.GetRefPath()] + if ti.structinfo != nil { + return fmt.Errorf("%s: duplicate structural usage of document %s: %s", ref.location, target.Source(), found[target].location) } - fmt.Printf("%s: found structural usage in %s\n", target.Source(), d.Source()) - found := false + fmt.Printf("%s: found structural usage in %s\n", target.Source(), di.Source()) + sect := false for _, n := range target.GetNodes() { if _, ok := n.(section.SectionNode); ok { - if found { - fmt.Printf("structural document %s used in %s may contain only one top level section\n", target.Source(), d.Source()) + if sect { + return fmt.Errorf("%s: structural document %s may contain only one top level section\n", ref.location, target.Source()) } + sect = true } } - di.structinfo = NewStructInfo(d) + ti.structinfo = NewStructInfo(di) + ref.docinfo = ti + found[target] = ref } } return nil @@ -188,11 +192,19 @@ func (t *tree) ResolveStructural(res *Resolution) error { func (t *tree) ResolveNumberRanges(res *Resolution) error { for _, di := range res.documents { - err := t.resolveNumberRanges(res, di, utils.History{}) + err := t.resolveDocumentOrder(res, di, utils.History{}) if err != nil { return err } } + for _, di := range res.documents { + if di.IsRoot() { + err := t.resolveNumberRanges(di) + if err != nil { + return err + } + } + } for _, di := range res.documents { if di.IsRoot() { @@ -205,6 +217,33 @@ func (t *tree) ResolveNumberRanges(res *Resolution) error { return nil } +func (t *tree) resolveDocumentOrder(res *Resolution, di *DocumentInfo, hist utils.History) error { + if di.rootinfo != nil { + return nil + } + + hist, cycle := hist.Add(di.Source()) + if cycle != nil { + return fmt.Errorf("structural cycle %s", hist) + } + + var root *RootInfo + master := di.structinfo + if master != nil { + err := t.resolveDocumentOrder(res, res.documents[master.docinfo.GetRefPath()], hist) + if err != nil { + return err + } + root = res.documents[master.docinfo.GetRefPath()].rootinfo + fmt.Printf("%s: sub structure for %s\n", di.Source(), root.docinfo.Source()) + } else { + fmt.Printf("%s: root document\n", di.Source()) + root = NewRootInfo(di) + } + di.rootinfo = root + return nil +} + func (t *tree) resolveLabels(di *DocumentInfo, nr *NumberRangeInfo, hist utils.History, resolved map[string]bool) error { if resolved[nr.Type()] { return nil @@ -229,30 +268,8 @@ func (t *tree) resolveLabels(di *DocumentInfo, nr *NumberRangeInfo, hist utils.H return nil } -func (t *tree) resolveNumberRanges(res *Resolution, di *DocumentInfo, hist utils.History) error { - if di.rootinfo != nil { - return nil - } - - hist, cycle := hist.Add(di.Source()) - if cycle != nil { - return fmt.Errorf("structural cycle %s", hist) - } - - var root *RootInfo - master := di.structinfo - if master != nil { - err := t.resolveNumberRanges(res, res.documents[master.document.GetRefPath()], hist) - if err != nil { - return err - } - root = res.documents[master.document.GetRefPath()].rootinfo - fmt.Printf("%s: sub structure for %s\n", di.Source(), root.document.Source()) - } else { - fmt.Printf("%s: root document\n", di.Source()) - root = NewRootInfo(di.document) - } - +func (t *tree) resolveNumberRanges(di *DocumentInfo) error { + root := di.rootinfo fmt.Printf("%s: found numberranges: %s\n", di.Source(), strings.Join(utils.SortedMapKeys(di.context.numberranges), ", ")) rules := di.document.GetLabelRules() for typ := range di.context.numberranges { @@ -318,8 +335,6 @@ func (t *tree) resolveNumberRanges(res *Resolution, di *DocumentInfo, hist utils } } - di.rootinfo = root - for _, nr := range root.ranges { err := checkCycle(di, nr, nil) if err != nil { @@ -327,7 +342,18 @@ func (t *tree) resolveNumberRanges(res *Resolution, di *DocumentInfo, hist utils } } fmt.Printf(" resolve %s\n", di.GetRefPath()) - return di.Walk(scanner.Resolve[scanner.LabelResolver](di.context)) + err := di.Walk(scanner.Resolve[scanner.LabelResolver](di.context)) + if err != nil { + return err + } + + for _, ref := range di.context.docrefs.order { + err := t.resolveNumberRanges(ref.docinfo) + if err != nil { + return err + } + } + return nil } func checkCycle(di *DocumentInfo, nr *NumberRangeInfo, hist utils.History) error {