Skip to content

Commit 1dd4a22

Browse files
committed
Clean up some notes and refer to generations instead of stack
1 parent 5519c27 commit 1dd4a22

File tree

3 files changed

+42
-31
lines changed

3 files changed

+42
-31
lines changed

src/text/template/exec.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ func initMaxExecDepth() int {
3333
type state struct {
3434
tmpl *Template
3535
wr io.Writer
36-
node parse.Node // current node, for errors
37-
vars []variable // push-down stack of variable values.
38-
depth int // the height of the stack of executing templates.
39-
scope map[string]int
36+
node parse.Node // current node, for errors
37+
vars []variable // push-down stack of variable values.
38+
depth int // the height of the stack of executing templates.
39+
level map[string]int // map from template name to current level.
4040
}
4141

4242
// variable holds the dynamic value of a variable such as $, $x etc.
@@ -211,7 +211,7 @@ func (t *Template) execute(wr io.Writer, data interface{}) (err error) {
211211
tmpl: t,
212212
wr: wr,
213213
vars: []variable{{"$", value}},
214-
scope: make(map[string]int),
214+
level: make(map[string]int),
215215
}
216216
if t.Tree == nil || t.Root == nil {
217217
state.errorf("%q is an incomplete or empty template", t.Name())
@@ -403,12 +403,12 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
403403

404404
func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
405405
s.at(t)
406-
scope := s.scope[t.Name]
406+
level := s.level[t.Name]
407407
if t.Parent {
408-
scope++
408+
level++
409409
}
410-
s.scope[t.Name] = scope
411-
tmpl := s.tmpl.LookupWithScope(t.Name, scope)
410+
s.level[t.Name] = level
411+
tmpl := s.tmpl.LookupByLevel(t.Name, level)
412412
if tmpl == nil {
413413
s.errorf("template %q not defined", t.Name)
414414
}
@@ -423,11 +423,11 @@ func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
423423
// No dynamic scoping: template invocations inherit no variables.
424424
newState.vars = []variable{{"$", dot}}
425425
newState.walk(dot, tmpl.Root)
426-
scope--
427-
if scope < 0 { // TODO logical bug
428-
scope = 0
426+
level--
427+
if level < 0 {
428+
level = 0 // TODO: this could be masking a bug
429429
}
430-
newState.scope[t.Name] = scope // TODO: unclear if this makes sense here
430+
newState.level[t.Name] = level
431431
}
432432

433433
// Eval functions evaluate pipelines, commands, and their elements and extract

src/text/template/parse/lex_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var itemName = map[itemType]string{
4040
itemIf: "if",
4141
itemEnd: "end",
4242
itemNil: "nil",
43+
itemParent: "parent",
4344
itemRange: "range",
4445
itemTemplate: "template",
4546
itemWith: "with",

src/text/template/template.go

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ import (
1212

1313
// common holds the information shared by related templates.
1414
type common struct {
15-
tmpl map[string][]*Template // Map from name to defined templates.
16-
muTmpl sync.RWMutex // protects tmpl
15+
// Map from name to defined templates. There is a slice of templates,
16+
// because there are generations of previously defined templates with the
17+
// same name.
18+
tmpl map[string][]*Template
19+
muTmpl sync.RWMutex // protects tmpl
1720
option option
1821
// We use two maps, one for parsing and one for execution.
1922
// This separation makes the API cleaner since it doesn't
@@ -91,14 +94,14 @@ func (t *Template) Clone() (*Template, error) {
9194
}
9295
t.muTmpl.RLock()
9396
defer t.muTmpl.RUnlock()
94-
for k, stack := range t.tmpl {
97+
for k, generations := range t.tmpl {
9598
if k == t.name {
96-
nt.tmpl[t.name] = append(nt.tmpl[t.name], nt) // TODO: double-check this - maybe should just be assigning new slice
99+
nt.tmpl[t.name] = append(nt.tmpl[t.name], nt)
97100
continue
98101
}
99102
// The associated templates share nt's common structure.
100-
for i := range stack {
101-
tmpl := stack[i].copy(nt.common)
103+
for i := range generations {
104+
tmpl := generations[i].copy(nt.common)
102105
nt.tmpl[k] = append(nt.tmpl[k], tmpl)
103106
}
104107
}
@@ -152,8 +155,8 @@ func (t *Template) Templates() []*Template {
152155
t.muTmpl.RLock()
153156
defer t.muTmpl.RUnlock()
154157
m := make([]*Template, 0, len(t.tmpl))
155-
for _, stack := range t.tmpl {
156-
m = append(m, stack[0]) // TODO: runtime assert there is at least one? invariant check
158+
for _, generations := range t.tmpl {
159+
m = append(m, generations[0])
157160
}
158161
return m
159162
}
@@ -196,20 +199,20 @@ func (t *Template) Lookup(name string) *Template {
196199
return t.lookup(name, 0)
197200
}
198201

199-
func (t *Template) LookupWithScope(name string, scope int) *Template {
202+
func (t *Template) LookupByLevel(name string, level int) *Template {
200203
if t.common == nil {
201204
return nil
202205
}
203206
t.muTmpl.RLock()
204207
defer t.muTmpl.RUnlock()
205-
return t.lookup(name, scope)
208+
return t.lookup(name, level)
206209
}
207210

208-
func (t *Template) lookup(name string, scope int) *Template {
209-
if scope >= len(t.tmpl[name]) {
211+
func (t *Template) lookup(name string, level int) *Template {
212+
if level < 0 || level >= len(t.tmpl[name]) {
210213
return nil
211214
}
212-
return t.tmpl[name][scope] // TODO: invariant check: at least one
215+
return t.tmpl[name][level]
213216
}
214217

215218
// Parse parses text as a template body for t.
@@ -251,10 +254,17 @@ func (t *Template) associate(new *Template, tree *parse.Tree) bool {
251254
// don't replace it with an empty template.
252255
return false
253256
}
254-
stack := t.tmpl[new.name]
255-
stack = append(stack, nil)
256-
copy(stack[1:], stack[0:])
257-
stack[0] = new
258-
t.tmpl[new.name] = stack
257+
258+
// associating a template with the name of an existing one retains a
259+
// reference to the original, pushing the new one to the front of a slice
260+
// of previously defined templates, so that previously defined templates by
261+
// that name can be accessed by indexing into the slice, each successive
262+
// level being an older generation.
263+
generations := t.tmpl[new.name]
264+
generations = append(generations, nil)
265+
copy(generations[1:], generations[0:])
266+
generations[0] = new
267+
t.tmpl[new.name] = generations
268+
259269
return true
260270
}

0 commit comments

Comments
 (0)