Source File
parse.go
Belonging Package
text/template/parse
package parse
import (
)
type Mode uint
const (
ParseComments Mode = 1 << iota // parse comments and add them to AST
)
func ( *Tree) () item {
:= .nextNonSpace()
.backup()
return
}
func ( *Tree) ( itemType, string) item {
:= .nextNonSpace()
if .typ != {
.unexpected(, )
}
return
}
func ( *Tree) (, itemType, string) item {
:= .nextNonSpace()
if .typ != && .typ != {
.unexpected(, )
}
return
}
func ( *Tree) ( item, string) {
if .typ == itemError {
:= ""
if .actionLine != 0 && .actionLine != .line {
= fmt.Sprintf(" in action started at %s:%d", .ParseName, .actionLine)
if strings.HasSuffix(.val, " action") {
= [len(" in action"):] // avoid "action in action"
}
}
.errorf("%s%s", , )
}
.errorf("unexpected %s in %s", , )
}
func ( Node) bool {
switch n := .(type) {
case nil:
return true
case *ActionNode:
case *CommentNode:
return true
case *IfNode:
case *ListNode:
for , := range .Nodes {
if !() {
return false
}
}
return true
case *RangeNode:
case *TemplateNode:
case *TextNode:
return len(bytes.TrimSpace(.Text)) == 0
case *WithNode:
default:
panic("unknown node: " + .String())
}
return false
}
func ( *Tree) () {
.Root = .newList(.peek().pos)
for .peek().typ != itemEOF {
if .peek().typ == itemLeftDelim {
:= .next()
if .nextNonSpace().typ == itemDefine {
:= New("definition") // name will be updated once we know it.
.text = .text
.Mode = .Mode
.ParseName = .ParseName
.startParse(.funcs, .lex, .treeSet)
.parseDefinition()
continue
}
.backup2()
}
switch := .textOrAction(); .Type() {
case nodeEnd, nodeElse:
.errorf("unexpected %s", )
default:
.Root.append()
}
}
}
func ( *Tree) () ( *ListNode, Node) {
= .newList(.peekNonSpace().pos)
for .peekNonSpace().typ != itemEOF {
:= .textOrAction()
switch .Type() {
case nodeEnd, nodeElse:
return ,
}
.append()
}
.errorf("unexpected EOF")
return
}
func ( *Tree) () Node {
switch := .nextNonSpace(); .typ {
case itemText:
return .newText(.pos, .val)
case itemLeftDelim:
.actionLine = .line
defer .clearActionLine()
return .action()
case itemComment:
return .newComment(.pos, .val)
default:
.unexpected(, "input")
}
return nil
}
func ( *Tree) () {
.actionLine = 0
}
func ( *Tree) () ( Node) {
switch := .nextNonSpace(); .typ {
case itemBlock:
return .blockControl()
case itemElse:
return .elseControl()
case itemEnd:
return .endControl()
case itemIf:
return .ifControl()
case itemRange:
return .rangeControl()
case itemTemplate:
return .templateControl()
case itemWith:
return .withControl()
}
.backup()
return .newAction(.pos, .line, .pipeline("command", itemRightDelim))
}
func ( *Tree) ( string, itemType) ( *PipeNode) {
:= .peekNonSpace()
:
if := .peekNonSpace(); .typ == itemVariable {
:= .peek()
:= .peekNonSpace()
switch {
case .typ == itemAssign, .typ == itemDeclare:
.IsAssign = .typ == itemAssign
.nextNonSpace()
.Decl = append(.Decl, .newVariable(.pos, .val))
.vars = append(.vars, .val)
case .typ == itemChar && .val == ",":
.nextNonSpace()
.Decl = append(.Decl, .newVariable(.pos, .val))
.vars = append(.vars, .val)
if == "range" && len(.Decl) < 2 {
switch .peekNonSpace().typ {
.checkPipeline(, )
return
case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen:
.backup()
.append(.command())
default:
.unexpected(, )
}
}
}
func ( *Tree) () Node {
return .newIf(.parseControl(true, "if"))
}
func ( *Tree) () Node {
return .newRange(.parseControl(false, "range"))
}
func ( *Tree) () Node {
return .newWith(.parseControl(false, "with"))
}
:= .peekNonSpace()
func ( *Tree) () Node {
const = "block clause"
:= .nextNonSpace()
:= .parseTemplateName(, )
:= .pipeline(, itemRightDelim)
:= New() // name will be updated once we know it.
.text = .text
.Mode = .Mode
.ParseName = .ParseName
.startParse(.funcs, .lex, .treeSet)
var Node
.Root, = .itemList()
if .Type() != nodeEnd {
.errorf("unexpected %s in %s", , )
}
.add()
.stopParse()
return .newTemplate(.pos, .line, , )
}
func ( *Tree) () Node {
const = "template clause"
:= .nextNonSpace()
:= .parseTemplateName(, )
var *PipeNode
if .nextNonSpace().typ != itemRightDelim {
= .pipeline(, itemRightDelim)
}
return .newTemplate(.pos, .line, , )
}
func ( *Tree) ( item, string) ( string) {
switch .typ {
case itemString, itemRawString:
, := strconv.Unquote(.val)
if != nil {
.error()
}
=
default:
.unexpected(, )
}
return
}
func ( *Tree) () *CommandNode {
:= .newCommand(.peekNonSpace().pos)
for {
.peekNonSpace() // skip leading spaces.
:= .operand()
if != nil {
.append()
}
switch := .next(); .typ {
case itemSpace:
continue
case itemRightDelim, itemRightParen:
.backup()
default:
.unexpected(, "operand")
}
break
}
if len(.Args) == 0 {
.errorf("empty command")
}
return
}
switch .Type() {
case NodeField:
= .newField(.Position(), .String())
case NodeVariable:
= .newVariable(.Position(), .String())
case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
.errorf("unexpected . after term %q", .String())
default:
=
}
}
return
}
func ( *Tree) () Node {
switch := .nextNonSpace(); .typ {
case itemIdentifier:
if !.hasFunction(.val) {
.errorf("function %q not defined", .val)
}
return NewIdentifier(.val).SetTree().SetPos(.pos)
case itemDot:
return .newDot(.pos)
case itemNil:
return .newNil(.pos)
case itemVariable:
return .useVar(.pos, .val)
case itemField:
return .newField(.pos, .val)
case itemBool:
return .newBool(.pos, .val == "true")
case itemCharConstant, itemComplex, itemNumber:
, := .newNumber(.pos, .val, .typ)
if != nil {
.error()
}
return
case itemLeftParen:
return .pipeline("parenthesized pipeline", itemRightParen)
case itemString, itemRawString:
, := strconv.Unquote(.val)
if != nil {
.error()
}
return .newString(.pos, .val, )
}
.backup()
return nil
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |