Source File
node.go
Belonging Package
text/template/parse
package parse
import (
)
var textFormat = "%s" // Changed to "%q" in tests for better error messages.
Copy() Node
func ( NodeType) () NodeType {
return
}
const (
NodeText NodeType = iota // Plain text.
NodeAction // A non-control action such as a field evaluation.
NodeBool // A boolean constant.
NodeChain // A sequence of field accesses.
NodeCommand // An element of a pipeline.
NodeDot // The cursor, dot.
nodeElse // An else action. Not added to tree.
nodeEnd // An end action. Not added to tree.
NodeField // A field or method name.
NodeIdentifier // An identifier; always a function name.
NodeIf // An if action.
NodeList // A list of Nodes.
NodeNil // An untyped nil constant.
NodeNumber // A numerical constant.
NodePipe // A pipeline of commands.
NodeRange // A range action.
NodeString // A string constant.
NodeTemplate // A template invocation action.
NodeVariable // A $ variable.
NodeWith // A with action.
NodeComment // A comment.
)
type ListNode struct {
NodeType
Pos
tr *Tree
Nodes []Node // The element nodes in lexical order.
}
func ( *Tree) ( Pos) *ListNode {
return &ListNode{tr: , NodeType: NodeList, Pos: }
}
func ( *ListNode) ( Node) {
.Nodes = append(.Nodes, )
}
func ( *ListNode) () *Tree {
return .tr
}
func ( *ListNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *ListNode) ( *strings.Builder) {
for , := range .Nodes {
.writeTo()
}
}
func ( *ListNode) () *ListNode {
if == nil {
return
}
:= .tr.newList(.Pos)
for , := range .Nodes {
.append(.Copy())
}
return
}
func ( *ListNode) () Node {
return .CopyList()
}
type TextNode struct {
NodeType
Pos
tr *Tree
Text []byte // The text; may span newlines.
}
func ( *Tree) ( Pos, string) *TextNode {
return &TextNode{tr: , NodeType: NodeText, Pos: , Text: []byte()}
}
func ( *TextNode) () string {
return fmt.Sprintf(textFormat, .Text)
}
func ( *TextNode) ( *strings.Builder) {
.WriteString(.String())
}
func ( *TextNode) () *Tree {
return .tr
}
func ( *TextNode) () Node {
return &TextNode{tr: .tr, NodeType: NodeText, Pos: .Pos, Text: append([]byte{}, .Text...)}
}
type CommentNode struct {
NodeType
Pos
tr *Tree
Text string // Comment text.
}
func ( *Tree) ( Pos, string) *CommentNode {
return &CommentNode{tr: , NodeType: NodeComment, Pos: , Text: }
}
func ( *CommentNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *CommentNode) ( *strings.Builder) {
.WriteString("{{")
.WriteString(.Text)
.WriteString("}}")
}
func ( *CommentNode) () *Tree {
return .tr
}
func ( *CommentNode) () Node {
return &CommentNode{tr: .tr, NodeType: NodeComment, Pos: .Pos, Text: .Text}
}
type PipeNode struct {
NodeType
Pos
tr *Tree
Line int // The line number in the input. Deprecated: Kept for compatibility.
IsAssign bool // The variables are being assigned, not declared.
Decl []*VariableNode // Variables in lexical order.
Cmds []*CommandNode // The commands in lexical order.
}
func ( *Tree) ( Pos, int, []*VariableNode) *PipeNode {
return &PipeNode{tr: , NodeType: NodePipe, Pos: , Line: , Decl: }
}
func ( *PipeNode) ( *CommandNode) {
.Cmds = append(.Cmds, )
}
func ( *PipeNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *PipeNode) ( *strings.Builder) {
if len(.Decl) > 0 {
for , := range .Decl {
if > 0 {
.WriteString(", ")
}
.writeTo()
}
.WriteString(" := ")
}
for , := range .Cmds {
if > 0 {
.WriteString(" | ")
}
.writeTo()
}
}
func ( *PipeNode) () *Tree {
return .tr
}
func ( *PipeNode) () *PipeNode {
if == nil {
return
}
:= make([]*VariableNode, len(.Decl))
for , := range .Decl {
[] = .Copy().(*VariableNode)
}
:= .tr.newPipeline(.Pos, .Line, )
.IsAssign = .IsAssign
for , := range .Cmds {
.append(.Copy().(*CommandNode))
}
return
}
func ( *PipeNode) () Node {
return .CopyPipe()
}
type ActionNode struct {
NodeType
Pos
tr *Tree
Line int // The line number in the input. Deprecated: Kept for compatibility.
Pipe *PipeNode // The pipeline in the action.
}
func ( *Tree) ( Pos, int, *PipeNode) *ActionNode {
return &ActionNode{tr: , NodeType: NodeAction, Pos: , Line: , Pipe: }
}
func ( *ActionNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *ActionNode) ( *strings.Builder) {
.WriteString("{{")
.Pipe.writeTo()
.WriteString("}}")
}
func ( *ActionNode) () *Tree {
return .tr
}
func ( *ActionNode) () Node {
return .tr.newAction(.Pos, .Line, .Pipe.CopyPipe())
}
type CommandNode struct {
NodeType
Pos
tr *Tree
Args []Node // Arguments in lexical order: Identifier, field, or constant.
}
func ( *Tree) ( Pos) *CommandNode {
return &CommandNode{tr: , NodeType: NodeCommand, Pos: }
}
func ( *CommandNode) ( Node) {
.Args = append(.Args, )
}
func ( *CommandNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *CommandNode) ( *strings.Builder) {
for , := range .Args {
if > 0 {
.WriteByte(' ')
}
if , := .(*PipeNode); {
.WriteByte('(')
.writeTo()
.WriteByte(')')
continue
}
.writeTo()
}
}
func ( *CommandNode) () *Tree {
return .tr
}
func ( *CommandNode) () Node {
if == nil {
return
}
:= .tr.newCommand(.Pos)
for , := range .Args {
.append(.Copy())
}
return
}
func ( string) *IdentifierNode {
return &IdentifierNode{NodeType: NodeIdentifier, Ident: }
}
func ( *IdentifierNode) ( Pos) *IdentifierNode {
.Pos =
return
}
func ( *IdentifierNode) ( *Tree) *IdentifierNode {
.tr =
return
}
func ( *IdentifierNode) () string {
return .Ident
}
func ( *IdentifierNode) ( *strings.Builder) {
.WriteString(.String())
}
func ( *IdentifierNode) () *Tree {
return .tr
}
func ( *IdentifierNode) () Node {
return NewIdentifier(.Ident).SetTree(.tr).SetPos(.Pos)
}
type VariableNode struct {
NodeType
Pos
tr *Tree
Ident []string // Variable name and fields in lexical order.
}
func ( *Tree) ( Pos, string) *VariableNode {
return &VariableNode{tr: , NodeType: NodeVariable, Pos: , Ident: strings.Split(, ".")}
}
func ( *VariableNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *VariableNode) ( *strings.Builder) {
for , := range .Ident {
if > 0 {
.WriteByte('.')
}
.WriteString()
}
}
func ( *VariableNode) () *Tree {
return .tr
}
func ( *VariableNode) () Node {
return &VariableNode{tr: .tr, NodeType: NodeVariable, Pos: .Pos, Ident: append([]string{}, .Ident...)}
}
type FieldNode struct {
NodeType
Pos
tr *Tree
Ident []string // The identifiers in lexical order.
}
func ( *Tree) ( Pos, string) *FieldNode {
return &FieldNode{tr: , NodeType: NodeField, Pos: , Ident: strings.Split([1:], ".")} // [1:] to drop leading period
}
func ( *FieldNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *FieldNode) ( *strings.Builder) {
for , := range .Ident {
.WriteByte('.')
.WriteString()
}
}
func ( *FieldNode) () *Tree {
return .tr
}
func ( *FieldNode) () Node {
return &FieldNode{tr: .tr, NodeType: NodeField, Pos: .Pos, Ident: append([]string{}, .Ident...)}
}
func ( *ChainNode) ( string) {
if len() == 0 || [0] != '.' {
panic("no dot in field")
}
= [1:] // Remove leading dot.
if == "" {
panic("empty field")
}
.Field = append(.Field, )
}
func ( *ChainNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *ChainNode) ( *strings.Builder) {
if , := .Node.(*PipeNode); {
.WriteByte('(')
.Node.writeTo()
.WriteByte(')')
} else {
.Node.writeTo()
}
for , := range .Field {
.WriteByte('.')
.WriteString()
}
}
func ( *ChainNode) () *Tree {
return .tr
}
func ( *ChainNode) () Node {
return &ChainNode{tr: .tr, NodeType: NodeChain, Pos: .Pos, Node: .Node, Field: append([]string{}, .Field...)}
}
type BoolNode struct {
NodeType
Pos
tr *Tree
True bool // The value of the boolean constant.
}
func ( *Tree) ( Pos, bool) *BoolNode {
return &BoolNode{tr: , NodeType: NodeBool, Pos: , True: }
}
func ( *BoolNode) () string {
if .True {
return "true"
}
return "false"
}
func ( *BoolNode) ( *strings.Builder) {
.WriteString(.String())
}
func ( *BoolNode) () *Tree {
return .tr
}
func ( *BoolNode) () Node {
return .tr.newBool(.Pos, .True)
}
type NumberNode struct {
NodeType
Pos
tr *Tree
IsInt bool // Number has an integral value.
IsUint bool // Number has an unsigned integral value.
IsFloat bool // Number has a floating-point value.
IsComplex bool // Number is complex.
Int64 int64 // The signed integer value.
Uint64 uint64 // The unsigned integer value.
Float64 float64 // The floating-point value.
Complex128 complex128 // The complex value.
Text string // The original textual representation from the input.
}
func ( *Tree) ( Pos, string, itemType) (*NumberNode, error) {
:= &NumberNode{tr: , NodeType: NodeNumber, Pos: , Text: }
switch {
case itemCharConstant:
, , , := strconv.UnquoteChar([1:], [0])
if != nil {
return nil,
}
if != "'" {
return nil, fmt.Errorf("malformed character constant: %s", )
}
.Int64 = int64()
.IsInt = true
.Uint64 = uint64()
.IsUint = true
.Float64 = float64() // odd but those are the rules.
.IsFloat = true
return , nil
if , := fmt.Sscan(, &.Complex128); != nil {
return nil,
}
.IsComplex = true
.simplifyComplex()
return , nil
if len() > 0 && [len()-1] == 'i' {
, := strconv.ParseFloat([:len()-1], 64)
if == nil {
.IsComplex = true
.Complex128 = complex(0, )
.simplifyComplex()
return , nil
}
func ( *NumberNode) () {
.IsFloat = imag(.Complex128) == 0
if .IsFloat {
.Float64 = real(.Complex128)
.IsInt = float64(int64(.Float64)) == .Float64
if .IsInt {
.Int64 = int64(.Float64)
}
.IsUint = float64(uint64(.Float64)) == .Float64
if .IsUint {
.Uint64 = uint64(.Float64)
}
}
}
func ( *NumberNode) () string {
return .Text
}
func ( *NumberNode) ( *strings.Builder) {
.WriteString(.String())
}
func ( *NumberNode) () *Tree {
return .tr
}
func ( *NumberNode) () Node {
:= new(NumberNode)
* = * // Easy, fast, correct.
return
}
type StringNode struct {
NodeType
Pos
tr *Tree
Quoted string // The original text of the string, with quotes.
Text string // The string, after quote processing.
}
func ( *Tree) ( Pos, , string) *StringNode {
return &StringNode{tr: , NodeType: NodeString, Pos: , Quoted: , Text: }
}
func ( *StringNode) () string {
return .Quoted
}
func ( *StringNode) ( *strings.Builder) {
.WriteString(.String())
}
func ( *StringNode) () *Tree {
return .tr
}
func ( *StringNode) () Node {
return .tr.newString(.Pos, .Quoted, .Text)
}
type endNode struct {
NodeType
Pos
tr *Tree
}
func ( *Tree) ( Pos) *endNode {
return &endNode{tr: , NodeType: nodeEnd, Pos: }
}
func ( *endNode) () string {
return "{{end}}"
}
func ( *endNode) ( *strings.Builder) {
.WriteString(.String())
}
func ( *endNode) () *Tree {
return .tr
}
func ( *endNode) () Node {
return .tr.newEnd(.Pos)
}
type elseNode struct {
NodeType
Pos
tr *Tree
Line int // The line number in the input. Deprecated: Kept for compatibility.
}
func ( *Tree) ( Pos, int) *elseNode {
return &elseNode{tr: , NodeType: nodeElse, Pos: , Line: }
}
func ( *elseNode) () NodeType {
return nodeElse
}
func ( *elseNode) () string {
return "{{else}}"
}
func ( *elseNode) ( *strings.Builder) {
.WriteString(.String())
}
func ( *elseNode) () *Tree {
return .tr
}
func ( *elseNode) () Node {
return .tr.newElse(.Pos, .Line)
}
type BranchNode struct {
NodeType
Pos
tr *Tree
Line int // The line number in the input. Deprecated: Kept for compatibility.
Pipe *PipeNode // The pipeline to be evaluated.
List *ListNode // What to execute if the value is non-empty.
ElseList *ListNode // What to execute if the value is empty (nil if absent).
}
func ( *BranchNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *BranchNode) ( *strings.Builder) {
:= ""
switch .NodeType {
case NodeIf:
= "if"
case NodeRange:
= "range"
case NodeWith:
= "with"
default:
panic("unknown branch type")
}
.WriteString("{{")
.WriteString()
.WriteByte(' ')
.Pipe.writeTo()
.WriteString("}}")
.List.writeTo()
if .ElseList != nil {
.WriteString("{{else}}")
.ElseList.writeTo()
}
.WriteString("{{end}}")
}
func ( *BranchNode) () *Tree {
return .tr
}
func ( *BranchNode) () Node {
switch .NodeType {
case NodeIf:
return .tr.newIf(.Pos, .Line, .Pipe, .List, .ElseList)
case NodeRange:
return .tr.newRange(.Pos, .Line, .Pipe, .List, .ElseList)
case NodeWith:
return .tr.newWith(.Pos, .Line, .Pipe, .List, .ElseList)
default:
panic("unknown branch type")
}
}
type IfNode struct {
BranchNode
}
func ( *Tree) ( Pos, int, *PipeNode, , *ListNode) *IfNode {
return &IfNode{BranchNode{tr: , NodeType: NodeIf, Pos: , Line: , Pipe: , List: , ElseList: }}
}
func ( *IfNode) () Node {
return .tr.newIf(.Pos, .Line, .Pipe.CopyPipe(), .List.CopyList(), .ElseList.CopyList())
}
type RangeNode struct {
BranchNode
}
func ( *Tree) ( Pos, int, *PipeNode, , *ListNode) *RangeNode {
return &RangeNode{BranchNode{tr: , NodeType: NodeRange, Pos: , Line: , Pipe: , List: , ElseList: }}
}
func ( *RangeNode) () Node {
return .tr.newRange(.Pos, .Line, .Pipe.CopyPipe(), .List.CopyList(), .ElseList.CopyList())
}
type WithNode struct {
BranchNode
}
func ( *Tree) ( Pos, int, *PipeNode, , *ListNode) *WithNode {
return &WithNode{BranchNode{tr: , NodeType: NodeWith, Pos: , Line: , Pipe: , List: , ElseList: }}
}
func ( *WithNode) () Node {
return .tr.newWith(.Pos, .Line, .Pipe.CopyPipe(), .List.CopyList(), .ElseList.CopyList())
}
type TemplateNode struct {
NodeType
Pos
tr *Tree
Line int // The line number in the input. Deprecated: Kept for compatibility.
Name string // The name of the template (unquoted).
Pipe *PipeNode // The command to evaluate as dot for the template.
}
func ( *Tree) ( Pos, int, string, *PipeNode) *TemplateNode {
return &TemplateNode{tr: , NodeType: NodeTemplate, Pos: , Line: , Name: , Pipe: }
}
func ( *TemplateNode) () string {
var strings.Builder
.writeTo(&)
return .String()
}
func ( *TemplateNode) ( *strings.Builder) {
.WriteString("{{template ")
.WriteString(strconv.Quote(.Name))
if .Pipe != nil {
.WriteByte(' ')
.Pipe.writeTo()
}
.WriteString("}}")
}
func ( *TemplateNode) () *Tree {
return .tr
}
func ( *TemplateNode) () Node {
return .tr.newTemplate(.Pos, .Line, .Name, .Pipe.CopyPipe())
![]() |
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. |