1
2
3
4
5
6
7 package parse
8
9 import (
10 "bytes"
11 "fmt"
12 "strconv"
13 "strings"
14 )
15
16 var textFormat = "%s"
17
18
19
20
21 type Node interface {
22 Type() NodeType
23 String() string
24
25
26
27 Copy() Node
28 Position() Pos
29
30
31 tree() *Tree
32 }
33
34
35 type NodeType int
36
37
38
39 type Pos int
40
41 func (p Pos) Position() Pos {
42 return p
43 }
44
45
46
47 func (t NodeType) Type() NodeType {
48 return t
49 }
50
51 const (
52 NodeText NodeType = iota
53 NodeAction
54 NodeBool
55 NodeChain
56 NodeCommand
57 NodeDot
58 nodeElse
59 nodeEnd
60 NodeField
61 NodeIdentifier
62 NodeIf
63 NodeList
64 NodeNil
65 NodeNumber
66 NodePipe
67 NodeRange
68 NodeString
69 NodeTemplate
70 NodeVariable
71 NodeWith
72 )
73
74
75
76
77 type ListNode struct {
78 NodeType
79 Pos
80 tr *Tree
81 Nodes []Node
82 }
83
84 func (t *Tree) newList(pos Pos) *ListNode {
85 return &ListNode{tr: t, NodeType: NodeList, Pos: pos}
86 }
87
88 func (l *ListNode) append(n Node) {
89 l.Nodes = append(l.Nodes, n)
90 }
91
92 func (l *ListNode) tree() *Tree {
93 return l.tr
94 }
95
96 func (l *ListNode) String() string {
97 b := new(bytes.Buffer)
98 for _, n := range l.Nodes {
99 fmt.Fprint(b, n)
100 }
101 return b.String()
102 }
103
104 func (l *ListNode) CopyList() *ListNode {
105 if l == nil {
106 return l
107 }
108 n := l.tr.newList(l.Pos)
109 for _, elem := range l.Nodes {
110 n.append(elem.Copy())
111 }
112 return n
113 }
114
115 func (l *ListNode) Copy() Node {
116 return l.CopyList()
117 }
118
119
120 type TextNode struct {
121 NodeType
122 Pos
123 tr *Tree
124 Text []byte
125 }
126
127 func (t *Tree) newText(pos Pos, text string) *TextNode {
128 return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)}
129 }
130
131 func (t *TextNode) String() string {
132 return fmt.Sprintf(textFormat, t.Text)
133 }
134
135 func (t *TextNode) tree() *Tree {
136 return t.tr
137 }
138
139 func (t *TextNode) Copy() Node {
140 return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)}
141 }
142
143
144 type PipeNode struct {
145 NodeType
146 Pos
147 tr *Tree
148 Line int
149 Decl []*VariableNode
150 Cmds []*CommandNode
151 }
152
153 func (t *Tree) newPipeline(pos Pos, line int, decl []*VariableNode) *PipeNode {
154 return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: decl}
155 }
156
157 func (p *PipeNode) append(command *CommandNode) {
158 p.Cmds = append(p.Cmds, command)
159 }
160
161 func (p *PipeNode) String() string {
162 s := ""
163 if len(p.Decl) > 0 {
164 for i, v := range p.Decl {
165 if i > 0 {
166 s += ", "
167 }
168 s += v.String()
169 }
170 s += " := "
171 }
172 for i, c := range p.Cmds {
173 if i > 0 {
174 s += " | "
175 }
176 s += c.String()
177 }
178 return s
179 }
180
181 func (p *PipeNode) tree() *Tree {
182 return p.tr
183 }
184
185 func (p *PipeNode) CopyPipe() *PipeNode {
186 if p == nil {
187 return p
188 }
189 var decl []*VariableNode
190 for _, d := range p.Decl {
191 decl = append(decl, d.Copy().(*VariableNode))
192 }
193 n := p.tr.newPipeline(p.Pos, p.Line, decl)
194 for _, c := range p.Cmds {
195 n.append(c.Copy().(*CommandNode))
196 }
197 return n
198 }
199
200 func (p *PipeNode) Copy() Node {
201 return p.CopyPipe()
202 }
203
204
205
206
207 type ActionNode struct {
208 NodeType
209 Pos
210 tr *Tree
211 Line int
212 Pipe *PipeNode
213 }
214
215 func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {
216 return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}
217 }
218
219 func (a *ActionNode) String() string {
220 return fmt.Sprintf("{{%s}}", a.Pipe)
221
222 }
223
224 func (a *ActionNode) tree() *Tree {
225 return a.tr
226 }
227
228 func (a *ActionNode) Copy() Node {
229 return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
230
231 }
232
233
234 type CommandNode struct {
235 NodeType
236 Pos
237 tr *Tree
238 Args []Node
239 }
240
241 func (t *Tree) newCommand(pos Pos) *CommandNode {
242 return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}
243 }
244
245 func (c *CommandNode) append(arg Node) {
246 c.Args = append(c.Args, arg)
247 }
248
249 func (c *CommandNode) String() string {
250 s := ""
251 for i, arg := range c.Args {
252 if i > 0 {
253 s += " "
254 }
255 if arg, ok := arg.(*PipeNode); ok {
256 s += "(" + arg.String() + ")"
257 continue
258 }
259 s += arg.String()
260 }
261 return s
262 }
263
264 func (c *CommandNode) tree() *Tree {
265 return c.tr
266 }
267
268 func (c *CommandNode) Copy() Node {
269 if c == nil {
270 return c
271 }
272 n := c.tr.newCommand(c.Pos)
273 for _, c := range c.Args {
274 n.append(c.Copy())
275 }
276 return n
277 }
278
279
280 type IdentifierNode struct {
281 NodeType
282 Pos
283 tr *Tree
284 Ident string
285 }
286
287
288 func NewIdentifier(ident string) *IdentifierNode {
289 return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
290 }
291
292
293
294
295 func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
296 i.Pos = pos
297 return i
298 }
299
300
301
302
303 func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {
304 i.tr = t
305 return i
306 }
307
308 func (i *IdentifierNode) String() string {
309 return i.Ident
310 }
311
312 func (i *IdentifierNode) tree() *Tree {
313 return i.tr
314 }
315
316 func (i *IdentifierNode) Copy() Node {
317 return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
318 }
319
320
321
322 type VariableNode struct {
323 NodeType
324 Pos
325 tr *Tree
326 Ident []string
327 }
328
329 func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
330 return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
331 }
332
333 func (v *VariableNode) String() string {
334 s := ""
335 for i, id := range v.Ident {
336 if i > 0 {
337 s += "."
338 }
339 s += id
340 }
341 return s
342 }
343
344 func (v *VariableNode) tree() *Tree {
345 return v.tr
346 }
347
348 func (v *VariableNode) Copy() Node {
349 return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
350 }
351
352
353 type DotNode struct {
354 NodeType
355 Pos
356 tr *Tree
357 }
358
359 func (t *Tree) newDot(pos Pos) *DotNode {
360 return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}
361 }
362
363 func (d *DotNode) Type() NodeType {
364
365
366
367 return NodeDot
368 }
369
370 func (d *DotNode) String() string {
371 return "."
372 }
373
374 func (d *DotNode) tree() *Tree {
375 return d.tr
376 }
377
378 func (d *DotNode) Copy() Node {
379 return d.tr.newDot(d.Pos)
380 }
381
382
383 type NilNode struct {
384 NodeType
385 Pos
386 tr *Tree
387 }
388
389 func (t *Tree) newNil(pos Pos) *NilNode {
390 return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}
391 }
392
393 func (n *NilNode) Type() NodeType {
394
395
396
397 return NodeNil
398 }
399
400 func (n *NilNode) String() string {
401 return "nil"
402 }
403
404 func (n *NilNode) tree() *Tree {
405 return n.tr
406 }
407
408 func (n *NilNode) Copy() Node {
409 return n.tr.newNil(n.Pos)
410 }
411
412
413
414
415 type FieldNode struct {
416 NodeType
417 Pos
418 tr *Tree
419 Ident []string
420 }
421
422 func (t *Tree) newField(pos Pos, ident string) *FieldNode {
423 return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")}
424 }
425
426 func (f *FieldNode) String() string {
427 s := ""
428 for _, id := range f.Ident {
429 s += "." + id
430 }
431 return s
432 }
433
434 func (f *FieldNode) tree() *Tree {
435 return f.tr
436 }
437
438 func (f *FieldNode) Copy() Node {
439 return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
440 }
441
442
443
444
445 type ChainNode struct {
446 NodeType
447 Pos
448 tr *Tree
449 Node Node
450 Field []string
451 }
452
453 func (t *Tree) newChain(pos Pos, node Node) *ChainNode {
454 return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}
455 }
456
457
458 func (c *ChainNode) Add(field string) {
459 if len(field) == 0 || field[0] != '.' {
460 panic("no dot in field")
461 }
462 field = field[1:]
463 if field == "" {
464 panic("empty field")
465 }
466 c.Field = append(c.Field, field)
467 }
468
469 func (c *ChainNode) String() string {
470 s := c.Node.String()
471 if _, ok := c.Node.(*PipeNode); ok {
472 s = "(" + s + ")"
473 }
474 for _, field := range c.Field {
475 s += "." + field
476 }
477 return s
478 }
479
480 func (c *ChainNode) tree() *Tree {
481 return c.tr
482 }
483
484 func (c *ChainNode) Copy() Node {
485 return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
486 }
487
488
489 type BoolNode struct {
490 NodeType
491 Pos
492 tr *Tree
493 True bool
494 }
495
496 func (t *Tree) newBool(pos Pos, true bool) *BoolNode {
497 return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}
498 }
499
500 func (b *BoolNode) String() string {
501 if b.True {
502 return "true"
503 }
504 return "false"
505 }
506
507 func (b *BoolNode) tree() *Tree {
508 return b.tr
509 }
510
511 func (b *BoolNode) Copy() Node {
512 return b.tr.newBool(b.Pos, b.True)
513 }
514
515
516
517
518 type NumberNode struct {
519 NodeType
520 Pos
521 tr *Tree
522 IsInt bool
523 IsUint bool
524 IsFloat bool
525 IsComplex bool
526 Int64 int64
527 Uint64 uint64
528 Float64 float64
529 Complex128 complex128
530 Text string
531 }
532
533 func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
534 n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}
535 switch typ {
536 case itemCharConstant:
537 rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
538 if err != nil {
539 return nil, err
540 }
541 if tail != "'" {
542 return nil, fmt.Errorf("malformed character constant: %s", text)
543 }
544 n.Int64 = int64(rune)
545 n.IsInt = true
546 n.Uint64 = uint64(rune)
547 n.IsUint = true
548 n.Float64 = float64(rune)
549 n.IsFloat = true
550 return n, nil
551 case itemComplex:
552
553 if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
554 return nil, err
555 }
556 n.IsComplex = true
557 n.simplifyComplex()
558 return n, nil
559 }
560
561 if len(text) > 0 && text[len(text)-1] == 'i' {
562 f, err := strconv.ParseFloat(text[:len(text)-1], 64)
563 if err == nil {
564 n.IsComplex = true
565 n.Complex128 = complex(0, f)
566 n.simplifyComplex()
567 return n, nil
568 }
569 }
570
571 u, err := strconv.ParseUint(text, 0, 64)
572 if err == nil {
573 n.IsUint = true
574 n.Uint64 = u
575 }
576 i, err := strconv.ParseInt(text, 0, 64)
577 if err == nil {
578 n.IsInt = true
579 n.Int64 = i
580 if i == 0 {
581 n.IsUint = true
582 n.Uint64 = u
583 }
584 }
585
586 if n.IsInt {
587 n.IsFloat = true
588 n.Float64 = float64(n.Int64)
589 } else if n.IsUint {
590 n.IsFloat = true
591 n.Float64 = float64(n.Uint64)
592 } else {
593 f, err := strconv.ParseFloat(text, 64)
594 if err == nil {
595
596
597 if !strings.ContainsAny(text, ".eE") {
598 return nil, fmt.Errorf("integer overflow: %q", text)
599 }
600 n.IsFloat = true
601 n.Float64 = f
602
603 if !n.IsInt && float64(int64(f)) == f {
604 n.IsInt = true
605 n.Int64 = int64(f)
606 }
607 if !n.IsUint && float64(uint64(f)) == f {
608 n.IsUint = true
609 n.Uint64 = uint64(f)
610 }
611 }
612 }
613 if !n.IsInt && !n.IsUint && !n.IsFloat {
614 return nil, fmt.Errorf("illegal number syntax: %q", text)
615 }
616 return n, nil
617 }
618
619
620
621 func (n *NumberNode) simplifyComplex() {
622 n.IsFloat = imag(n.Complex128) == 0
623 if n.IsFloat {
624 n.Float64 = real(n.Complex128)
625 n.IsInt = float64(int64(n.Float64)) == n.Float64
626 if n.IsInt {
627 n.Int64 = int64(n.Float64)
628 }
629 n.IsUint = float64(uint64(n.Float64)) == n.Float64
630 if n.IsUint {
631 n.Uint64 = uint64(n.Float64)
632 }
633 }
634 }
635
636 func (n *NumberNode) String() string {
637 return n.Text
638 }
639
640 func (n *NumberNode) tree() *Tree {
641 return n.tr
642 }
643
644 func (n *NumberNode) Copy() Node {
645 nn := new(NumberNode)
646 *nn = *n
647 return nn
648 }
649
650
651 type StringNode struct {
652 NodeType
653 Pos
654 tr *Tree
655 Quoted string
656 Text string
657 }
658
659 func (t *Tree) newString(pos Pos, orig, text string) *StringNode {
660 return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
661 }
662
663 func (s *StringNode) String() string {
664 return s.Quoted
665 }
666
667 func (s *StringNode) tree() *Tree {
668 return s.tr
669 }
670
671 func (s *StringNode) Copy() Node {
672 return s.tr.newString(s.Pos, s.Quoted, s.Text)
673 }
674
675
676
677 type endNode struct {
678 NodeType
679 Pos
680 tr *Tree
681 }
682
683 func (t *Tree) newEnd(pos Pos) *endNode {
684 return &endNode{tr: t, NodeType: nodeEnd, Pos: pos}
685 }
686
687 func (e *endNode) String() string {
688 return "{{end}}"
689 }
690
691 func (e *endNode) tree() *Tree {
692 return e.tr
693 }
694
695 func (e *endNode) Copy() Node {
696 return e.tr.newEnd(e.Pos)
697 }
698
699
700 type elseNode struct {
701 NodeType
702 Pos
703 tr *Tree
704 Line int
705 }
706
707 func (t *Tree) newElse(pos Pos, line int) *elseNode {
708 return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line}
709 }
710
711 func (e *elseNode) Type() NodeType {
712 return nodeElse
713 }
714
715 func (e *elseNode) String() string {
716 return "{{else}}"
717 }
718
719 func (e *elseNode) tree() *Tree {
720 return e.tr
721 }
722
723 func (e *elseNode) Copy() Node {
724 return e.tr.newElse(e.Pos, e.Line)
725 }
726
727
728 type BranchNode struct {
729 NodeType
730 Pos
731 tr *Tree
732 Line int
733 Pipe *PipeNode
734 List *ListNode
735 ElseList *ListNode
736 }
737
738 func (b *BranchNode) String() string {
739 name := ""
740 switch b.NodeType {
741 case NodeIf:
742 name = "if"
743 case NodeRange:
744 name = "range"
745 case NodeWith:
746 name = "with"
747 default:
748 panic("unknown branch type")
749 }
750 if b.ElseList != nil {
751 return fmt.Sprintf("{{%s %s}}%s{{else}}%s{{end}}", name, b.Pipe, b.List, b.ElseList)
752 }
753 return fmt.Sprintf("{{%s %s}}%s{{end}}", name, b.Pipe, b.List)
754 }
755
756 func (b *BranchNode) tree() *Tree {
757 return b.tr
758 }
759
760 func (b *BranchNode) Copy() Node {
761 switch b.NodeType {
762 case NodeIf:
763 return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
764 case NodeRange:
765 return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
766 case NodeWith:
767 return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
768 default:
769 panic("unknown branch type")
770 }
771 }
772
773
774 type IfNode struct {
775 BranchNode
776 }
777
778 func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
779 return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
780 }
781
782 func (i *IfNode) Copy() Node {
783 return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
784 }
785
786
787 type RangeNode struct {
788 BranchNode
789 }
790
791 func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
792 return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
793 }
794
795 func (r *RangeNode) Copy() Node {
796 return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
797 }
798
799
800 type WithNode struct {
801 BranchNode
802 }
803
804 func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
805 return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
806 }
807
808 func (w *WithNode) Copy() Node {
809 return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
810 }
811
812
813 type TemplateNode struct {
814 NodeType
815 Pos
816 tr *Tree
817 Line int
818 Name string
819 Pipe *PipeNode
820 }
821
822 func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
823 return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe}
824 }
825
826 func (t *TemplateNode) String() string {
827 if t.Pipe == nil {
828 return fmt.Sprintf("{{template %q}}", t.Name)
829 }
830 return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
831 }
832
833 func (t *TemplateNode) tree() *Tree {
834 return t.tr
835 }
836
837 func (t *TemplateNode) Copy() Node {
838 return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
839 }
840
View as plain text