• Golang Template source code analysis(Parse)



        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)
    	}
    }
        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.

    •     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

  • 相关阅读:
    UnixTime的时间戳的转换
    dotnet cors 跨域问题
    sqlServer备份和还原语句
    mvc的生命周期
    Java序列化
    js 分页
    jquery js 分页
    Myeclipse 6.0代码
    前序遍历_中序遍历_后序遍历
    数组去重的一些方法以及数组排序
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7220658.html
Copyright © 2020-2023  润新知