From 9b8964bf2df0626530a0ca493e3e95d8dc3844dd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Mart=C3=AD?= Date: Wed, 6 Sep 2017 11:57:16 +0200 Subject: [PATCH] text/template: fix pos info when trimming newlines MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The lexer keeps the byte offset and the line for the rune it's currently on. This was simple enough up until whitespace trimming was introduced. With whitespace trimming, we might skip over newlines. In that case, the lexer wasn't properly updating the line counter. Fix it. Also, TestPos now checks that the line is correct too, which it was ignoring before. This was necessary to test this scenario in the lexer. Fixes #21778. Change-Id: I3880f3adf02662eac8f818d5caa6935cca9cb33b Reviewed-on: https://go-review.googlesource.com/61870 Run-TryBot: Daniel Martí Reviewed-by: Rob Pike TryBot-Result: Gobot Gobot --- src/text/template/parse/lex.go | 1 + src/text/template/parse/lex_test.go | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go index cdecd412ee..2cde4a2ca1 100644 --- a/src/text/template/parse/lex.go +++ b/src/text/template/parse/lex.go @@ -164,6 +164,7 @@ func (l *lexer) emit(t itemType) { // ignore skips over the pending input before this point. func (l *lexer) ignore() { + l.line += strings.Count(l.input[l.start:l.pos], "\n") l.start = l.pos } diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go index 2c73bb623a..cb01cd98b6 100644 --- a/src/text/template/parse/lex_test.go +++ b/src/text/template/parse/lex_test.go @@ -404,6 +404,9 @@ func equal(i1, i2 []item, checkPos bool) bool { if checkPos && i1[k].pos != i2[k].pos { return false } + if checkPos && i1[k].line != i2[k].line { + return false + } } return true } @@ -452,7 +455,7 @@ func TestDelims(t *testing.T) { } var lexPosTests = []lexTest{ - {"empty", "", []item{tEOF}}, + {"empty", "", []item{{itemEOF, 0, "", 1}}}, {"punctuation", "{{,@%#}}", []item{ {itemLeftDelim, 0, "{{", 1}, {itemChar, 2, ",", 1}, @@ -470,6 +473,24 @@ var lexPosTests = []lexTest{ {itemText, 13, "xyz", 1}, {itemEOF, 16, "", 1}, }}, + {"trimafter", "{{x -}}\n{{y}}", []item{ + {itemLeftDelim, 0, "{{", 1}, + {itemIdentifier, 2, "x", 1}, + {itemRightDelim, 5, "}}", 1}, + {itemLeftDelim, 8, "{{", 2}, + {itemIdentifier, 10, "y", 2}, + {itemRightDelim, 11, "}}", 2}, + {itemEOF, 13, "", 2}, + }}, + {"trimbefore", "{{x}}\n{{- y}}", []item{ + {itemLeftDelim, 0, "{{", 1}, + {itemIdentifier, 2, "x", 1}, + {itemRightDelim, 3, "}}", 1}, + {itemLeftDelim, 6, "{{", 2}, + {itemIdentifier, 10, "y", 2}, + {itemRightDelim, 11, "}}", 2}, + {itemEOF, 13, "", 2}, + }}, } // The other tests don't check position, to make the test cases easier to construct. @@ -485,7 +506,8 @@ func TestPos(t *testing.T) { if !equal(items[i:i+1], test.items[i:i+1], true) { i1 := items[i] i2 := test.items[i] - t.Errorf("\t#%d: got {%v %d %q} expected {%v %d %q}", i, i1.typ, i1.pos, i1.val, i2.typ, i2.pos, i2.val) + t.Errorf("\t#%d: got {%v %d %q %d} expected {%v %d %q %d}", + i, i1.typ, i1.pos, i1.val, i1.line, i2.typ, i2.pos, i2.val, i2.line) } } } -- 2.50.0