mirror of
https://github.com/golang/go
synced 2024-11-13 17:40:23 -07:00
text/template: fix a couple of parse bugs around identifiers.
1) Poor error checking in variable declarations admitted $x=2 or even $x%2. 2) Need white space or suitable termination character after identifiers, so $x+2 doesn't parse, in case we want it to mean something one day. Number 2 in particular prevents mistakes that we will have to honor later and so is necessary for Go 1. Fixes #3270. Fixes #3271. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/5795073
This commit is contained in:
parent
5361712ab4
commit
8170d81f4f
@ -93,7 +93,7 @@ var multiExecTests = []execTest{
|
||||
{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
|
||||
{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
|
||||
{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
|
||||
{"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
|
||||
{"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
|
||||
|
||||
// User-defined function: test argument evaluator.
|
||||
{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
|
||||
|
@ -347,6 +347,9 @@ Loop:
|
||||
default:
|
||||
l.backup()
|
||||
word := l.input[l.start:l.pos]
|
||||
if !l.atTerminator() {
|
||||
return l.errorf("unexpected character %+U", r)
|
||||
}
|
||||
switch {
|
||||
case key[word] > itemKeyword:
|
||||
l.emit(key[word])
|
||||
@ -365,6 +368,28 @@ Loop:
|
||||
return lexInsideAction
|
||||
}
|
||||
|
||||
// atTerminator reports whether the input is at valid termination character to
|
||||
// appear after an identifier. Mostly to catch cases like "$x+2" not being
|
||||
// acceptable without a space, in case we decide one day to implement
|
||||
// arithmetic.
|
||||
func (l *lexer) atTerminator() bool {
|
||||
r := l.peek()
|
||||
if isSpace(r) {
|
||||
return true
|
||||
}
|
||||
switch r {
|
||||
case eof, ',', '|', ':':
|
||||
return true
|
||||
}
|
||||
// Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will
|
||||
// succeed but should fail) but only in extremely rare cases caused by willfully
|
||||
// bad choice of delimiter.
|
||||
if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// lexChar scans a character constant. The initial quote is already
|
||||
// scanned. Syntax checking is done by the parse.
|
||||
func lexChar(l *lexer) stateFn {
|
||||
|
@ -326,7 +326,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
|
||||
for {
|
||||
if v := t.peek(); v.typ == itemVariable {
|
||||
t.next()
|
||||
if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
|
||||
if next := t.peek(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
|
||||
t.next()
|
||||
variable := newVariable(v.val)
|
||||
if len(variable.Ident) != 1 {
|
||||
|
@ -201,6 +201,10 @@ var parseTests = []parseTest{
|
||||
`{{range .X | .M}}"true"{{else}}"false"{{end}}`},
|
||||
{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
|
||||
`{{range .SI}}{{.}}{{end}}`},
|
||||
{"range 1 var", "{{range $x := .SI}}{{.}}{{end}}", noError,
|
||||
`{{range $x := .SI}}{{.}}{{end}}`},
|
||||
{"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
|
||||
`{{range $x, $y := .SI}}{{.}}{{end}}`},
|
||||
{"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError,
|
||||
`{{range .SI 1 -3.2i true false 'a'}}{{end}}`},
|
||||
{"template", "{{template `x`}}", noError,
|
||||
@ -226,6 +230,17 @@ var parseTests = []parseTest{
|
||||
{"invalid punctuation", "{{printf 3, 4}}", hasError, ""},
|
||||
{"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""},
|
||||
{"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""},
|
||||
// Equals (and other chars) do not assignments make (yet).
|
||||
{"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"},
|
||||
{"bug0b", "{{$x = 1}}{{$x}}", hasError, ""},
|
||||
{"bug0c", "{{$x ! 2}}{{$x}}", hasError, ""},
|
||||
{"bug0d", "{{$x % 3}}{{$x}}", hasError, ""},
|
||||
// Check the parse fails for := rather than comma.
|
||||
{"bug0e", "{{range $x := $y := 3}}{{end}}", hasError, ""},
|
||||
// Another bug: variable read must ignore following punctuation.
|
||||
{"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""}, // ! is just illegal here.
|
||||
{"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""}, // $x+2 should not parse as ($x) (+2).
|
||||
{"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
|
||||
}
|
||||
|
||||
var builtins = map[string]interface{}{
|
||||
|
Loading…
Reference in New Issue
Block a user