node.go - hugo - [fork] hugo port for 9front
 (HTM) git clone https://git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       node.go (24888B)
       ---
            1 // Copyright 2011 The Go Authors. All rights reserved.
            2 // Use of this source code is governed by a BSD-style
            3 // license that can be found in the LICENSE file.
            4 
            5 // Parse nodes.
            6 
            7 package parse
            8 
            9 import (
           10         "fmt"
           11         "strconv"
           12         "strings"
           13 )
           14 
           15 var textFormat = "%s" // Changed to "%q" in tests for better error messages.
           16 
           17 // A Node is an element in the parse tree. The interface is trivial.
           18 // The interface contains an unexported method so that only
           19 // types local to this package can satisfy it.
           20 type Node interface {
           21         Type() NodeType
           22         String() string
           23         // Copy does a deep copy of the Node and all its components.
           24         // To avoid type assertions, some XxxNodes also have specialized
           25         // CopyXxx methods that return *XxxNode.
           26         Copy() Node
           27         Position() Pos // byte position of start of node in full original input string
           28         // tree returns the containing *Tree.
           29         // It is unexported so all implementations of Node are in this package.
           30         tree() *Tree
           31         // writeTo writes the String output to the builder.
           32         writeTo(*strings.Builder)
           33 }
           34 
           35 // NodeType identifies the type of a parse tree node.
           36 type NodeType int
           37 
           38 // Pos represents a byte position in the original input text from which
           39 // this template was parsed.
           40 type Pos int
           41 
           42 func (p Pos) Position() Pos {
           43         return p
           44 }
           45 
           46 // Type returns itself and provides an easy default implementation
           47 // for embedding in a Node. Embedded in all non-trivial Nodes.
           48 func (t NodeType) Type() NodeType {
           49         return t
           50 }
           51 
           52 const (
           53         NodeText       NodeType = iota // Plain text.
           54         NodeAction                     // A non-control action such as a field evaluation.
           55         NodeBool                       // A boolean constant.
           56         NodeChain                      // A sequence of field accesses.
           57         NodeCommand                    // An element of a pipeline.
           58         NodeDot                        // The cursor, dot.
           59         nodeElse                       // An else action. Not added to tree.
           60         nodeEnd                        // An end action. Not added to tree.
           61         NodeField                      // A field or method name.
           62         NodeIdentifier                 // An identifier; always a function name.
           63         NodeIf                         // An if action.
           64         NodeList                       // A list of Nodes.
           65         NodeNil                        // An untyped nil constant.
           66         NodeNumber                     // A numerical constant.
           67         NodePipe                       // A pipeline of commands.
           68         NodeRange                      // A range action.
           69         NodeString                     // A string constant.
           70         NodeTemplate                   // A template invocation action.
           71         NodeVariable                   // A $ variable.
           72         NodeWith                       // A with action.
           73         NodeComment                    // A comment.
           74         NodeBreak                      // A break action.
           75         NodeContinue                   // A continue action.
           76 )
           77 
           78 // Nodes.
           79 
           80 // ListNode holds a sequence of nodes.
           81 type ListNode struct {
           82         NodeType
           83         Pos
           84         tr    *Tree
           85         Nodes []Node // The element nodes in lexical order.
           86 }
           87 
           88 func (t *Tree) newList(pos Pos) *ListNode {
           89         return &ListNode{tr: t, NodeType: NodeList, Pos: pos}
           90 }
           91 
           92 func (l *ListNode) append(n Node) {
           93         l.Nodes = append(l.Nodes, n)
           94 }
           95 
           96 func (l *ListNode) tree() *Tree {
           97         return l.tr
           98 }
           99 
          100 func (l *ListNode) String() string {
          101         var sb strings.Builder
          102         l.writeTo(&sb)
          103         return sb.String()
          104 }
          105 
          106 func (l *ListNode) writeTo(sb *strings.Builder) {
          107         for _, n := range l.Nodes {
          108                 n.writeTo(sb)
          109         }
          110 }
          111 
          112 func (l *ListNode) CopyList() *ListNode {
          113         if l == nil {
          114                 return l
          115         }
          116         n := l.tr.newList(l.Pos)
          117         for _, elem := range l.Nodes {
          118                 n.append(elem.Copy())
          119         }
          120         return n
          121 }
          122 
          123 func (l *ListNode) Copy() Node {
          124         return l.CopyList()
          125 }
          126 
          127 // TextNode holds plain text.
          128 type TextNode struct {
          129         NodeType
          130         Pos
          131         tr   *Tree
          132         Text []byte // The text; may span newlines.
          133 }
          134 
          135 func (t *Tree) newText(pos Pos, text string) *TextNode {
          136         return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)}
          137 }
          138 
          139 func (t *TextNode) String() string {
          140         return fmt.Sprintf(textFormat, t.Text)
          141 }
          142 
          143 func (t *TextNode) writeTo(sb *strings.Builder) {
          144         sb.WriteString(t.String())
          145 }
          146 
          147 func (t *TextNode) tree() *Tree {
          148         return t.tr
          149 }
          150 
          151 func (t *TextNode) Copy() Node {
          152         return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)}
          153 }
          154 
          155 // CommentNode holds a comment.
          156 type CommentNode struct {
          157         NodeType
          158         Pos
          159         tr   *Tree
          160         Text string // Comment text.
          161 }
          162 
          163 func (t *Tree) newComment(pos Pos, text string) *CommentNode {
          164         return &CommentNode{tr: t, NodeType: NodeComment, Pos: pos, Text: text}
          165 }
          166 
          167 func (c *CommentNode) String() string {
          168         var sb strings.Builder
          169         c.writeTo(&sb)
          170         return sb.String()
          171 }
          172 
          173 func (c *CommentNode) writeTo(sb *strings.Builder) {
          174         sb.WriteString("{{")
          175         sb.WriteString(c.Text)
          176         sb.WriteString("}}")
          177 }
          178 
          179 func (c *CommentNode) tree() *Tree {
          180         return c.tr
          181 }
          182 
          183 func (c *CommentNode) Copy() Node {
          184         return &CommentNode{tr: c.tr, NodeType: NodeComment, Pos: c.Pos, Text: c.Text}
          185 }
          186 
          187 // PipeNode holds a pipeline with optional declaration
          188 type PipeNode struct {
          189         NodeType
          190         Pos
          191         tr       *Tree
          192         Line     int             // The line number in the input. Deprecated: Kept for compatibility.
          193         IsAssign bool            // The variables are being assigned, not declared.
          194         Decl     []*VariableNode // Variables in lexical order.
          195         Cmds     []*CommandNode  // The commands in lexical order.
          196 }
          197 
          198 func (t *Tree) newPipeline(pos Pos, line int, vars []*VariableNode) *PipeNode {
          199         return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: vars}
          200 }
          201 
          202 func (p *PipeNode) append(command *CommandNode) {
          203         p.Cmds = append(p.Cmds, command)
          204 }
          205 
          206 func (p *PipeNode) String() string {
          207         var sb strings.Builder
          208         p.writeTo(&sb)
          209         return sb.String()
          210 }
          211 
          212 func (p *PipeNode) writeTo(sb *strings.Builder) {
          213         if len(p.Decl) > 0 {
          214                 for i, v := range p.Decl {
          215                         if i > 0 {
          216                                 sb.WriteString(", ")
          217                         }
          218                         v.writeTo(sb)
          219                 }
          220                 if p.IsAssign {
          221                         sb.WriteString(" = ")
          222                 } else {
          223                         sb.WriteString(" := ")
          224                 }
          225         }
          226         for i, c := range p.Cmds {
          227                 if i > 0 {
          228                         sb.WriteString(" | ")
          229                 }
          230                 c.writeTo(sb)
          231         }
          232 }
          233 
          234 func (p *PipeNode) tree() *Tree {
          235         return p.tr
          236 }
          237 
          238 func (p *PipeNode) CopyPipe() *PipeNode {
          239         if p == nil {
          240                 return p
          241         }
          242         vars := make([]*VariableNode, len(p.Decl))
          243         for i, d := range p.Decl {
          244                 vars[i] = d.Copy().(*VariableNode)
          245         }
          246         n := p.tr.newPipeline(p.Pos, p.Line, vars)
          247         n.IsAssign = p.IsAssign
          248         for _, c := range p.Cmds {
          249                 n.append(c.Copy().(*CommandNode))
          250         }
          251         return n
          252 }
          253 
          254 func (p *PipeNode) Copy() Node {
          255         return p.CopyPipe()
          256 }
          257 
          258 // ActionNode holds an action (something bounded by delimiters).
          259 // Control actions have their own nodes; ActionNode represents simple
          260 // ones such as field evaluations and parenthesized pipelines.
          261 type ActionNode struct {
          262         NodeType
          263         Pos
          264         tr   *Tree
          265         Line int       // The line number in the input. Deprecated: Kept for compatibility.
          266         Pipe *PipeNode // The pipeline in the action.
          267 }
          268 
          269 func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {
          270         return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}
          271 }
          272 
          273 func (a *ActionNode) String() string {
          274         var sb strings.Builder
          275         a.writeTo(&sb)
          276         return sb.String()
          277 }
          278 
          279 func (a *ActionNode) writeTo(sb *strings.Builder) {
          280         sb.WriteString("{{")
          281         a.Pipe.writeTo(sb)
          282         sb.WriteString("}}")
          283 }
          284 
          285 func (a *ActionNode) tree() *Tree {
          286         return a.tr
          287 }
          288 
          289 func (a *ActionNode) Copy() Node {
          290         return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
          291 }
          292 
          293 // CommandNode holds a command (a pipeline inside an evaluating action).
          294 type CommandNode struct {
          295         NodeType
          296         Pos
          297         tr   *Tree
          298         Args []Node // Arguments in lexical order: Identifier, field, or constant.
          299 }
          300 
          301 func (t *Tree) newCommand(pos Pos) *CommandNode {
          302         return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}
          303 }
          304 
          305 func (c *CommandNode) append(arg Node) {
          306         c.Args = append(c.Args, arg)
          307 }
          308 
          309 func (c *CommandNode) String() string {
          310         var sb strings.Builder
          311         c.writeTo(&sb)
          312         return sb.String()
          313 }
          314 
          315 func (c *CommandNode) writeTo(sb *strings.Builder) {
          316         for i, arg := range c.Args {
          317                 if i > 0 {
          318                         sb.WriteByte(' ')
          319                 }
          320                 if arg, ok := arg.(*PipeNode); ok {
          321                         sb.WriteByte('(')
          322                         arg.writeTo(sb)
          323                         sb.WriteByte(')')
          324                         continue
          325                 }
          326                 arg.writeTo(sb)
          327         }
          328 }
          329 
          330 func (c *CommandNode) tree() *Tree {
          331         return c.tr
          332 }
          333 
          334 func (c *CommandNode) Copy() Node {
          335         if c == nil {
          336                 return c
          337         }
          338         n := c.tr.newCommand(c.Pos)
          339         for _, c := range c.Args {
          340                 n.append(c.Copy())
          341         }
          342         return n
          343 }
          344 
          345 // IdentifierNode holds an identifier.
          346 type IdentifierNode struct {
          347         NodeType
          348         Pos
          349         tr    *Tree
          350         Ident string // The identifier's name.
          351 }
          352 
          353 // NewIdentifier returns a new [IdentifierNode] with the given identifier name.
          354 func NewIdentifier(ident string) *IdentifierNode {
          355         return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
          356 }
          357 
          358 // SetPos sets the position. [NewIdentifier] is a public method so we can't modify its signature.
          359 // Chained for convenience.
          360 // TODO: fix one day?
          361 func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
          362         i.Pos = pos
          363         return i
          364 }
          365 
          366 // SetTree sets the parent tree for the node. [NewIdentifier] is a public method so we can't modify its signature.
          367 // Chained for convenience.
          368 // TODO: fix one day?
          369 func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {
          370         i.tr = t
          371         return i
          372 }
          373 
          374 func (i *IdentifierNode) String() string {
          375         return i.Ident
          376 }
          377 
          378 func (i *IdentifierNode) writeTo(sb *strings.Builder) {
          379         sb.WriteString(i.String())
          380 }
          381 
          382 func (i *IdentifierNode) tree() *Tree {
          383         return i.tr
          384 }
          385 
          386 func (i *IdentifierNode) Copy() Node {
          387         return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
          388 }
          389 
          390 // VariableNode holds a list of variable names, possibly with chained field
          391 // accesses. The dollar sign is part of the (first) name.
          392 type VariableNode struct {
          393         NodeType
          394         Pos
          395         tr    *Tree
          396         Ident []string // Variable name and fields in lexical order.
          397 }
          398 
          399 func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
          400         return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
          401 }
          402 
          403 func (v *VariableNode) String() string {
          404         var sb strings.Builder
          405         v.writeTo(&sb)
          406         return sb.String()
          407 }
          408 
          409 func (v *VariableNode) writeTo(sb *strings.Builder) {
          410         for i, id := range v.Ident {
          411                 if i > 0 {
          412                         sb.WriteByte('.')
          413                 }
          414                 sb.WriteString(id)
          415         }
          416 }
          417 
          418 func (v *VariableNode) tree() *Tree {
          419         return v.tr
          420 }
          421 
          422 func (v *VariableNode) Copy() Node {
          423         return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
          424 }
          425 
          426 // DotNode holds the special identifier '.'.
          427 type DotNode struct {
          428         NodeType
          429         Pos
          430         tr *Tree
          431 }
          432 
          433 func (t *Tree) newDot(pos Pos) *DotNode {
          434         return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}
          435 }
          436 
          437 func (d *DotNode) Type() NodeType {
          438         // Override method on embedded NodeType for API compatibility.
          439         // TODO: Not really a problem; could change API without effect but
          440         // api tool complains.
          441         return NodeDot
          442 }
          443 
          444 func (d *DotNode) String() string {
          445         return "."
          446 }
          447 
          448 func (d *DotNode) writeTo(sb *strings.Builder) {
          449         sb.WriteString(d.String())
          450 }
          451 
          452 func (d *DotNode) tree() *Tree {
          453         return d.tr
          454 }
          455 
          456 func (d *DotNode) Copy() Node {
          457         return d.tr.newDot(d.Pos)
          458 }
          459 
          460 // NilNode holds the special identifier 'nil' representing an untyped nil constant.
          461 type NilNode struct {
          462         NodeType
          463         Pos
          464         tr *Tree
          465 }
          466 
          467 func (t *Tree) newNil(pos Pos) *NilNode {
          468         return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}
          469 }
          470 
          471 func (n *NilNode) Type() NodeType {
          472         // Override method on embedded NodeType for API compatibility.
          473         // TODO: Not really a problem; could change API without effect but
          474         // api tool complains.
          475         return NodeNil
          476 }
          477 
          478 func (n *NilNode) String() string {
          479         return "nil"
          480 }
          481 
          482 func (n *NilNode) writeTo(sb *strings.Builder) {
          483         sb.WriteString(n.String())
          484 }
          485 
          486 func (n *NilNode) tree() *Tree {
          487         return n.tr
          488 }
          489 
          490 func (n *NilNode) Copy() Node {
          491         return n.tr.newNil(n.Pos)
          492 }
          493 
          494 // FieldNode holds a field (identifier starting with '.').
          495 // The names may be chained ('.x.y').
          496 // The period is dropped from each ident.
          497 type FieldNode struct {
          498         NodeType
          499         Pos
          500         tr    *Tree
          501         Ident []string // The identifiers in lexical order.
          502 }
          503 
          504 func (t *Tree) newField(pos Pos, ident string) *FieldNode {
          505         return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
          506 }
          507 
          508 func (f *FieldNode) String() string {
          509         var sb strings.Builder
          510         f.writeTo(&sb)
          511         return sb.String()
          512 }
          513 
          514 func (f *FieldNode) writeTo(sb *strings.Builder) {
          515         for _, id := range f.Ident {
          516                 sb.WriteByte('.')
          517                 sb.WriteString(id)
          518         }
          519 }
          520 
          521 func (f *FieldNode) tree() *Tree {
          522         return f.tr
          523 }
          524 
          525 func (f *FieldNode) Copy() Node {
          526         return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
          527 }
          528 
          529 // ChainNode holds a term followed by a chain of field accesses (identifier starting with '.').
          530 // The names may be chained ('.x.y').
          531 // The periods are dropped from each ident.
          532 type ChainNode struct {
          533         NodeType
          534         Pos
          535         tr    *Tree
          536         Node  Node
          537         Field []string // The identifiers in lexical order.
          538 }
          539 
          540 func (t *Tree) newChain(pos Pos, node Node) *ChainNode {
          541         return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}
          542 }
          543 
          544 // Add adds the named field (which should start with a period) to the end of the chain.
          545 func (c *ChainNode) Add(field string) {
          546         if len(field) == 0 || field[0] != '.' {
          547                 panic("no dot in field")
          548         }
          549         field = field[1:] // Remove leading dot.
          550         if field == "" {
          551                 panic("empty field")
          552         }
          553         c.Field = append(c.Field, field)
          554 }
          555 
          556 func (c *ChainNode) String() string {
          557         var sb strings.Builder
          558         c.writeTo(&sb)
          559         return sb.String()
          560 }
          561 
          562 func (c *ChainNode) writeTo(sb *strings.Builder) {
          563         if _, ok := c.Node.(*PipeNode); ok {
          564                 sb.WriteByte('(')
          565                 c.Node.writeTo(sb)
          566                 sb.WriteByte(')')
          567         } else {
          568                 c.Node.writeTo(sb)
          569         }
          570         for _, field := range c.Field {
          571                 sb.WriteByte('.')
          572                 sb.WriteString(field)
          573         }
          574 }
          575 
          576 func (c *ChainNode) tree() *Tree {
          577         return c.tr
          578 }
          579 
          580 func (c *ChainNode) Copy() Node {
          581         return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
          582 }
          583 
          584 // BoolNode holds a boolean constant.
          585 type BoolNode struct {
          586         NodeType
          587         Pos
          588         tr   *Tree
          589         True bool // The value of the boolean constant.
          590 }
          591 
          592 func (t *Tree) newBool(pos Pos, true bool) *BoolNode {
          593         return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}
          594 }
          595 
          596 func (b *BoolNode) String() string {
          597         if b.True {
          598                 return "true"
          599         }
          600         return "false"
          601 }
          602 
          603 func (b *BoolNode) writeTo(sb *strings.Builder) {
          604         sb.WriteString(b.String())
          605 }
          606 
          607 func (b *BoolNode) tree() *Tree {
          608         return b.tr
          609 }
          610 
          611 func (b *BoolNode) Copy() Node {
          612         return b.tr.newBool(b.Pos, b.True)
          613 }
          614 
          615 // NumberNode holds a number: signed or unsigned integer, float, or complex.
          616 // The value is parsed and stored under all the types that can represent the value.
          617 // This simulates in a small amount of code the behavior of Go's ideal constants.
          618 type NumberNode struct {
          619         NodeType
          620         Pos
          621         tr         *Tree
          622         IsInt      bool       // Number has an integral value.
          623         IsUint     bool       // Number has an unsigned integral value.
          624         IsFloat    bool       // Number has a floating-point value.
          625         IsComplex  bool       // Number is complex.
          626         Int64      int64      // The signed integer value.
          627         Uint64     uint64     // The unsigned integer value.
          628         Float64    float64    // The floating-point value.
          629         Complex128 complex128 // The complex value.
          630         Text       string     // The original textual representation from the input.
          631 }
          632 
          633 func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
          634         n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}
          635         switch typ {
          636         case itemCharConstant:
          637                 rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
          638                 if err != nil {
          639                         return nil, err
          640                 }
          641                 if tail != "'" {
          642                         return nil, fmt.Errorf("malformed character constant: %s", text)
          643                 }
          644                 n.Int64 = int64(rune)
          645                 n.IsInt = true
          646                 n.Uint64 = uint64(rune)
          647                 n.IsUint = true
          648                 n.Float64 = float64(rune) // odd but those are the rules.
          649                 n.IsFloat = true
          650                 return n, nil
          651         case itemComplex:
          652                 // fmt.Sscan can parse the pair, so let it do the work.
          653                 if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
          654                         return nil, err
          655                 }
          656                 n.IsComplex = true
          657                 n.simplifyComplex()
          658                 return n, nil
          659         }
          660         // Imaginary constants can only be complex unless they are zero.
          661         if len(text) > 0 && text[len(text)-1] == 'i' {
          662                 f, err := strconv.ParseFloat(text[:len(text)-1], 64)
          663                 if err == nil {
          664                         n.IsComplex = true
          665                         n.Complex128 = complex(0, f)
          666                         n.simplifyComplex()
          667                         return n, nil
          668                 }
          669         }
          670         // Do integer test first so we get 0x123 etc.
          671         u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
          672         if err == nil {
          673                 n.IsUint = true
          674                 n.Uint64 = u
          675         }
          676         i, err := strconv.ParseInt(text, 0, 64)
          677         if err == nil {
          678                 n.IsInt = true
          679                 n.Int64 = i
          680                 if i == 0 {
          681                         n.IsUint = true // in case of -0.
          682                         n.Uint64 = u
          683                 }
          684         }
          685         // If an integer extraction succeeded, promote the float.
          686         if n.IsInt {
          687                 n.IsFloat = true
          688                 n.Float64 = float64(n.Int64)
          689         } else if n.IsUint {
          690                 n.IsFloat = true
          691                 n.Float64 = float64(n.Uint64)
          692         } else {
          693                 f, err := strconv.ParseFloat(text, 64)
          694                 if err == nil {
          695                         // If we parsed it as a float but it looks like an integer,
          696                         // it's a huge number too large to fit in an int. Reject it.
          697                         if !strings.ContainsAny(text, ".eEpP") {
          698                                 return nil, fmt.Errorf("integer overflow: %q", text)
          699                         }
          700                         n.IsFloat = true
          701                         n.Float64 = f
          702                         // If a floating-point extraction succeeded, extract the int if needed.
          703                         if !n.IsInt && float64(int64(f)) == f {
          704                                 n.IsInt = true
          705                                 n.Int64 = int64(f)
          706                         }
          707                         if !n.IsUint && float64(uint64(f)) == f {
          708                                 n.IsUint = true
          709                                 n.Uint64 = uint64(f)
          710                         }
          711                 }
          712         }
          713         if !n.IsInt && !n.IsUint && !n.IsFloat {
          714                 return nil, fmt.Errorf("illegal number syntax: %q", text)
          715         }
          716         return n, nil
          717 }
          718 
          719 // simplifyComplex pulls out any other types that are represented by the complex number.
          720 // These all require that the imaginary part be zero.
          721 func (n *NumberNode) simplifyComplex() {
          722         n.IsFloat = imag(n.Complex128) == 0
          723         if n.IsFloat {
          724                 n.Float64 = real(n.Complex128)
          725                 n.IsInt = float64(int64(n.Float64)) == n.Float64
          726                 if n.IsInt {
          727                         n.Int64 = int64(n.Float64)
          728                 }
          729                 n.IsUint = float64(uint64(n.Float64)) == n.Float64
          730                 if n.IsUint {
          731                         n.Uint64 = uint64(n.Float64)
          732                 }
          733         }
          734 }
          735 
          736 func (n *NumberNode) String() string {
          737         return n.Text
          738 }
          739 
          740 func (n *NumberNode) writeTo(sb *strings.Builder) {
          741         sb.WriteString(n.String())
          742 }
          743 
          744 func (n *NumberNode) tree() *Tree {
          745         return n.tr
          746 }
          747 
          748 func (n *NumberNode) Copy() Node {
          749         nn := new(NumberNode)
          750         *nn = *n // Easy, fast, correct.
          751         return nn
          752 }
          753 
          754 // StringNode holds a string constant. The value has been "unquoted".
          755 type StringNode struct {
          756         NodeType
          757         Pos
          758         tr     *Tree
          759         Quoted string // The original text of the string, with quotes.
          760         Text   string // The string, after quote processing.
          761 }
          762 
          763 func (t *Tree) newString(pos Pos, orig, text string) *StringNode {
          764         return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
          765 }
          766 
          767 func (s *StringNode) String() string {
          768         return s.Quoted
          769 }
          770 
          771 func (s *StringNode) writeTo(sb *strings.Builder) {
          772         sb.WriteString(s.String())
          773 }
          774 
          775 func (s *StringNode) tree() *Tree {
          776         return s.tr
          777 }
          778 
          779 func (s *StringNode) Copy() Node {
          780         return s.tr.newString(s.Pos, s.Quoted, s.Text)
          781 }
          782 
          783 // endNode represents an {{end}} action.
          784 // It does not appear in the final parse tree.
          785 type endNode struct {
          786         NodeType
          787         Pos
          788         tr *Tree
          789 }
          790 
          791 func (t *Tree) newEnd(pos Pos) *endNode {
          792         return &endNode{tr: t, NodeType: nodeEnd, Pos: pos}
          793 }
          794 
          795 func (e *endNode) String() string {
          796         return "{{end}}"
          797 }
          798 
          799 func (e *endNode) writeTo(sb *strings.Builder) {
          800         sb.WriteString(e.String())
          801 }
          802 
          803 func (e *endNode) tree() *Tree {
          804         return e.tr
          805 }
          806 
          807 func (e *endNode) Copy() Node {
          808         return e.tr.newEnd(e.Pos)
          809 }
          810 
          811 // elseNode represents an {{else}} action. Does not appear in the final tree.
          812 type elseNode struct {
          813         NodeType
          814         Pos
          815         tr   *Tree
          816         Line int // The line number in the input. Deprecated: Kept for compatibility.
          817 }
          818 
          819 func (t *Tree) newElse(pos Pos, line int) *elseNode {
          820         return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line}
          821 }
          822 
          823 func (e *elseNode) Type() NodeType {
          824         return nodeElse
          825 }
          826 
          827 func (e *elseNode) String() string {
          828         return "{{else}}"
          829 }
          830 
          831 func (e *elseNode) writeTo(sb *strings.Builder) {
          832         sb.WriteString(e.String())
          833 }
          834 
          835 func (e *elseNode) tree() *Tree {
          836         return e.tr
          837 }
          838 
          839 func (e *elseNode) Copy() Node {
          840         return e.tr.newElse(e.Pos, e.Line)
          841 }
          842 
          843 // BranchNode is the common representation of if, range, and with.
          844 type BranchNode struct {
          845         NodeType
          846         Pos
          847         tr       *Tree
          848         Line     int       // The line number in the input. Deprecated: Kept for compatibility.
          849         Pipe     *PipeNode // The pipeline to be evaluated.
          850         List     *ListNode // What to execute if the value is non-empty.
          851         ElseList *ListNode // What to execute if the value is empty (nil if absent).
          852 }
          853 
          854 func (b *BranchNode) String() string {
          855         var sb strings.Builder
          856         b.writeTo(&sb)
          857         return sb.String()
          858 }
          859 
          860 func (b *BranchNode) writeTo(sb *strings.Builder) {
          861         name := ""
          862         switch b.NodeType {
          863         case NodeIf:
          864                 name = "if"
          865         case NodeRange:
          866                 name = "range"
          867         case NodeWith:
          868                 name = "with"
          869         default:
          870                 panic("unknown branch type")
          871         }
          872         sb.WriteString("{{")
          873         sb.WriteString(name)
          874         sb.WriteByte(' ')
          875         b.Pipe.writeTo(sb)
          876         sb.WriteString("}}")
          877         b.List.writeTo(sb)
          878         if b.ElseList != nil {
          879                 sb.WriteString("{{else}}")
          880                 b.ElseList.writeTo(sb)
          881         }
          882         sb.WriteString("{{end}}")
          883 }
          884 
          885 func (b *BranchNode) tree() *Tree {
          886         return b.tr
          887 }
          888 
          889 func (b *BranchNode) Copy() Node {
          890         switch b.NodeType {
          891         case NodeIf:
          892                 return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
          893         case NodeRange:
          894                 return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
          895         case NodeWith:
          896                 return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
          897         default:
          898                 panic("unknown branch type")
          899         }
          900 }
          901 
          902 // IfNode represents an {{if}} action and its commands.
          903 type IfNode struct {
          904         BranchNode
          905 }
          906 
          907 func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
          908         return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
          909 }
          910 
          911 func (i *IfNode) Copy() Node {
          912         return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
          913 }
          914 
          915 // BreakNode represents a {{break}} action.
          916 type BreakNode struct {
          917         tr *Tree
          918         NodeType
          919         Pos
          920         Line int
          921 }
          922 
          923 func (t *Tree) newBreak(pos Pos, line int) *BreakNode {
          924         return &BreakNode{tr: t, NodeType: NodeBreak, Pos: pos, Line: line}
          925 }
          926 
          927 func (b *BreakNode) Copy() Node                  { return b.tr.newBreak(b.Pos, b.Line) }
          928 func (b *BreakNode) String() string              { return "{{break}}" }
          929 func (b *BreakNode) tree() *Tree                 { return b.tr }
          930 func (b *BreakNode) writeTo(sb *strings.Builder) { sb.WriteString("{{break}}") }
          931 
          932 // ContinueNode represents a {{continue}} action.
          933 type ContinueNode struct {
          934         tr *Tree
          935         NodeType
          936         Pos
          937         Line int
          938 }
          939 
          940 func (t *Tree) newContinue(pos Pos, line int) *ContinueNode {
          941         return &ContinueNode{tr: t, NodeType: NodeContinue, Pos: pos, Line: line}
          942 }
          943 
          944 func (c *ContinueNode) Copy() Node                  { return c.tr.newContinue(c.Pos, c.Line) }
          945 func (c *ContinueNode) String() string              { return "{{continue}}" }
          946 func (c *ContinueNode) tree() *Tree                 { return c.tr }
          947 func (c *ContinueNode) writeTo(sb *strings.Builder) { sb.WriteString("{{continue}}") }
          948 
          949 // RangeNode represents a {{range}} action and its commands.
          950 type RangeNode struct {
          951         BranchNode
          952 }
          953 
          954 func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
          955         return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
          956 }
          957 
          958 func (r *RangeNode) Copy() Node {
          959         return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
          960 }
          961 
          962 // WithNode represents a {{with}} action and its commands.
          963 type WithNode struct {
          964         BranchNode
          965 }
          966 
          967 func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
          968         return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
          969 }
          970 
          971 func (w *WithNode) Copy() Node {
          972         return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
          973 }
          974 
          975 // TemplateNode represents a {{template}} action.
          976 type TemplateNode struct {
          977         NodeType
          978         Pos
          979         tr   *Tree
          980         Line int       // The line number in the input. Deprecated: Kept for compatibility.
          981         Name string    // The name of the template (unquoted).
          982         Pipe *PipeNode // The command to evaluate as dot for the template.
          983 }
          984 
          985 func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
          986         return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe}
          987 }
          988 
          989 func (t *TemplateNode) String() string {
          990         var sb strings.Builder
          991         t.writeTo(&sb)
          992         return sb.String()
          993 }
          994 
          995 func (t *TemplateNode) writeTo(sb *strings.Builder) {
          996         sb.WriteString("{{template ")
          997         sb.WriteString(strconv.Quote(t.Name))
          998         if t.Pipe != nil {
          999                 sb.WriteByte(' ')
         1000                 t.Pipe.writeTo(sb)
         1001         }
         1002         sb.WriteString("}}")
         1003 }
         1004 
         1005 func (t *TemplateNode) tree() *Tree {
         1006         return t.tr
         1007 }
         1008 
         1009 func (t *TemplateNode) Copy() Node {
         1010         return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
         1011 }