839 lines · 20.3 KB · Go
RawDownload
// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file. // Parse nodes. package parse import (	"bytes"	"fmt"	"strconv"	"strings") var textFormat = "%s" // Changed to "%q" in tests for better error messages. // A Node is an element in the parse tree. The interface is trivial.// The interface contains an unexported method so that only// types local to this package can satisfy it.type Node interface {	Type() NodeType	String() string	// Copy does a deep copy of the Node and all its components.	// To avoid type assertions, some XxxNodes also have specialized	// CopyXxx methods that return *XxxNode.	Copy() Node	Position() Pos // byte position of start of node in full original input string	// tree returns the containing *Tree.	// It is unexported so all implementations of Node are in this package.	tree() *Tree} // NodeType identifies the type of a parse tree node.type NodeType int // Pos represents a byte position in the original input text from which// this template was parsed.type Pos int func (p Pos) Position() Pos {	return p} // Type returns itself and provides an easy default implementation// for embedding in a Node. Embedded in all non-trivial Nodes.func (t NodeType) Type() NodeType {	return t} 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.) // Nodes. // ListNode holds a sequence of nodes.type ListNode struct {	NodeType	Pos	tr    *Tree	Nodes []Node // The element nodes in lexical order.} func (t *Tree) newList(pos Pos) *ListNode {	return &ListNode{tr: t, NodeType: NodeList, Pos: pos}} func (l *ListNode) append(n Node) {	l.Nodes = append(l.Nodes, n)} func (l *ListNode) tree() *Tree {	return l.tr} func (l *ListNode) String() string {	b := new(bytes.Buffer)	for _, n := range l.Nodes {		fmt.Fprint(b, n)	}	return b.String()} func (l *ListNode) CopyList() *ListNode {	if l == nil {		return l	}	n := l.tr.newList(l.Pos)	for _, elem := range l.Nodes {		n.append(elem.Copy())	}	return n} func (l *ListNode) Copy() Node {	return l.CopyList()} // TextNode holds plain text.type TextNode struct {	NodeType	Pos	tr   *Tree	Text []byte // The text; may span newlines.} func (t *Tree) newText(pos Pos, text string) *TextNode {	return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)}} func (t *TextNode) String() string {	return fmt.Sprintf(textFormat, t.Text)} func (t *TextNode) tree() *Tree {	return t.tr} func (t *TextNode) Copy() Node {	return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)}} // PipeNode holds a pipeline with optional declarationtype PipeNode struct {	NodeType	Pos	tr   *Tree	Line int             // The line number in the input. Deprecated: Kept for compatibility.	Decl []*VariableNode // Variable declarations in lexical order.	Cmds []*CommandNode  // The commands in lexical order.} func (t *Tree) newPipeline(pos Pos, line int, decl []*VariableNode) *PipeNode {	return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: decl}} func (p *PipeNode) append(command *CommandNode) {	p.Cmds = append(p.Cmds, command)} func (p *PipeNode) String() string {	s := ""	if len(p.Decl) > 0 {		for i, v := range p.Decl {			if i > 0 {				s += ", "			}			s += v.String()		}		s += " := "	}	for i, c := range p.Cmds {		if i > 0 {			s += " | "		}		s += c.String()	}	return s} func (p *PipeNode) tree() *Tree {	return p.tr} func (p *PipeNode) CopyPipe() *PipeNode {	if p == nil {		return p	}	var decl []*VariableNode	for _, d := range p.Decl {		decl = append(decl, d.Copy().(*VariableNode))	}	n := p.tr.newPipeline(p.Pos, p.Line, decl)	for _, c := range p.Cmds {		n.append(c.Copy().(*CommandNode))	}	return n} func (p *PipeNode) Copy() Node {	return p.CopyPipe()} // ActionNode holds an action (something bounded by delimiters).// Control actions have their own nodes; ActionNode represents simple// ones such as field evaluations and parenthesized pipelines.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 (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {	return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}} func (a *ActionNode) String() string {	return fmt.Sprintf("{{%s}}", a.Pipe) } func (a *ActionNode) tree() *Tree {	return a.tr} func (a *ActionNode) Copy() Node {	return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe()) } // CommandNode holds a command (a pipeline inside an evaluating action).type CommandNode struct {	NodeType	Pos	tr   *Tree	Args []Node // Arguments in lexical order: Identifier, field, or constant.} func (t *Tree) newCommand(pos Pos) *CommandNode {	return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}} func (c *CommandNode) append(arg Node) {	c.Args = append(c.Args, arg)} func (c *CommandNode) String() string {	s := ""	for i, arg := range c.Args {		if i > 0 {			s += " "		}		if arg, ok := arg.(*PipeNode); ok {			s += "(" + arg.String() + ")"			continue		}		s += arg.String()	}	return s} func (c *CommandNode) tree() *Tree {	return c.tr} func (c *CommandNode) Copy() Node {	if c == nil {		return c	}	n := c.tr.newCommand(c.Pos)	for _, c := range c.Args {		n.append(c.Copy())	}	return n} // IdentifierNode holds an identifier.type IdentifierNode struct {	NodeType	Pos	tr    *Tree	Ident string // The identifier's name.} // NewIdentifier returns a new IdentifierNode with the given identifier name.func NewIdentifier(ident string) *IdentifierNode {	return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}} // SetPos sets the position. NewIdentifier is a public method so we can't modify its signature.// Chained for convenience.// TODO: fix one day?func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {	i.Pos = pos	return i} // SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature.// Chained for convenience.// TODO: fix one day?func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {	i.tr = t	return i} func (i *IdentifierNode) String() string {	return i.Ident} func (i *IdentifierNode) tree() *Tree {	return i.tr} func (i *IdentifierNode) Copy() Node {	return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)} // VariableNode holds a list of variable names, possibly with chained field// accesses. The dollar sign is part of the (first) name.type VariableNode struct {	NodeType	Pos	tr    *Tree	Ident []string // Variable name and fields in lexical order.} func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {	return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}} func (v *VariableNode) String() string {	s := ""	for i, id := range v.Ident {		if i > 0 {			s += "."		}		s += id	}	return s} func (v *VariableNode) tree() *Tree {	return v.tr} func (v *VariableNode) Copy() Node {	return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}} // DotNode holds the special identifier '.'.type DotNode struct {	NodeType	Pos	tr *Tree} func (t *Tree) newDot(pos Pos) *DotNode {	return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}} func (d *DotNode) Type() NodeType {	// Override method on embedded NodeType for API compatibility.	// TODO: Not really a problem; could change API without effect but	// api tool complains.	return NodeDot} func (d *DotNode) String() string {	return "."} func (d *DotNode) tree() *Tree {	return d.tr} func (d *DotNode) Copy() Node {	return d.tr.newDot(d.Pos)} // NilNode holds the special identifier 'nil' representing an untyped nil constant.type NilNode struct {	NodeType	Pos	tr *Tree} func (t *Tree) newNil(pos Pos) *NilNode {	return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}} func (n *NilNode) Type() NodeType {	// Override method on embedded NodeType for API compatibility.	// TODO: Not really a problem; could change API without effect but	// api tool complains.	return NodeNil} func (n *NilNode) String() string {	return "nil"} func (n *NilNode) tree() *Tree {	return n.tr} func (n *NilNode) Copy() Node {	return n.tr.newNil(n.Pos)} // FieldNode holds a field (identifier starting with '.').// The names may be chained ('.x.y').// The period is dropped from each ident.type FieldNode struct {	NodeType	Pos	tr    *Tree	Ident []string // The identifiers in lexical order.} func (t *Tree) newField(pos Pos, ident string) *FieldNode {	return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period} func (f *FieldNode) String() string {	s := ""	for _, id := range f.Ident {		s += "." + id	}	return s} func (f *FieldNode) tree() *Tree {	return f.tr} func (f *FieldNode) Copy() Node {	return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}} // ChainNode holds a term followed by a chain of field accesses (identifier starting with '.').// The names may be chained ('.x.y').// The periods are dropped from each ident.type ChainNode struct {	NodeType	Pos	tr    *Tree	Node  Node	Field []string // The identifiers in lexical order.} func (t *Tree) newChain(pos Pos, node Node) *ChainNode {	return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}} // Add adds the named field (which should start with a period) to the end of the chain.func (c *ChainNode) Add(field string) {	if len(field) == 0 || field[0] != '.' {		panic("no dot in field")	}	field = field[1:] // Remove leading dot.	if field == "" {		panic("empty field")	}	c.Field = append(c.Field, field)} func (c *ChainNode) String() string {	s := c.Node.String()	if _, ok := c.Node.(*PipeNode); ok {		s = "(" + s + ")"	}	for _, field := range c.Field {		s += "." + field	}	return s} func (c *ChainNode) tree() *Tree {	return c.tr} func (c *ChainNode) Copy() Node {	return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}} // BoolNode holds a boolean constant.type BoolNode struct {	NodeType	Pos	tr   *Tree	True bool // The value of the boolean constant.} func (t *Tree) newBool(pos Pos, true bool) *BoolNode {	return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}} func (b *BoolNode) String() string {

Lines 1–500 of 839.