From bd3b2f843fc4ee1ba311036b0ebba255bc7b0e82 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 27 Apr 2009 21:04:46 -0700 Subject: [PATCH] implement .alternates R=rsc OCL=27928 CL=27928 --- src/lib/template/template.go | 30 ++++++++++++++++++++++++++---- src/lib/template/template_test.go | 14 ++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/lib/template/template.go b/src/lib/template/template.go index 1676a8fdde..c6957d4de5 100644 --- a/src/lib/template/template.go +++ b/src/lib/template/template.go @@ -36,7 +36,6 @@ is executed for each element. If the array is nil or empty, YYY is executed instead. If the {.alternates with} marker is present, ZZZ is executed between iterations of XXX. - (TODO(r): .alternates is not yet implemented) {field} {field|formatter} @@ -132,9 +131,11 @@ type sectionElement struct { end int; // one beyond last element } -// A .repeated block, possibly with a .or. TODO(r): .alternates +// A .repeated block, possibly with a .or and a .alternates type repeatedElement struct { - sectionElement; // It has the same structure! + sectionElement; // It has the same structure... + altstart int; // ... except for alternates + altend int; } // Template is the type that represents a template definition. @@ -438,6 +439,8 @@ func (t *Template) parseRepeated(words []string) *repeatedElement { // Scan section, collecting true and false (.or) blocks. r.start = t.elems.Len(); r.or = -1; + r.altstart = -1; + r.altend = -1; Loop: for { item := t.nextItem(); @@ -455,17 +458,27 @@ Loop: if r.or >= 0 { t.parseError("extra .or in .repeated section"); } + r.altend = t.elems.Len(); r.or = t.elems.Len(); case tokSection: t.parseSection(w); case tokRepeated: t.parseRepeated(w); case tokAlternates: - t.parseError("internal error: .alternates not implemented"); + if r.altstart >= 0 { + t.parseError("extra .alternates in .repeated section"); + } + if r.or >= 0 { + t.parseError(".alternates inside .or block in .repeated section"); + } + r.altstart = t.elems.Len(); default: t.parseError("internal error: unknown repeated section item: %s", item); } } + if r.altend < 0 { + r.altend = t.elems.Len() + } r.end = t.elems.Len(); return r; } @@ -693,6 +706,9 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) { if end < 0 { end = r.end } + if r.altstart >= 0 { + end = r.altstart + } if field != nil { array := field.(reflect.ArrayValue); for j := 0; j < array.Len(); j++ { @@ -700,6 +716,12 @@ func (t *Template) executeRepeated(r *repeatedElement, st *state) { for i := start; i < end; { i = t.executeElement(i, newst) } + // If appropriate, do .alternates between elements + if j < array.Len() - 1 && r.altstart >= 0 { + for i := r.altstart; i < r.altend; i++ { + i = t.executeElement(i, newst) + } + } } } } diff --git a/src/lib/template/template_test.go b/src/lib/template/template_test.go index cacc4404fa..fb931615ea 100644 --- a/src/lib/template/template_test.go +++ b/src/lib/template/template_test.go @@ -183,6 +183,20 @@ var tests = []*Test { "this should appear: empty field\n" }, + &Test{ + "{.section pdata }\n" + "{.repeated section @ }\n" + "{item}={value}\n" + "{.alternates with}DIVIDER\n" + "{.or}\n" + "this should not appear\n" + "{.end}\n" + "{.end}\n", + + "ItemNumber1=ValueNumber1\n" + "DIVIDER\n" + "ItemNumber2=ValueNumber2\n" + }, // Formatters &Test{ -- 2.48.1