@@ -12,8 +12,11 @@ import (
12
12
13
13
// common holds the information shared by related templates.
14
14
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
17
20
option option
18
21
// We use two maps, one for parsing and one for execution.
19
22
// This separation makes the API cleaner since it doesn't
@@ -91,14 +94,14 @@ func (t *Template) Clone() (*Template, error) {
91
94
}
92
95
t .muTmpl .RLock ()
93
96
defer t .muTmpl .RUnlock ()
94
- for k , stack := range t .tmpl {
97
+ for k , generations := range t .tmpl {
95
98
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 )
97
100
continue
98
101
}
99
102
// 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 )
102
105
nt .tmpl [k ] = append (nt .tmpl [k ], tmpl )
103
106
}
104
107
}
@@ -152,8 +155,8 @@ func (t *Template) Templates() []*Template {
152
155
t .muTmpl .RLock ()
153
156
defer t .muTmpl .RUnlock ()
154
157
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 ])
157
160
}
158
161
return m
159
162
}
@@ -196,20 +199,20 @@ func (t *Template) Lookup(name string) *Template {
196
199
return t .lookup (name , 0 )
197
200
}
198
201
199
- func (t * Template ) LookupWithScope (name string , scope int ) * Template {
202
+ func (t * Template ) LookupByLevel (name string , level int ) * Template {
200
203
if t .common == nil {
201
204
return nil
202
205
}
203
206
t .muTmpl .RLock ()
204
207
defer t .muTmpl .RUnlock ()
205
- return t .lookup (name , scope )
208
+ return t .lookup (name , level )
206
209
}
207
210
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 ]) {
210
213
return nil
211
214
}
212
- return t.tmpl [name ][scope ] // TODO: invariant check: at least one
215
+ return t.tmpl [name ][level ]
213
216
}
214
217
215
218
// Parse parses text as a template body for t.
@@ -251,10 +254,17 @@ func (t *Template) associate(new *Template, tree *parse.Tree) bool {
251
254
// don't replace it with an empty template.
252
255
return false
253
256
}
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
+
259
269
return true
260
270
}
0 commit comments