Golang Template source code analysis(Parse)
阿新 • • 發佈:2017-07-22
def oot string sse new eml comm strings []
It mainly has three steps,the first is allow template,the second is tmpl.Parse,the third is tmpl.Execute(os.Stdout, name),the first step is simple.This blog introduces the second step.
followed function produce t.Root list thought nextNonSpace bring value to
To be continued
This blog was written at go 1.3.1 version.
We know that we use template thought by followed way:
func main() { name := "waynehu" tmpl := template.New("test") tmpl, err := tmpl.Parse("hello {{.}}") if err != nil { panic(err) } err = tmpl.Execute(os.Stdout, name) if err != nil { panic(err) } }
- Major Class
The ListNode struct:
// ListNode holds a sequence of nodes. type ListNode struct { NodeType Pos Nodes []Node // The element nodes in lexical order. }The "NodeType" and "Pos" is as same as int.
- Sequence Diagram
- The key of parts of code
// lex creates a new scanner for the input string. func lex(name, input, left, right string) *lexer { if left == "" { left = leftDelim } if right == "" { right = rightDelim } l := &lexer{ name: name, input: input, leftDelim: left, rightDelim: right, items: make(chan item), } go l.run() return l }
// run runs the state machine for the lexer. func (l *lexer) run() { for l.state = lexText; l.state != nil; { l.state = l.state(l) } }
l.emit(itemText) is handle static text information and lexLeftDelim is handle dynamic information.
// lexText scans until an opening action delimiter, "{{". func lexText(l *lexer) stateFn { for { if strings.HasPrefix(l.input[l.pos:], l.leftDelim) { if l.pos > l.start { l.emit(itemText) } return lexLeftDelim } if l.next() == eof { break } } // Correctly reached EOF. if l.pos > l.start { l.emit(itemText) } l.emit(itemEOF) return nil }
lexComment is hande comment without analysis
// lexLeftDelim scans the left delimiter, which is known to be present. func lexLeftDelim(l *lexer) stateFn { l.pos += Pos(len(l.leftDelim)) if strings.HasPrefix(l.input[l.pos:], leftComment) { return lexComment } l.emit(itemLeftDelim) l.parenDepth = 0 return lexInsideAction }
any syntax parsing are transmited by "chan item" is a channel.and take away it thought func (l *lexer) nextItem() item function.
put value in emit function.
// emit passes an item back to the client. func (l *lexer) emit(t itemType) { l.items <- item{t, l.start, l.input[l.start:l.pos]} l.start = l.pos }
followed function produce t.Root list thought nextNonSpace bring value to
// 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) { t.Root = newList(t.peek().pos) for t.peek().typ != itemEOF { if t.peek().typ == itemLeftDelim { delim := t.next() if t.nextNonSpace().typ == itemDefine { 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) continue } t.backup2(delim) } n := t.textOrAction() if n.Type() == nodeEnd { t.errorf("unexpected %s", n) } t.Root.append(n) } return nil }
// nextNonSpace returns the next non-space token. func (t *Tree) nextNonSpace() (token item) { for { token = t.next() if token.typ != itemSpace { break } } return token }
take away item in nextItem function
// nextItem returns the next item from the input. func (l *lexer) nextItem() item { item := <-l.items l.lastPos = item.pos return item }
To be continued
Golang Template source code analysis(Parse)