]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/go/text/template/parse/node.go
tree-cfg.c (replace_uses_by): Fixup TREE_CONSTANT for propagating all kinds of constants.
[thirdparty/gcc.git] / libgo / go / text / template / parse / node.go
CommitLineData
adb0401d
ILT
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
7package parse
8
9import (
10 "bytes"
11 "fmt"
adb0401d
ILT
12 "strconv"
13 "strings"
14)
15
16// A node is an element in the parse tree. The interface is trivial.
17type Node interface {
18 Type() NodeType
19 String() string
20}
21
22// NodeType identifies the type of a parse tree node.
23type NodeType int
24
25// Type returns itself and provides an easy default implementation
26// for embedding in a Node. Embedded in all non-trivial Nodes.
27func (t NodeType) Type() NodeType {
28 return t
29}
30
31const (
32 NodeText NodeType = iota // Plain text.
33 NodeAction // A simple action such as field evaluation.
34 NodeBool // A boolean constant.
35 NodeCommand // An element of a pipeline.
36 NodeDot // The cursor, dot.
37 nodeElse // An else action. Not added to tree.
38 nodeEnd // An end action. Not added to tree.
39 NodeField // A field or method name.
40 NodeIdentifier // An identifier; always a function name.
41 NodeIf // An if action.
42 NodeList // A list of Nodes.
43 NodeNumber // A numerical constant.
44 NodePipe // A pipeline of commands.
45 NodeRange // A range action.
46 NodeString // A string constant.
47 NodeTemplate // A template invocation action.
48 NodeVariable // A $ variable.
49 NodeWith // A with action.
50)
51
52// Nodes.
53
54// ListNode holds a sequence of nodes.
55type ListNode struct {
56 NodeType
57 Nodes []Node // The element nodes in lexical order.
58}
59
60func newList() *ListNode {
61 return &ListNode{NodeType: NodeList}
62}
63
64func (l *ListNode) append(n Node) {
65 l.Nodes = append(l.Nodes, n)
66}
67
68func (l *ListNode) String() string {
69 b := new(bytes.Buffer)
70 fmt.Fprint(b, "[")
71 for _, n := range l.Nodes {
72 fmt.Fprint(b, n)
73 }
74 fmt.Fprint(b, "]")
75 return b.String()
76}
77
78// TextNode holds plain text.
79type TextNode struct {
80 NodeType
81 Text []byte // The text; may span newlines.
82}
83
84func newText(text string) *TextNode {
85 return &TextNode{NodeType: NodeText, Text: []byte(text)}
86}
87
88func (t *TextNode) String() string {
89 return fmt.Sprintf("(text: %q)", t.Text)
90}
91
92// PipeNode holds a pipeline with optional declaration
93type PipeNode struct {
94 NodeType
95 Line int // The line number in the input.
96 Decl []*VariableNode // Variable declarations in lexical order.
97 Cmds []*CommandNode // The commands in lexical order.
98}
99
100func newPipeline(line int, decl []*VariableNode) *PipeNode {
101 return &PipeNode{NodeType: NodePipe, Line: line, Decl: decl}
102}
103
104func (p *PipeNode) append(command *CommandNode) {
105 p.Cmds = append(p.Cmds, command)
106}
107
108func (p *PipeNode) String() string {
109 if p.Decl != nil {
110 return fmt.Sprintf("%v := %v", p.Decl, p.Cmds)
111 }
112 return fmt.Sprintf("%v", p.Cmds)
113}
114
115// ActionNode holds an action (something bounded by delimiters).
116// Control actions have their own nodes; ActionNode represents simple
117// ones such as field evaluations.
118type ActionNode struct {
119 NodeType
120 Line int // The line number in the input.
121 Pipe *PipeNode // The pipeline in the action.
122}
123
124func newAction(line int, pipe *PipeNode) *ActionNode {
125 return &ActionNode{NodeType: NodeAction, Line: line, Pipe: pipe}
126}
127
128func (a *ActionNode) String() string {
129 return fmt.Sprintf("(action: %v)", a.Pipe)
130}
131
132// CommandNode holds a command (a pipeline inside an evaluating action).
133type CommandNode struct {
134 NodeType
135 Args []Node // Arguments in lexical order: Identifier, field, or constant.
136}
137
138func newCommand() *CommandNode {
139 return &CommandNode{NodeType: NodeCommand}
140}
141
142func (c *CommandNode) append(arg Node) {
143 c.Args = append(c.Args, arg)
144}
145
146func (c *CommandNode) String() string {
147 return fmt.Sprintf("(command: %v)", c.Args)
148}
149
150// IdentifierNode holds an identifier.
151type IdentifierNode struct {
152 NodeType
153 Ident string // The identifier's name.
154}
155
156// NewIdentifier returns a new IdentifierNode with the given identifier name.
157func NewIdentifier(ident string) *IdentifierNode {
158 return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
159}
160
161func (i *IdentifierNode) String() string {
162 return fmt.Sprintf("I=%s", i.Ident)
163}
164
165// VariableNode holds a list of variable names. The dollar sign is
166// part of the name.
167type VariableNode struct {
168 NodeType
169 Ident []string // Variable names in lexical order.
170}
171
172func newVariable(ident string) *VariableNode {
173 return &VariableNode{NodeType: NodeVariable, Ident: strings.Split(ident, ".")}
174}
175
176func (v *VariableNode) String() string {
177 return fmt.Sprintf("V=%s", v.Ident)
178}
179
180// DotNode holds the special identifier '.'. It is represented by a nil pointer.
181type DotNode bool
182
183func newDot() *DotNode {
184 return nil
185}
186
187func (d *DotNode) Type() NodeType {
188 return NodeDot
189}
190
191func (d *DotNode) String() string {
192 return "{{<.>}}"
193}
194
195// FieldNode holds a field (identifier starting with '.').
196// The names may be chained ('.x.y').
197// The period is dropped from each ident.
198type FieldNode struct {
199 NodeType
200 Ident []string // The identifiers in lexical order.
201}
202
203func newField(ident string) *FieldNode {
204 return &FieldNode{NodeType: NodeField, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
205}
206
207func (f *FieldNode) String() string {
208 return fmt.Sprintf("F=%s", f.Ident)
209}
210
211// BoolNode holds a boolean constant.
212type BoolNode struct {
213 NodeType
214 True bool // The value of the boolean constant.
215}
216
217func newBool(true bool) *BoolNode {
218 return &BoolNode{NodeType: NodeBool, True: true}
219}
220
221func (b *BoolNode) String() string {
222 return fmt.Sprintf("B=%t", b.True)
223}
224
225// NumberNode holds a number: signed or unsigned integer, float, or complex.
226// The value is parsed and stored under all the types that can represent the value.
227// This simulates in a small amount of code the behavior of Go's ideal constants.
228type NumberNode struct {
229 NodeType
230 IsInt bool // Number has an integral value.
231 IsUint bool // Number has an unsigned integral value.
232 IsFloat bool // Number has a floating-point value.
233 IsComplex bool // Number is complex.
234 Int64 int64 // The signed integer value.
235 Uint64 uint64 // The unsigned integer value.
236 Float64 float64 // The floating-point value.
237 Complex128 complex128 // The complex value.
238 Text string // The original textual representation from the input.
239}
240
2fd401c8 241func newNumber(text string, typ itemType) (*NumberNode, error) {
adb0401d
ILT
242 n := &NumberNode{NodeType: NodeNumber, Text: text}
243 switch typ {
244 case itemCharConstant:
245 rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
246 if err != nil {
247 return nil, err
248 }
249 if tail != "'" {
250 return nil, fmt.Errorf("malformed character constant: %s", text)
251 }
252 n.Int64 = int64(rune)
253 n.IsInt = true
254 n.Uint64 = uint64(rune)
255 n.IsUint = true
256 n.Float64 = float64(rune) // odd but those are the rules.
257 n.IsFloat = true
258 return n, nil
259 case itemComplex:
260 // fmt.Sscan can parse the pair, so let it do the work.
261 if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
262 return nil, err
263 }
264 n.IsComplex = true
265 n.simplifyComplex()
266 return n, nil
267 }
268 // Imaginary constants can only be complex unless they are zero.
269 if len(text) > 0 && text[len(text)-1] == 'i' {
270 f, err := strconv.Atof64(text[:len(text)-1])
271 if err == nil {
272 n.IsComplex = true
273 n.Complex128 = complex(0, f)
274 n.simplifyComplex()
275 return n, nil
276 }
277 }
278 // Do integer test first so we get 0x123 etc.
279 u, err := strconv.Btoui64(text, 0) // will fail for -0; fixed below.
280 if err == nil {
281 n.IsUint = true
282 n.Uint64 = u
283 }
284 i, err := strconv.Btoi64(text, 0)
285 if err == nil {
286 n.IsInt = true
287 n.Int64 = i
288 if i == 0 {
289 n.IsUint = true // in case of -0.
290 n.Uint64 = u
291 }
292 }
293 // If an integer extraction succeeded, promote the float.
294 if n.IsInt {
295 n.IsFloat = true
296 n.Float64 = float64(n.Int64)
297 } else if n.IsUint {
298 n.IsFloat = true
299 n.Float64 = float64(n.Uint64)
300 } else {
301 f, err := strconv.Atof64(text)
302 if err == nil {
303 n.IsFloat = true
304 n.Float64 = f
305 // If a floating-point extraction succeeded, extract the int if needed.
306 if !n.IsInt && float64(int64(f)) == f {
307 n.IsInt = true
308 n.Int64 = int64(f)
309 }
310 if !n.IsUint && float64(uint64(f)) == f {
311 n.IsUint = true
312 n.Uint64 = uint64(f)
313 }
314 }
315 }
316 if !n.IsInt && !n.IsUint && !n.IsFloat {
317 return nil, fmt.Errorf("illegal number syntax: %q", text)
318 }
319 return n, nil
320}
321
322// simplifyComplex pulls out any other types that are represented by the complex number.
323// These all require that the imaginary part be zero.
324func (n *NumberNode) simplifyComplex() {
325 n.IsFloat = imag(n.Complex128) == 0
326 if n.IsFloat {
327 n.Float64 = real(n.Complex128)
328 n.IsInt = float64(int64(n.Float64)) == n.Float64
329 if n.IsInt {
330 n.Int64 = int64(n.Float64)
331 }
332 n.IsUint = float64(uint64(n.Float64)) == n.Float64
333 if n.IsUint {
334 n.Uint64 = uint64(n.Float64)
335 }
336 }
337}
338
339func (n *NumberNode) String() string {
340 return fmt.Sprintf("N=%s", n.Text)
341}
342
343// StringNode holds a string constant. The value has been "unquoted".
344type StringNode struct {
345 NodeType
346 Quoted string // The original text of the string, with quotes.
347 Text string // The string, after quote processing.
348}
349
350func newString(orig, text string) *StringNode {
351 return &StringNode{NodeType: NodeString, Quoted: orig, Text: text}
352}
353
354func (s *StringNode) String() string {
355 return fmt.Sprintf("S=%#q", s.Text)
356}
357
358// endNode represents an {{end}} action. It is represented by a nil pointer.
359// It does not appear in the final parse tree.
360type endNode bool
361
362func newEnd() *endNode {
363 return nil
364}
365
366func (e *endNode) Type() NodeType {
367 return nodeEnd
368}
369
370func (e *endNode) String() string {
371 return "{{end}}"
372}
373
374// elseNode represents an {{else}} action. Does not appear in the final tree.
375type elseNode struct {
376 NodeType
377 Line int // The line number in the input.
378}
379
380func newElse(line int) *elseNode {
381 return &elseNode{NodeType: nodeElse, Line: line}
382}
383
384func (e *elseNode) Type() NodeType {
385 return nodeElse
386}
387
388func (e *elseNode) String() string {
389 return "{{else}}"
390}
391
d8f41257
ILT
392// BranchNode is the common representation of if, range, and with.
393type BranchNode struct {
adb0401d
ILT
394 NodeType
395 Line int // The line number in the input.
396 Pipe *PipeNode // The pipeline to be evaluated.
397 List *ListNode // What to execute if the value is non-empty.
398 ElseList *ListNode // What to execute if the value is empty (nil if absent).
399}
400
d8f41257
ILT
401func (b *BranchNode) String() string {
402 name := ""
403 switch b.NodeType {
404 case NodeIf:
405 name = "if"
406 case NodeRange:
407 name = "range"
408 case NodeWith:
409 name = "with"
410 default:
411 panic("unknown branch type")
412 }
413 if b.ElseList != nil {
414 return fmt.Sprintf("({{%s %s}} %s {{else}} %s)", name, b.Pipe, b.List, b.ElseList)
415 }
416 return fmt.Sprintf("({{%s %s}} %s)", name, b.Pipe, b.List)
adb0401d
ILT
417}
418
d8f41257
ILT
419// IfNode represents an {{if}} action and its commands.
420type IfNode struct {
421 BranchNode
422}
423
424func newIf(line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
425 return &IfNode{BranchNode{NodeType: NodeIf, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
adb0401d
ILT
426}
427
428// RangeNode represents a {{range}} action and its commands.
429type RangeNode struct {
d8f41257 430 BranchNode
adb0401d
ILT
431}
432
433func newRange(line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
d8f41257 434 return &RangeNode{BranchNode{NodeType: NodeRange, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
adb0401d
ILT
435}
436
d8f41257
ILT
437// WithNode represents a {{with}} action and its commands.
438type WithNode struct {
439 BranchNode
440}
441
442func newWith(line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
443 return &WithNode{BranchNode{NodeType: NodeWith, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
adb0401d
ILT
444}
445
446// TemplateNode represents a {{template}} action.
447type TemplateNode struct {
448 NodeType
449 Line int // The line number in the input.
450 Name string // The name of the template (unquoted).
451 Pipe *PipeNode // The command to evaluate as dot for the template.
452}
453
454func newTemplate(line int, name string, pipe *PipeNode) *TemplateNode {
455 return &TemplateNode{NodeType: NodeTemplate, Line: line, Name: name, Pipe: pipe}
456}
457
458func (t *TemplateNode) String() string {
459 if t.Pipe == nil {
460 return fmt.Sprintf("{{template %q}}", t.Name)
461 }
462 return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
463}