]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: allow using -}} with many spaces
authorDaniel Martí <mvdan@mvdan.cc>
Wed, 20 Mar 2019 15:47:56 +0000 (15:47 +0000)
committerRob Pike <r@golang.org>
Sun, 24 Mar 2019 09:06:14 +0000 (09:06 +0000)
lexSpace consumed all spaces, even if the last one was part of a right
delimiter like " -}}". Thus, "3  -}}" wouldn't lex as "3" and a right
delimiter, but as "3", "-", and "}}".

To fix that, make lexSpace stop if it encounters a right delimiter.

Fixes #30948.

Change-Id: I80a5546e5809e54f6823e2bf3a57a7e8808329be
Reviewed-on: https://go-review.googlesource.com/c/go/+/168457
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
src/text/template/parse/lex.go
src/text/template/parse/parse_test.go

index 92b97f423f5161b37e6b791be9c55ca8f43cd250..3d57708796ca795ef0c485ad5e630f3a8f5a09c1 100644 (file)
@@ -107,17 +107,18 @@ type stateFn func(*lexer) stateFn
 
 // lexer holds the state of the scanner.
 type lexer struct {
-       name       string    // the name of the input; used only for error reports
-       input      string    // the string being scanned
-       leftDelim  string    // start of action
-       rightDelim string    // end of action
-       pos        Pos       // current position in the input
-       start      Pos       // start position of this item
-       width      Pos       // width of last rune read from input
-       items      chan item // channel of scanned items
-       parenDepth int       // nesting depth of ( ) exprs
-       line       int       // 1+number of newlines seen
-       startLine  int       // start line of this item
+       name           string    // the name of the input; used only for error reports
+       input          string    // the string being scanned
+       leftDelim      string    // start of action
+       rightDelim     string    // end of action
+       trimRightDelim string    // end of action with trim marker
+       pos            Pos       // current position in the input
+       start          Pos       // start position of this item
+       width          Pos       // width of last rune read from input
+       items          chan item // channel of scanned items
+       parenDepth     int       // nesting depth of ( ) exprs
+       line           int       // 1+number of newlines seen
+       startLine      int       // start line of this item
 }
 
 // next returns the next rune in the input.
@@ -210,13 +211,14 @@ func lex(name, input, left, right string) *lexer {
                right = rightDelim
        }
        l := &lexer{
-               name:       name,
-               input:      input,
-               leftDelim:  left,
-               rightDelim: right,
-               items:      make(chan item),
-               line:       1,
-               startLine:  1,
+               name:           name,
+               input:          input,
+               leftDelim:      left,
+               rightDelim:     right,
+               trimRightDelim: rightTrimMarker + right,
+               items:          make(chan item),
+               line:           1,
+               startLine:      1,
        }
        go l.run()
        return l
@@ -275,14 +277,12 @@ func rightTrimLength(s string) Pos {
 
 // atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker.
 func (l *lexer) atRightDelim() (delim, trimSpaces bool) {
-       if strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
-               return true, false
-       }
-       // The right delim might have the marker before.
-       if strings.HasPrefix(l.input[l.pos:], rightTrimMarker) &&
-               strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) {
+       if strings.HasPrefix(l.input[l.pos:], l.trimRightDelim) { // With trim marker.
                return true, true
        }
+       if strings.HasPrefix(l.input[l.pos:], l.rightDelim) { // Without trim marker.
+               return true, false
+       }
        return false, false
 }
 
@@ -366,6 +366,7 @@ func lexInsideAction(l *lexer) stateFn {
        case r == eof || isEndOfLine(r):
                return l.errorf("unclosed action")
        case isSpace(r):
+               l.backup() // Put space back in case we have " -}}".
                return lexSpace
        case r == '=':
                l.emit(itemAssign)
@@ -418,10 +419,26 @@ func lexInsideAction(l *lexer) stateFn {
 }
 
 // lexSpace scans a run of space characters.
-// One space has already been seen.
+// We have not consumed the first space, which is known to be present.
+// Take care if there is a trim-marked right delimiter, which starts with a space.
 func lexSpace(l *lexer) stateFn {
-       for isSpace(l.peek()) {
+       var r rune
+       var numSpaces int
+       for {
+               r = l.peek()
+               if !isSpace(r) {
+                       break
+               }
                l.next()
+               numSpaces++
+       }
+       // Be careful about a trim-marked closing delimiter, which has a minus
+       // after a space. We know there is a space, so check for the '-' that might follow.
+       if strings.HasPrefix(l.input[l.pos-1:], l.trimRightDelim) {
+               l.backup() // Before the space.
+               if numSpaces == 1 {
+                       return lexRightDelim // On the delim, so go right to that.
+               }
        }
        l.emit(itemSpace)
        return lexInsideAction
index 5cb41d0bf5b6b0f015dee3d142a77336da0cab9e..6932cf232ea4a4e5f7a7d41def31a263786b96bc 100644 (file)
@@ -244,6 +244,7 @@ var parseTests = []parseTest{
        {"trim left", "x \r\n\t{{- 3}}", noError, `"x"{{3}}`},
        {"trim right", "{{3 -}}\n\n\ty", noError, `{{3}}"y"`},
        {"trim left and right", "x \r\n\t{{- 3 -}}\n\n\ty", noError, `"x"{{3}}"y"`},
+       {"trim with extra spaces", "x\n{{-  3   -}}\ny", noError, `"x"{{3}}"y"`},
        {"comment trim left", "x \r\n\t{{- /* hi */}}", noError, `"x"`},
        {"comment trim right", "{{/* hi */ -}}\n\n\ty", noError, `"y"`},
        {"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`},