diff options
Diffstat (limited to 'libgo/go/text/template/parse/parse.go')
-rw-r--r-- | libgo/go/text/template/parse/parse.go | 83 |
1 files changed, 60 insertions, 23 deletions
diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go index 88aacd1..dc56cf7 100644 --- a/libgo/go/text/template/parse/parse.go +++ b/libgo/go/text/template/parse/parse.go @@ -28,6 +28,7 @@ type Tree struct { token [3]item // three-token lookahead for parser. peekCount int vars []string // variables defined at the moment. + treeSet map[string]*Tree } // Copy returns a copy of the Tree. Any parsing state is discarded. @@ -205,11 +206,12 @@ func (t *Tree) recover(errp *error) { } // startParse initializes the parser, using the lexer. -func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) { +func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet map[string]*Tree) { t.Root = nil t.lex = lex t.vars = []string{"$"} t.funcs = funcs + t.treeSet = treeSet } // stopParse terminates parsing. @@ -217,6 +219,7 @@ func (t *Tree) stopParse() { t.lex = nil t.vars = nil t.funcs = nil + t.treeSet = nil } // Parse parses the template definition string to construct a representation of @@ -226,19 +229,19 @@ func (t *Tree) stopParse() { func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) { defer t.recover(&err) t.ParseName = t.Name - t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim)) + t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim), treeSet) t.text = text - t.parse(treeSet) - t.add(treeSet) + t.parse() + t.add() t.stopParse() return t, nil } -// add adds tree to the treeSet. -func (t *Tree) add(treeSet map[string]*Tree) { - tree := treeSet[t.Name] +// add adds tree to t.treeSet. +func (t *Tree) add() { + tree := t.treeSet[t.Name] if tree == nil || IsEmptyTree(tree.Root) { - treeSet[t.Name] = t + t.treeSet[t.Name] = t return } if !IsEmptyTree(t.Root) { @@ -274,7 +277,7 @@ func IsEmptyTree(n Node) bool { // parse is the top-level parser for a template, essentially the same // as itemList except it also parses {{define}} actions. // It runs to EOF. -func (t *Tree) parse(treeSet map[string]*Tree) (next Node) { +func (t *Tree) parse() (next Node) { t.Root = t.newList(t.peek().pos) for t.peek().typ != itemEOF { if t.peek().typ == itemLeftDelim { @@ -283,8 +286,8 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) { newT := New("definition") // name will be updated once we know it. newT.text = t.text newT.ParseName = t.ParseName - newT.startParse(t.funcs, t.lex) - newT.parseDefinition(treeSet) + newT.startParse(t.funcs, t.lex, t.treeSet) + newT.parseDefinition() continue } t.backup2(delim) @@ -300,9 +303,9 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) { } // parseDefinition parses a {{define}} ... {{end}} template definition and -// installs the definition in the treeSet map. The "define" keyword has already +// installs the definition in t.treeSet. The "define" keyword has already // been scanned. -func (t *Tree) parseDefinition(treeSet map[string]*Tree) { +func (t *Tree) parseDefinition() { const context = "define clause" name := t.expectOneOf(itemString, itemRawString, context) var err error @@ -316,7 +319,7 @@ func (t *Tree) parseDefinition(treeSet map[string]*Tree) { if end.Type() != nodeEnd { t.errorf("unexpected %s in %s", end, context) } - t.add(treeSet) + t.add() t.stopParse() } @@ -358,6 +361,8 @@ func (t *Tree) textOrAction() Node { // First word could be a keyword such as range. func (t *Tree) action() (n Node) { switch token := t.nextNonSpace(); token.typ { + case itemBlock: + return t.blockControl() case itemElse: return t.elseControl() case itemEnd: @@ -522,13 +527,51 @@ func (t *Tree) elseControl() Node { return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber()) } +// Block: +// {{block stringValue pipeline}} +// Block keyword is past. +// The name must be something that can evaluate to a string. +// The pipeline is mandatory. +func (t *Tree) blockControl() Node { + const context = "block clause" + + token := t.nextNonSpace() + name := t.parseTemplateName(token, context) + pipe := t.pipeline(context) + + block := New(name) // name will be updated once we know it. + block.text = t.text + block.ParseName = t.ParseName + block.startParse(t.funcs, t.lex, t.treeSet) + var end Node + block.Root, end = block.itemList() + if end.Type() != nodeEnd { + t.errorf("unexpected %s in %s", end, context) + } + block.add() + block.stopParse() + + return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) +} + // Template: // {{template stringValue pipeline}} // Template keyword is past. The name must be something that can evaluate // to a string. func (t *Tree) templateControl() Node { - var name string + const context = "template clause" token := t.nextNonSpace() + name := t.parseTemplateName(token, context) + var pipe *PipeNode + if t.nextNonSpace().typ != itemRightDelim { + t.backup() + // Do not pop variables; they persist until "end". + pipe = t.pipeline(context) + } + return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) +} + +func (t *Tree) parseTemplateName(token item, context string) (name string) { switch token.typ { case itemString, itemRawString: s, err := strconv.Unquote(token.val) @@ -537,15 +580,9 @@ func (t *Tree) templateControl() Node { } name = s default: - t.unexpected(token, "template invocation") - } - var pipe *PipeNode - if t.nextNonSpace().typ != itemRightDelim { - t.backup() - // Do not pop variables; they persist until "end". - pipe = t.pipeline("template") + t.unexpected(token, context) } - return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) + return } // command: |