tpls

Extendable, Fast Template Engine for Go
git clone git://git.lair.cx/tpls
Log | Files | Refs | README | LICENSE

builtin_fallback.go (1326B)


      1 package tplc
      2 
      3 import (
      4 	"bytes"
      5 	"fmt"
      6 	"io"
      7 	"strconv"
      8 
      9 	"github.com/valyala/bytebufferpool"
     10 
     11 	"go.lair.cx/go-core/net/htmlx"
     12 	"go.lair.cx/tpls/internal/stacks"
     13 )
     14 
     15 // TagFallback skips current tag.
     16 func TagFallback(name string) TagHandler {
     17 	return func(_ *Builder, w *Writer, t *htmlx.Tokenizer) error {
     18 		if t.CurrentType() == htmlx.SelfClosingTagToken {
     19 			return nil
     20 		}
     21 
     22 		stackBuf := bytebufferpool.Get()
     23 		defer bytebufferpool.Put(stackBuf)
     24 
     25 		stack := stacks.NewByteStack(stackBuf.B)
     26 
     27 	loop:
     28 		for {
     29 			switch t.Next() {
     30 			case htmlx.StartTagToken:
     31 				tagName, _ := t.TagName()
     32 				stack.Put(tagName)
     33 
     34 			case htmlx.EndTagToken:
     35 				tagName, _ := t.TagName()
     36 
     37 				// Remove items in stack until the matched starting tag is found.
     38 				// If the tag is not exists in stack,
     39 				//   - Root tag's closing.
     40 				//   - Unexpected closing tag.
     41 				for {
     42 					item, ok := stack.Pop()
     43 					if !ok { // Tag is not found:
     44 						if string(tagName) == name {
     45 							break loop
     46 						}
     47 						return fmt.Errorf(
     48 							"unexpected closing tag: %s",
     49 							strconv.Quote(string(tagName)),
     50 						)
     51 					}
     52 					if bytes.Equal(item, tagName) {
     53 						break
     54 					}
     55 				}
     56 
     57 			case htmlx.ErrorToken:
     58 				err := t.Err()
     59 				if err == io.EOF {
     60 					return io.ErrUnexpectedEOF
     61 				} else {
     62 					return err
     63 				}
     64 			}
     65 		}
     66 
     67 		return nil
     68 	}
     69 }