One reference draw per render in both views: a repeat iteration draws anew, a group option draws apart, and one fence refuses what a render's draws cannot answer for
Tests / vet + fmt + tests (pull_request) Successful in 1m6s
Tests / vet + fmt + tests (pull_request) Successful in 1m6s
This commit is contained in:
@@ -27,7 +27,7 @@ func (f *Generator) Fake(path string) (string, error) {
|
||||
if _, ok := n.(*group); ok {
|
||||
return "", fmt.Errorf("fejkdata: %s names a folder, not a value", path)
|
||||
}
|
||||
return render(f.rand, n, nil), nil
|
||||
return renderOnce(f.rand, n), nil
|
||||
}
|
||||
|
||||
// descend walks named fields to the node a path names. It is the one render-side
|
||||
@@ -50,20 +50,21 @@ func descend(s *session, root node, segments []string) (node, error) {
|
||||
}
|
||||
|
||||
// render evaluates a compiled node to a string. compile validates every node up
|
||||
// front, so rendering a compiled tree cannot fail. refScope carries the draws a
|
||||
// reference shares beyond its own expansion; nil keeps every reference local.
|
||||
func render(s *session, n node, refScope *draws) string {
|
||||
// front, so rendering a compiled tree cannot fail. sc holds the reference draws the
|
||||
// render shares; each repeat iteration renders over draws of its own.
|
||||
func render(s *session, n node, sc drawScope) string {
|
||||
switch n := n.(type) {
|
||||
case *choice:
|
||||
return render(s, pick(s, n), refScope)
|
||||
return render(s, pick(s, n), sc)
|
||||
case *null:
|
||||
return ""
|
||||
case *template:
|
||||
sc = sc.in(n)
|
||||
if n.repeat == 1 {
|
||||
if n.fixed {
|
||||
return n.lit
|
||||
}
|
||||
return expand(s, n, refScope)
|
||||
return expand(s, n, sc)
|
||||
}
|
||||
var b strings.Builder
|
||||
b.Grow(n.repeat * (n.grow + len(n.separator)))
|
||||
@@ -71,7 +72,7 @@ func render(s *session, n node, refScope *draws) string {
|
||||
if i > 0 {
|
||||
b.WriteString(n.separator)
|
||||
}
|
||||
b.WriteString(expand(s, n, refScope))
|
||||
b.WriteString(expandAnew(s, n, sc.group))
|
||||
}
|
||||
return b.String()
|
||||
default:
|
||||
@@ -79,6 +80,15 @@ func render(s *session, n node, refScope *draws) string {
|
||||
}
|
||||
}
|
||||
|
||||
// expandAnew expands one repeat iteration of t as a render of its own, in group. Inlined into
|
||||
// render's loop, its draw set would move to the heap.
|
||||
//
|
||||
//go:noinline
|
||||
func expandAnew(s *session, t *template, group string) string {
|
||||
var set drawSet
|
||||
return expand(s, t, drawScope{set: &set, group: group})
|
||||
}
|
||||
|
||||
// pick selects one item. Uniform choices are O(1); weighted choices are an
|
||||
// O(log n) search over precomputed cumulative weights. compile guarantees a
|
||||
// non-empty choice and a finite positive total, so the index is always in range.
|
||||
@@ -93,12 +103,12 @@ func pick(r rng, c *choice) node {
|
||||
|
||||
// expand renders a template's compiled ops. compile validated every token, so this
|
||||
// cannot fail.
|
||||
func expand(s *session, t *template, refScope *draws) string {
|
||||
func expand(s *session, t *template, sc drawScope) string {
|
||||
var b strings.Builder
|
||||
b.Grow(t.grow)
|
||||
// One draw per held name, for this expansion only: a nested template and each
|
||||
// repeat iteration get their own, since each is its own expansion. A reference
|
||||
// reads the caller's scope instead, whenever one was supplied.
|
||||
// path reads the render's draws in sc instead.
|
||||
var held *draws
|
||||
if len(t.held) > 0 {
|
||||
held = &draws{
|
||||
@@ -112,7 +122,7 @@ func expand(s *session, t *template, refScope *draws) string {
|
||||
case 'l':
|
||||
b.WriteString(o.lit)
|
||||
case 'f':
|
||||
b.WriteString(readField(s, t, held, refScope, o.arms[s.IntN(len(o.arms))]).text)
|
||||
b.WriteString(readField(s, t, held, sc, o.arms[s.IntN(len(o.arms))]).text)
|
||||
case 'b':
|
||||
// Read before the call, so the value a calc computes is the value the
|
||||
// format showed. calcVars fixed the order op.operands holds.
|
||||
@@ -120,7 +130,7 @@ func expand(s *session, t *template, refScope *draws) string {
|
||||
if len(o.operands) > 0 {
|
||||
operands = make([]string, len(o.operands))
|
||||
for j, a := range o.operands {
|
||||
operands[j] = readField(s, t, held, refScope, a).text
|
||||
operands[j] = readField(s, t, held, sc, a).text
|
||||
}
|
||||
}
|
||||
b.WriteString(o.call(s, b.String(), operands)) // b.String() is the output so far
|
||||
|
||||
Reference in New Issue
Block a user