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]interface{}
28 lex *lexer
29 token [3]item
30 peekCount int
31 vars []string
32 treeSet map[string]*Tree
33 actionLine int
34 mode Mode
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]interface{}) (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]interface{}) *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 ...interface{}) {
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]interface{}, 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 }
228
229
230 func (t *Tree) stopParse() {
231 t.lex = nil
232 t.vars = nil
233 t.funcs = nil
234 t.treeSet = nil
235 }
236
237
238
239
240
241 func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
242 defer t.recover(&err)
243 t.ParseName = t.Name
244 emitComment := t.Mode&ParseComments != 0
245 t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim, emitComment), treeSet)
246 t.text = text
247 t.parse()
248 t.add()
249 t.stopParse()
250 return t, nil
251 }
252
253
254 func (t *Tree) add() {
255 tree := t.treeSet[t.Name]
256 if tree == nil || IsEmptyTree(tree.Root) {
257 t.treeSet[t.Name] = t
258 return
259 }
260 if !IsEmptyTree(t.Root) {
261 t.errorf("template: multiple definition of template %q", t.Name)
262 }
263 }
264
265
266 func IsEmptyTree(n Node) bool {
267 switch n := n.(type) {
268 case nil:
269 return true
270 case *ActionNode:
271 case *CommentNode:
272 return true
273 case *IfNode:
274 case *ListNode:
275 for _, node := range n.Nodes {
276 if !IsEmptyTree(node) {
277 return false
278 }
279 }
280 return true
281 case *RangeNode:
282 case *TemplateNode:
283 case *TextNode:
284 return len(bytes.TrimSpace(n.Text)) == 0
285 case *WithNode:
286 default:
287 panic("unknown node: " + n.String())
288 }
289 return false
290 }
291
292
293
294
295 func (t *Tree) parse() {
296 t.Root = t.newList(t.peek().pos)
297 for t.peek().typ != itemEOF {
298 if t.peek().typ == itemLeftDelim {
299 delim := t.next()
300 if t.nextNonSpace().typ == itemDefine {
301 newT := New("definition")
302 newT.text = t.text
303 newT.Mode = t.Mode
304 newT.ParseName = t.ParseName
305 newT.startParse(t.funcs, t.lex, t.treeSet)
306 newT.parseDefinition()
307 continue
308 }
309 t.backup2(delim)
310 }
311 switch n := t.textOrAction(); n.Type() {
312 case nodeEnd, nodeElse:
313 t.errorf("unexpected %s", n)
314 default:
315 t.Root.append(n)
316 }
317 }
318 }
319
320
321
322
323 func (t *Tree) parseDefinition() {
324 const context = "define clause"
325 name := t.expectOneOf(itemString, itemRawString, context)
326 var err error
327 t.Name, err = strconv.Unquote(name.val)
328 if err != nil {
329 t.error(err)
330 }
331 t.expect(itemRightDelim, context)
332 var end Node
333 t.Root, end = t.itemList()
334 if end.Type() != nodeEnd {
335 t.errorf("unexpected %s in %s", end, context)
336 }
337 t.add()
338 t.stopParse()
339 }
340
341
342
343
344 func (t *Tree) itemList() (list *ListNode, next Node) {
345 list = t.newList(t.peekNonSpace().pos)
346 for t.peekNonSpace().typ != itemEOF {
347 n := t.textOrAction()
348 switch n.Type() {
349 case nodeEnd, nodeElse:
350 return list, n
351 }
352 list.append(n)
353 }
354 t.errorf("unexpected EOF")
355 return
356 }
357
358
359
360 func (t *Tree) textOrAction() Node {
361 switch token := t.nextNonSpace(); token.typ {
362 case itemText:
363 return t.newText(token.pos, token.val)
364 case itemLeftDelim:
365 t.actionLine = token.line
366 defer t.clearActionLine()
367 return t.action()
368 case itemComment:
369 return t.newComment(token.pos, token.val)
370 default:
371 t.unexpected(token, "input")
372 }
373 return nil
374 }
375
376 func (t *Tree) clearActionLine() {
377 t.actionLine = 0
378 }
379
380
381
382
383
384
385 func (t *Tree) action() (n Node) {
386 switch token := t.nextNonSpace(); token.typ {
387 case itemBlock:
388 return t.blockControl()
389 case itemElse:
390 return t.elseControl()
391 case itemEnd:
392 return t.endControl()
393 case itemIf:
394 return t.ifControl()
395 case itemRange:
396 return t.rangeControl()
397 case itemTemplate:
398 return t.templateControl()
399 case itemWith:
400 return t.withControl()
401 }
402 t.backup()
403 token := t.peek()
404
405 return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim))
406 }
407
408
409
410 func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) {
411 token := t.peekNonSpace()
412 pipe = t.newPipeline(token.pos, token.line, nil)
413
414 decls:
415 if v := t.peekNonSpace(); v.typ == itemVariable {
416 t.next()
417
418
419
420
421 tokenAfterVariable := t.peek()
422 next := t.peekNonSpace()
423 switch {
424 case next.typ == itemAssign, next.typ == itemDeclare:
425 pipe.IsAssign = next.typ == itemAssign
426 t.nextNonSpace()
427 pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val))
428 t.vars = append(t.vars, v.val)
429 case next.typ == itemChar && next.val == ",":
430 t.nextNonSpace()
431 pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val))
432 t.vars = append(t.vars, v.val)
433 if context == "range" && len(pipe.Decl) < 2 {
434 switch t.peekNonSpace().typ {
435 case itemVariable, itemRightDelim, itemRightParen:
436
437 goto decls
438 default:
439 t.errorf("range can only initialize variables")
440 }
441 }
442 t.errorf("too many declarations in %s", context)
443 case tokenAfterVariable.typ == itemSpace:
444 t.backup3(v, tokenAfterVariable)
445 default:
446 t.backup2(v)
447 }
448 }
449 for {
450 switch token := t.nextNonSpace(); token.typ {
451 case end:
452
453 t.checkPipeline(pipe, context)
454 return
455 case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
456 itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen:
457 t.backup()
458 pipe.append(t.command())
459 default:
460 t.unexpected(token, context)
461 }
462 }
463 }
464
465 func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
466
467 if len(pipe.Cmds) == 0 {
468 t.errorf("missing value for %s", context)
469 }
470
471 for i, c := range pipe.Cmds[1:] {
472 switch c.Args[0].Type() {
473 case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString:
474
475 t.errorf("non executable command in pipeline stage %d", i+2)
476 }
477 }
478 }
479
480 func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
481 defer t.popVars(len(t.vars))
482 pipe = t.pipeline(context, itemRightDelim)
483 var next Node
484 list, next = t.itemList()
485 switch next.Type() {
486 case nodeEnd:
487 case nodeElse:
488 if allowElseIf {
489
490
491
492
493
494
495
496
497 if t.peek().typ == itemIf {
498 t.next()
499 elseList = t.newList(next.Position())
500 elseList.append(t.ifControl())
501
502 break
503 }
504 }
505 elseList, next = t.itemList()
506 if next.Type() != nodeEnd {
507 t.errorf("expected end; found %s", next)
508 }
509 }
510 return pipe.Position(), pipe.Line, pipe, list, elseList
511 }
512
513
514
515
516
517 func (t *Tree) ifControl() Node {
518 return t.newIf(t.parseControl(true, "if"))
519 }
520
521
522
523
524
525 func (t *Tree) rangeControl() Node {
526 return t.newRange(t.parseControl(false, "range"))
527 }
528
529
530
531
532
533 func (t *Tree) withControl() Node {
534 return t.newWith(t.parseControl(false, "with"))
535 }
536
537
538
539
540 func (t *Tree) endControl() Node {
541 return t.newEnd(t.expect(itemRightDelim, "end").pos)
542 }
543
544
545
546
547 func (t *Tree) elseControl() Node {
548
549 peek := t.peekNonSpace()
550 if peek.typ == itemIf {
551
552 return t.newElse(peek.pos, peek.line)
553 }
554 token := t.expect(itemRightDelim, "else")
555 return t.newElse(token.pos, token.line)
556 }
557
558
559
560
561
562
563 func (t *Tree) blockControl() Node {
564 const context = "block clause"
565
566 token := t.nextNonSpace()
567 name := t.parseTemplateName(token, context)
568 pipe := t.pipeline(context, itemRightDelim)
569
570 block := New(name)
571 block.text = t.text
572 block.Mode = t.Mode
573 block.ParseName = t.ParseName
574 block.startParse(t.funcs, t.lex, t.treeSet)
575 var end Node
576 block.Root, end = block.itemList()
577 if end.Type() != nodeEnd {
578 t.errorf("unexpected %s in %s", end, context)
579 }
580 block.add()
581 block.stopParse()
582
583 return t.newTemplate(token.pos, token.line, name, pipe)
584 }
585
586
587
588
589
590 func (t *Tree) templateControl() Node {
591 const context = "template clause"
592 token := t.nextNonSpace()
593 name := t.parseTemplateName(token, context)
594 var pipe *PipeNode
595 if t.nextNonSpace().typ != itemRightDelim {
596 t.backup()
597
598 pipe = t.pipeline(context, itemRightDelim)
599 }
600 return t.newTemplate(token.pos, token.line, name, pipe)
601 }
602
603 func (t *Tree) parseTemplateName(token item, context string) (name string) {
604 switch token.typ {
605 case itemString, itemRawString:
606 s, err := strconv.Unquote(token.val)
607 if err != nil {
608 t.error(err)
609 }
610 name = s
611 default:
612 t.unexpected(token, context)
613 }
614 return
615 }
616
617
618
619
620
621 func (t *Tree) command() *CommandNode {
622 cmd := t.newCommand(t.peekNonSpace().pos)
623 for {
624 t.peekNonSpace()
625 operand := t.operand()
626 if operand != nil {
627 cmd.append(operand)
628 }
629 switch token := t.next(); token.typ {
630 case itemSpace:
631 continue
632 case itemRightDelim, itemRightParen:
633 t.backup()
634 case itemPipe:
635
636 default:
637 t.unexpected(token, "operand")
638 }
639 break
640 }
641 if len(cmd.Args) == 0 {
642 t.errorf("empty command")
643 }
644 return cmd
645 }
646
647
648
649
650
651
652 func (t *Tree) operand() Node {
653 node := t.term()
654 if node == nil {
655 return nil
656 }
657 if t.peek().typ == itemField {
658 chain := t.newChain(t.peek().pos, node)
659 for t.peek().typ == itemField {
660 chain.Add(t.next().val)
661 }
662
663
664
665
666
667 switch node.Type() {
668 case NodeField:
669 node = t.newField(chain.Position(), chain.String())
670 case NodeVariable:
671 node = t.newVariable(chain.Position(), chain.String())
672 case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
673 t.errorf("unexpected . after term %q", node.String())
674 default:
675 node = chain
676 }
677 }
678 return node
679 }
680
681
682
683
684
685
686
687
688
689
690 func (t *Tree) term() Node {
691 switch token := t.nextNonSpace(); token.typ {
692 case itemIdentifier:
693 checkFunc := t.Mode&SkipFuncCheck == 0
694 if checkFunc && !t.hasFunction(token.val) {
695 t.errorf("function %q not defined", token.val)
696 }
697 return NewIdentifier(token.val).SetTree(t).SetPos(token.pos)
698 case itemDot:
699 return t.newDot(token.pos)
700 case itemNil:
701 return t.newNil(token.pos)
702 case itemVariable:
703 return t.useVar(token.pos, token.val)
704 case itemField:
705 return t.newField(token.pos, token.val)
706 case itemBool:
707 return t.newBool(token.pos, token.val == "true")
708 case itemCharConstant, itemComplex, itemNumber:
709 number, err := t.newNumber(token.pos, token.val, token.typ)
710 if err != nil {
711 t.error(err)
712 }
713 return number
714 case itemLeftParen:
715 return t.pipeline("parenthesized pipeline", itemRightParen)
716 case itemString, itemRawString:
717 s, err := strconv.Unquote(token.val)
718 if err != nil {
719 t.error(err)
720 }
721 return t.newString(token.pos, token.val, s)
722 }
723 t.backup()
724 return nil
725 }
726
727
728 func (t *Tree) hasFunction(name string) bool {
729 for _, funcMap := range t.funcs {
730 if funcMap == nil {
731 continue
732 }
733 if funcMap[name] != nil {
734 return true
735 }
736 }
737 return false
738 }
739
740
741 func (t *Tree) popVars(n int) {
742 t.vars = t.vars[:n]
743 }
744
745
746
747 func (t *Tree) useVar(pos Pos, name string) Node {
748 v := t.newVariable(pos, name)
749 for _, varName := range t.vars {
750 if varName == v.Ident[0] {
751 return v
752 }
753 }
754 t.errorf("undefined variable %q", v.Ident[0])
755 return nil
756 }
757
View as plain text