1
2
3
4
5
6
7
8
9 package parse
10
11 import (
12 "bytes"
13 "fmt"
14 "runtime"
15 "strconv"
16 "strings"
17 )
18
19
20 type Tree struct {
21 Name string
22 ParseName string
23 Root *ListNode
24 Mode Mode
25 text string
26
27 funcs []map[string]any
28 lex *lexer
29 token [3]item
30 peekCount int
31 vars []string
32 treeSet map[string]*Tree
33 actionLine int
34 rangeDepth int
35 }
36
37
38 type Mode uint
39
40 const (
41 ParseComments Mode = 1 << iota
42 SkipFuncCheck
43 )
44
45
46 func (t *Tree) Copy() *Tree {
47 if t == nil {
48 return nil
49 }
50 return &Tree{
51 Name: t.Name,
52 ParseName: t.ParseName,
53 Root: t.Root.CopyList(),
54 text: t.text,
55 }
56 }
57
58
59
60
61
62 func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]any) (map[string]*Tree, error) {
63 treeSet := make(map[string]*Tree)
64 t := New(name)
65 t.text = text
66 _, err := t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
67 return treeSet, err
68 }
69
70
71 func (t *Tree) next() item {
72 if t.peekCount > 0 {
73 t.peekCount--
74 } else {
75 t.token[0] = t.lex.nextItem()
76 }
77 return t.token[t.peekCount]
78 }
79
80
81 func (t *Tree) backup() {
82 t.peekCount++
83 }
84
85
86
87 func (t *Tree) backup2(t1 item) {
88 t.token[1] = t1
89 t.peekCount = 2
90 }
91
92
93
94 func (t *Tree) backup3(t2, t1 item) {
95 t.token[1] = t1
96 t.token[2] = t2
97 t.peekCount = 3
98 }
99
100
101 func (t *Tree) peek() item {
102 if t.peekCount > 0 {
103 return t.token[t.peekCount-1]
104 }
105 t.peekCount = 1
106 t.token[0] = t.lex.nextItem()
107 return t.token[0]
108 }
109
110
111 func (t *Tree) nextNonSpace() (token item) {
112 for {
113 token = t.next()
114 if token.typ != itemSpace {
115 break
116 }
117 }
118 return token
119 }
120
121
122 func (t *Tree) peekNonSpace() item {
123 token := t.nextNonSpace()
124 t.backup()
125 return token
126 }
127
128
129
130
131 func New(name string, funcs ...map[string]any) *Tree {
132 return &Tree{
133 Name: name,
134 funcs: funcs,
135 }
136 }
137
138
139
140
141 func (t *Tree) ErrorContext(n Node) (location, context string) {
142 pos := int(n.Position())
143 tree := n.tree()
144 if tree == nil {
145 tree = t
146 }
147 text := tree.text[:pos]
148 byteNum := strings.LastIndex(text, "\n")
149 if byteNum == -1 {
150 byteNum = pos
151 } else {
152 byteNum++
153 byteNum = pos - byteNum
154 }
155 lineNum := 1 + strings.Count(text, "\n")
156 context = n.String()
157 return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context
158 }
159
160
161 func (t *Tree) errorf(format string, args ...any) {
162 t.Root = nil
163 format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format)
164 panic(fmt.Errorf(format, args...))
165 }
166
167
168 func (t *Tree) error(err error) {
169 t.errorf("%s", err)
170 }
171
172
173 func (t *Tree) expect(expected itemType, context string) item {
174 token := t.nextNonSpace()
175 if token.typ != expected {
176 t.unexpected(token, context)
177 }
178 return token
179 }
180
181
182 func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
183 token := t.nextNonSpace()
184 if token.typ != expected1 && token.typ != expected2 {
185 t.unexpected(token, context)
186 }
187 return token
188 }
189
190
191 func (t *Tree) unexpected(token item, context string) {
192 if token.typ == itemError {
193 extra := ""
194 if t.actionLine != 0 && t.actionLine != token.line {
195 extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine)
196 if strings.HasSuffix(token.val, " action") {
197 extra = extra[len(" in action"):]
198 }
199 }
200 t.errorf("%s%s", token, extra)
201 }
202 t.errorf("unexpected %s in %s", token, context)
203 }
204
205
206 func (t *Tree) recover(errp *error) {
207 e := recover()
208 if e != nil {
209 if _, ok := e.(runtime.Error); ok {
210 panic(e)
211 }
212 if t != nil {
213 t.lex.drain()
214 t.stopParse()
215 }
216 *errp = e.(error)
217 }
218 }
219
220
221 func (t *Tree) startParse(funcs []map[string]any, lex *lexer, treeSet map[string]*Tree) {
222 t.Root = nil
223 t.lex = lex
224 t.vars = []string{"$"}
225 t.funcs = funcs
226 t.treeSet = treeSet
227 lex.breakOK = !t.hasFunction("break")
228 lex.continueOK = !t.hasFunction("continue")
229 }
230
231
232 func (t *Tree) stopParse() {
233 t.lex = nil
234 t.vars = nil
235 t.funcs = nil
236 t.treeSet = nil
237 }
238
239
240
241
242
243 func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]any) (tree *Tree, err error) {
244 defer t.recover(&err)
245 t.ParseName = t.Name
246 emitComment := t.Mode&ParseComments != 0
247 t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim, emitComment), treeSet)
248 t.text = text
249 t.parse()
250 t.add()
251 t.stopParse()
252 return t, nil
253 }
254
255
256 func (t *Tree) add() {
257 tree := t.treeSet[t.Name]
258 if tree == nil || IsEmptyTree(tree.Root) {
259 t.treeSet[t.Name] = t
260 return
261 }
262 if !IsEmptyTree(t.Root) {
263 t.errorf("template: multiple definition of template %q", t.Name)
264 }
265 }
266
267
268 func IsEmptyTree(n Node) bool {
269 switch n := n.(type) {
270 case nil:
271 return true
272 case *ActionNode:
273 case *CommentNode:
274 return true
275 case *IfNode:
276 case *ListNode:
277 for _, node := range n.Nodes {
278 if !IsEmptyTree(node) {
279 return false
280 }
281 }
282 return true
283 case *RangeNode:
284 case *TemplateNode:
285 case *TextNode:
286 return len(bytes.TrimSpace(n.Text)) == 0
287 case *WithNode:
288 default:
289 panic("unknown node: " + n.String())
290 }
291 return false
292 }
293
294
295
296
297 func (t *Tree) parse() {
298 t.Root = t.newList(t.peek().pos)
299 for t.peek().typ != itemEOF {
300 if t.peek().typ == itemLeftDelim {
301 delim := t.next()
302 if t.nextNonSpace().typ == itemDefine {
303 newT := New("definition")
304 newT.text = t.text
305 newT.Mode = t.Mode
306 newT.ParseName = t.ParseName
307 newT.startParse(t.funcs, t.lex, t.treeSet)
308 newT.parseDefinition()
309 continue
310 }
311 t.backup2(delim)
312 }
313 switch n := t.textOrAction(); n.Type() {
314 case nodeEnd, nodeElse:
315 t.errorf("unexpected %s", n)
316 default:
317 t.Root.append(n)
318 }
319 }
320 }
321
322
323
324
325 func (t *Tree) parseDefinition() {
326 const context = "define clause"
327 name := t.expectOneOf(itemString, itemRawString, context)
328 var err error
329 t.Name, err = strconv.Unquote(name.val)
330 if err != nil {
331 t.error(err)
332 }
333 t.expect(itemRightDelim, context)
334 var end Node
335 t.Root, end = t.itemList()
336 if end.Type() != nodeEnd {
337 t.errorf("unexpected %s in %s", end, context)
338 }
339 t.add()
340 t.stopParse()
341 }
342
343
344
345
346 func (t *Tree) itemList() (list *ListNode, next Node) {
347 list = t.newList(t.peekNonSpace().pos)
348 for t.peekNonSpace().typ != itemEOF {
349 n := t.textOrAction()
350 switch n.Type() {
351 case nodeEnd, nodeElse:
352 return list, n
353 }
354 list.append(n)
355 }
356 t.errorf("unexpected EOF")
357 return
358 }
359
360
361
362 func (t *Tree) textOrAction() Node {
363 switch token := t.nextNonSpace(); token.typ {
364 case itemText:
365 return t.newText(token.pos, token.val)
366 case itemLeftDelim:
367 t.actionLine = token.line
368 defer t.clearActionLine()
369 return t.action()
370 case itemComment:
371 return t.newComment(token.pos, token.val)
372 default:
373 t.unexpected(token, "input")
374 }
375 return nil
376 }
377
378 func (t *Tree) clearActionLine() {
379 t.actionLine = 0
380 }
381
382
383
384
385
386
387 func (t *Tree) action() (n Node) {
388 switch token := t.nextNonSpace(); token.typ {
389 case itemBlock:
390 return t.blockControl()
391 case itemBreak:
392 return t.breakControl(token.pos, token.line)
393 case itemContinue:
394 return t.continueControl(token.pos, token.line)
395 case itemElse:
396 return t.elseControl()
397 case itemEnd:
398 return t.endControl()
399 case itemIf:
400 return t.ifControl()
401 case itemRange:
402 return t.rangeControl()
403 case itemTemplate:
404 return t.templateControl()
405 case itemWith:
406 return t.withControl()
407 }
408 t.backup()
409 token := t.peek()
410
411 return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim))
412 }
413
414
415
416
417 func (t *Tree) breakControl(pos Pos, line int) Node {
418 if token := t.nextNonSpace(); token.typ != itemRightDelim {
419 t.unexpected(token, "{{break}}")
420 }
421 if t.rangeDepth == 0 {
422 t.errorf("{{break}} outside {{range}}")
423 }
424 return t.newBreak(pos, line)
425 }
426
427
428
429
430 func (t *Tree) continueControl(pos Pos, line int) Node {
431 if token := t.nextNonSpace(); token.typ != itemRightDelim {
432 t.unexpected(token, "{{continue}}")
433 }
434 if t.rangeDepth == 0 {
435 t.errorf("{{continue}} outside {{range}}")
436 }
437 return t.newContinue(pos, line)
438 }
439
440
441
442 func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) {
443 token := t.peekNonSpace()
444 pipe = t.newPipeline(token.pos, token.line, nil)
445
446 decls:
447 if v := t.peekNonSpace(); v.typ == itemVariable {
448 t.next()
449
450
451
452
453 tokenAfterVariable := t.peek()
454 next := t.peekNonSpace()
455 switch {
456 case next.typ == itemAssign, next.typ == itemDeclare:
457 pipe.IsAssign = next.typ == itemAssign
458 t.nextNonSpace()
459 pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val))
460 t.vars = append(t.vars, v.val)
461 case next.typ == itemChar && next.val == ",":
462 t.nextNonSpace()
463 pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val))
464 t.vars = append(t.vars, v.val)
465 if context == "range" && len(pipe.Decl) < 2 {
466 switch t.peekNonSpace().typ {
467 case itemVariable, itemRightDelim, itemRightParen:
468
469 goto decls
470 default:
471 t.errorf("range can only initialize variables")
472 }
473 }
474 t.errorf("too many declarations in %s", context)
475 case tokenAfterVariable.typ == itemSpace:
476 t.backup3(v, tokenAfterVariable)
477 default:
478 t.backup2(v)
479 }
480 }
481 for {
482 switch token := t.nextNonSpace(); token.typ {
483 case end:
484
485 t.checkPipeline(pipe, context)
486 return
487 case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
488 itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen:
489 t.backup()
490 pipe.append(t.command())
491 default:
492 t.unexpected(token, context)
493 }
494 }
495 }
496
497 func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
498
499 if len(pipe.Cmds) == 0 {
500 t.errorf("missing value for %s", context)
501 }
502
503 for i, c := range pipe.Cmds[1:] {
504 switch c.Args[0].Type() {
505 case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString:
506
507 t.errorf("non executable command in pipeline stage %d", i+2)
508 }
509 }
510 }
511
512 func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
513 defer t.popVars(len(t.vars))
514 pipe = t.pipeline(context, itemRightDelim)
515 if context == "range" {
516 t.rangeDepth++
517 }
518 var next Node
519 list, next = t.itemList()
520 if context == "range" {
521 t.rangeDepth--
522 }
523 switch next.Type() {
524 case nodeEnd:
525 case nodeElse:
526 if allowElseIf {
527
528
529
530
531
532
533
534
535 if t.peek().typ == itemIf {
536 t.next()
537 elseList = t.newList(next.Position())
538 elseList.append(t.ifControl())
539
540 break
541 }
542 }
543 elseList, next = t.itemList()
544 if next.Type() != nodeEnd {
545 t.errorf("expected end; found %s", next)
546 }
547 }
548 return pipe.Position(), pipe.Line, pipe, list, elseList
549 }
550
551
552
553
554
555 func (t *Tree) ifControl() Node {
556 return t.newIf(t.parseControl(true, "if"))
557 }
558
559
560
561
562
563 func (t *Tree) rangeControl() Node {
564 r := t.newRange(t.parseControl(false, "range"))
565 return r
566 }
567
568
569
570
571
572 func (t *Tree) withControl() Node {
573 return t.newWith(t.parseControl(false, "with"))
574 }
575
576
577
578
579 func (t *Tree) endControl() Node {
580 return t.newEnd(t.expect(itemRightDelim, "end").pos)
581 }
582
583
584
585
586 func (t *Tree) elseControl() Node {
587
588 peek := t.peekNonSpace()
589 if peek.typ == itemIf {
590
591 return t.newElse(peek.pos, peek.line)
592 }
593 token := t.expect(itemRightDelim, "else")
594 return t.newElse(token.pos, token.line)
595 }
596
597
598
599
600
601
602 func (t *Tree) blockControl() Node {
603 const context = "block clause"
604
605 token := t.nextNonSpace()
606 name := t.parseTemplateName(token, context)
607 pipe := t.pipeline(context, itemRightDelim)
608
609 block := New(name)
610 block.text = t.text
611 block.Mode = t.Mode
612 block.ParseName = t.ParseName
613 block.startParse(t.funcs, t.lex, t.treeSet)
614 var end Node
615 block.Root, end = block.itemList()
616 if end.Type() != nodeEnd {
617 t.errorf("unexpected %s in %s", end, context)
618 }
619 block.add()
620 block.stopParse()
621
622 return t.newTemplate(token.pos, token.line, name, pipe)
623 }
624
625
626
627
628
629 func (t *Tree) templateControl() Node {
630 const context = "template clause"
631 token := t.nextNonSpace()
632 name := t.parseTemplateName(token, context)
633 var pipe *PipeNode
634 if t.nextNonSpace().typ != itemRightDelim {
635 t.backup()
636
637 pipe = t.pipeline(context, itemRightDelim)
638 }
639 return t.newTemplate(token.pos, token.line, name, pipe)
640 }
641
642 func (t *Tree) parseTemplateName(token item, context string) (name string) {
643 switch token.typ {
644 case itemString, itemRawString:
645 s, err := strconv.Unquote(token.val)
646 if err != nil {
647 t.error(err)
648 }
649 name = s
650 default:
651 t.unexpected(token, context)
652 }
653 return
654 }
655
656
657
658
659
660 func (t *Tree) command() *CommandNode {
661 cmd := t.newCommand(t.peekNonSpace().pos)
662 for {
663 t.peekNonSpace()
664 operand := t.operand()
665 if operand != nil {
666 cmd.append(operand)
667 }
668 switch token := t.next(); token.typ {
669 case itemSpace:
670 continue
671 case itemRightDelim, itemRightParen:
672 t.backup()
673 case itemPipe:
674
675 default:
676 t.unexpected(token, "operand")
677 }
678 break
679 }
680 if len(cmd.Args) == 0 {
681 t.errorf("empty command")
682 }
683 return cmd
684 }
685
686
687
688
689
690
691 func (t *Tree) operand() Node {
692 node := t.term()
693 if node == nil {
694 return nil
695 }
696 if t.peek().typ == itemField {
697 chain := t.newChain(t.peek().pos, node)
698 for t.peek().typ == itemField {
699 chain.Add(t.next().val)
700 }
701
702
703
704
705
706 switch node.Type() {
707 case NodeField:
708 node = t.newField(chain.Position(), chain.String())
709 case NodeVariable:
710 node = t.newVariable(chain.Position(), chain.String())
711 case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
712 t.errorf("unexpected . after term %q", node.String())
713 default:
714 node = chain
715 }
716 }
717 return node
718 }
719
720
721
722
723
724
725
726
727
728
729 func (t *Tree) term() Node {
730 switch token := t.nextNonSpace(); token.typ {
731 case itemIdentifier:
732 checkFunc := t.Mode&SkipFuncCheck == 0
733 if checkFunc && !t.hasFunction(token.val) {
734 t.errorf("function %q not defined", token.val)
735 }
736 return NewIdentifier(token.val).SetTree(t).SetPos(token.pos)
737 case itemDot:
738 return t.newDot(token.pos)
739 case itemNil:
740 return t.newNil(token.pos)
741 case itemVariable:
742 return t.useVar(token.pos, token.val)
743 case itemField:
744 return t.newField(token.pos, token.val)
745 case itemBool:
746 return t.newBool(token.pos, token.val == "true")
747 case itemCharConstant, itemComplex, itemNumber:
748 number, err := t.newNumber(token.pos, token.val, token.typ)
749 if err != nil {
750 t.error(err)
751 }
752 return number
753 case itemLeftParen:
754 return t.pipeline("parenthesized pipeline", itemRightParen)
755 case itemString, itemRawString:
756 s, err := strconv.Unquote(token.val)
757 if err != nil {
758 t.error(err)
759 }
760 return t.newString(token.pos, token.val, s)
761 }
762 t.backup()
763 return nil
764 }
765
766
767 func (t *Tree) hasFunction(name string) bool {
768 for _, funcMap := range t.funcs {
769 if funcMap == nil {
770 continue
771 }
772 if funcMap[name] != nil {
773 return true
774 }
775 }
776 return false
777 }
778
779
780 func (t *Tree) popVars(n int) {
781 t.vars = t.vars[:n]
782 }
783
784
785
786 func (t *Tree) useVar(pos Pos, name string) Node {
787 v := t.newVariable(pos, name)
788 for _, varName := range t.vars {
789 if varName == v.Ident[0] {
790 return v
791 }
792 }
793 t.errorf("undefined variable %q", v.Ident[0])
794 return nil
795 }
796
View as plain text