diff options
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch')
-rw-r--r-- | meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch new file mode 100644 index 0000000000..d5e2eb6684 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538_4.patch | |||
@@ -0,0 +1,497 @@ | |||
1 | From 760d88497091fb5d6d231a18e6f4e06ecb9af9b2 Mon Sep 17 00:00:00 2001 | ||
2 | From: Russ Cox <rsc@golang.org> | ||
3 | Date: Thu, 10 Sep 2020 18:53:26 -0400 | ||
4 | Subject: [PATCH 4/6] text/template: allow newlines inside action delimiters | ||
5 | |||
6 | This allows multiline constructs like: | ||
7 | |||
8 | {{"hello" | | ||
9 | printf}} | ||
10 | |||
11 | Now that unclosed actions can span multiple lines, | ||
12 | track and report the start of the action when reporting errors. | ||
13 | |||
14 | Also clean up a few "unexpected <error message>" to be just "<error message>". | ||
15 | |||
16 | Fixes #29770. | ||
17 | |||
18 | Change-Id: I54c6c016029a8328b7902a4b6d85eab713ec3285 | ||
19 | Reviewed-on: https://go-review.googlesource.com/c/go/+/254257 | ||
20 | Trust: Russ Cox <rsc@golang.org> | ||
21 | Run-TryBot: Russ Cox <rsc@golang.org> | ||
22 | TryBot-Result: Go Bot <gobot@golang.org> | ||
23 | Reviewed-by: Rob Pike <r@golang.org> | ||
24 | |||
25 | Dependency Patch #4 | ||
26 | |||
27 | Upstream-Status: Backport from https://github.com/golang/go/commit/9384d34c58099657bb1b133beaf3ff37ada9b017 | ||
28 | CVE: CVE-2023-24538 | ||
29 | Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> | ||
30 | --- | ||
31 | src/text/template/doc.go | 21 ++++----- | ||
32 | src/text/template/exec_test.go | 2 +- | ||
33 | src/text/template/parse/lex.go | 84 +++++++++++++++++------------------ | ||
34 | src/text/template/parse/lex_test.go | 2 +- | ||
35 | src/text/template/parse/parse.go | 59 +++++++++++++----------- | ||
36 | src/text/template/parse/parse_test.go | 36 ++++++++++++--- | ||
37 | 6 files changed, 117 insertions(+), 87 deletions(-) | ||
38 | |||
39 | diff --git a/src/text/template/doc.go b/src/text/template/doc.go | ||
40 | index 4b0efd2..7b30294 100644 | ||
41 | --- a/src/text/template/doc.go | ||
42 | +++ b/src/text/template/doc.go | ||
43 | @@ -40,16 +40,17 @@ More intricate examples appear below. | ||
44 | Text and spaces | ||
45 | |||
46 | By default, all text between actions is copied verbatim when the template is | ||
47 | -executed. For example, the string " items are made of " in the example above appears | ||
48 | -on standard output when the program is run. | ||
49 | - | ||
50 | -However, to aid in formatting template source code, if an action's left delimiter | ||
51 | -(by default "{{") is followed immediately by a minus sign and ASCII space character | ||
52 | -("{{- "), all trailing white space is trimmed from the immediately preceding text. | ||
53 | -Similarly, if the right delimiter ("}}") is preceded by a space and minus sign | ||
54 | -(" -}}"), all leading white space is trimmed from the immediately following text. | ||
55 | -In these trim markers, the ASCII space must be present; "{{-3}}" parses as an | ||
56 | -action containing the number -3. | ||
57 | +executed. For example, the string " items are made of " in the example above | ||
58 | +appears on standard output when the program is run. | ||
59 | + | ||
60 | +However, to aid in formatting template source code, if an action's left | ||
61 | +delimiter (by default "{{") is followed immediately by a minus sign and white | ||
62 | +space, all trailing white space is trimmed from the immediately preceding text. | ||
63 | +Similarly, if the right delimiter ("}}") is preceded by white space and a minus | ||
64 | +sign, all leading white space is trimmed from the immediately following text. | ||
65 | +In these trim markers, the white space must be present: | ||
66 | +"{{- 3}}" is like "{{3}}" but trims the immediately preceding text, while | ||
67 | +"{{-3}}" parses as an action containing the number -3. | ||
68 | |||
69 | For instance, when executing the template whose source is | ||
70 | |||
71 | diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go | ||
72 | index b8a809e..3309b33 100644 | ||
73 | --- a/src/text/template/exec_test.go | ||
74 | +++ b/src/text/template/exec_test.go | ||
75 | @@ -1295,7 +1295,7 @@ func TestUnterminatedStringError(t *testing.T) { | ||
76 | t.Fatal("expected error") | ||
77 | } | ||
78 | str := err.Error() | ||
79 | - if !strings.Contains(str, "X:3: unexpected unterminated raw quoted string") { | ||
80 | + if !strings.Contains(str, "X:3: unterminated raw quoted string") { | ||
81 | t.Fatalf("unexpected error: %s", str) | ||
82 | } | ||
83 | } | ||
84 | diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go | ||
85 | index e41373a..6784071 100644 | ||
86 | --- a/src/text/template/parse/lex.go | ||
87 | +++ b/src/text/template/parse/lex.go | ||
88 | @@ -92,15 +92,14 @@ const eof = -1 | ||
89 | // If the action begins "{{- " rather than "{{", then all space/tab/newlines | ||
90 | // preceding the action are trimmed; conversely if it ends " -}}" the | ||
91 | // leading spaces are trimmed. This is done entirely in the lexer; the | ||
92 | -// parser never sees it happen. We require an ASCII space to be | ||
93 | -// present to avoid ambiguity with things like "{{-3}}". It reads | ||
94 | +// parser never sees it happen. We require an ASCII space (' ', \t, \r, \n) | ||
95 | +// to be present to avoid ambiguity with things like "{{-3}}". It reads | ||
96 | // better with the space present anyway. For simplicity, only ASCII | ||
97 | -// space does the job. | ||
98 | +// does the job. | ||
99 | const ( | ||
100 | - spaceChars = " \t\r\n" // These are the space characters defined by Go itself. | ||
101 | - leftTrimMarker = "- " // Attached to left delimiter, trims trailing spaces from preceding text. | ||
102 | - rightTrimMarker = " -" // Attached to right delimiter, trims leading spaces from following text. | ||
103 | - trimMarkerLen = Pos(len(leftTrimMarker)) | ||
104 | + spaceChars = " \t\r\n" // These are the space characters defined by Go itself. | ||
105 | + trimMarker = '-' // Attached to left/right delimiter, trims trailing spaces from preceding/following text. | ||
106 | + trimMarkerLen = Pos(1 + 1) // marker plus space before or after | ||
107 | ) | ||
108 | |||
109 | // stateFn represents the state of the scanner as a function that returns the next state. | ||
110 | @@ -108,19 +107,18 @@ type stateFn func(*lexer) stateFn | ||
111 | |||
112 | // lexer holds the state of the scanner. | ||
113 | type lexer struct { | ||
114 | - name string // the name of the input; used only for error reports | ||
115 | - input string // the string being scanned | ||
116 | - leftDelim string // start of action | ||
117 | - rightDelim string // end of action | ||
118 | - trimRightDelim string // end of action with trim marker | ||
119 | - emitComment bool // emit itemComment tokens. | ||
120 | - pos Pos // current position in the input | ||
121 | - start Pos // start position of this item | ||
122 | - width Pos // width of last rune read from input | ||
123 | - items chan item // channel of scanned items | ||
124 | - parenDepth int // nesting depth of ( ) exprs | ||
125 | - line int // 1+number of newlines seen | ||
126 | - startLine int // start line of this item | ||
127 | + name string // the name of the input; used only for error reports | ||
128 | + input string // the string being scanned | ||
129 | + leftDelim string // start of action | ||
130 | + rightDelim string // end of action | ||
131 | + emitComment bool // emit itemComment tokens. | ||
132 | + pos Pos // current position in the input | ||
133 | + start Pos // start position of this item | ||
134 | + width Pos // width of last rune read from input | ||
135 | + items chan item // channel of scanned items | ||
136 | + parenDepth int // nesting depth of ( ) exprs | ||
137 | + line int // 1+number of newlines seen | ||
138 | + startLine int // start line of this item | ||
139 | } | ||
140 | |||
141 | // next returns the next rune in the input. | ||
142 | @@ -213,15 +211,14 @@ func lex(name, input, left, right string, emitComment bool) *lexer { | ||
143 | right = rightDelim | ||
144 | } | ||
145 | l := &lexer{ | ||
146 | - name: name, | ||
147 | - input: input, | ||
148 | - leftDelim: left, | ||
149 | - rightDelim: right, | ||
150 | - trimRightDelim: rightTrimMarker + right, | ||
151 | - emitComment: emitComment, | ||
152 | - items: make(chan item), | ||
153 | - line: 1, | ||
154 | - startLine: 1, | ||
155 | + name: name, | ||
156 | + input: input, | ||
157 | + leftDelim: left, | ||
158 | + rightDelim: right, | ||
159 | + emitComment: emitComment, | ||
160 | + items: make(chan item), | ||
161 | + line: 1, | ||
162 | + startLine: 1, | ||
163 | } | ||
164 | go l.run() | ||
165 | return l | ||
166 | @@ -251,7 +248,7 @@ func lexText(l *lexer) stateFn { | ||
167 | ldn := Pos(len(l.leftDelim)) | ||
168 | l.pos += Pos(x) | ||
169 | trimLength := Pos(0) | ||
170 | - if strings.HasPrefix(l.input[l.pos+ldn:], leftTrimMarker) { | ||
171 | + if hasLeftTrimMarker(l.input[l.pos+ldn:]) { | ||
172 | trimLength = rightTrimLength(l.input[l.start:l.pos]) | ||
173 | } | ||
174 | l.pos -= trimLength | ||
175 | @@ -280,7 +277,7 @@ func rightTrimLength(s string) Pos { | ||
176 | |||
177 | // atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker. | ||
178 | func (l *lexer) atRightDelim() (delim, trimSpaces bool) { | ||
179 | - if strings.HasPrefix(l.input[l.pos:], l.trimRightDelim) { // With trim marker. | ||
180 | + if hasRightTrimMarker(l.input[l.pos:]) && strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) { // With trim marker. | ||
181 | return true, true | ||
182 | } | ||
183 | if strings.HasPrefix(l.input[l.pos:], l.rightDelim) { // Without trim marker. | ||
184 | @@ -297,7 +294,7 @@ func leftTrimLength(s string) Pos { | ||
185 | // lexLeftDelim scans the left delimiter, which is known to be present, possibly with a trim marker. | ||
186 | func lexLeftDelim(l *lexer) stateFn { | ||
187 | l.pos += Pos(len(l.leftDelim)) | ||
188 | - trimSpace := strings.HasPrefix(l.input[l.pos:], leftTrimMarker) | ||
189 | + trimSpace := hasLeftTrimMarker(l.input[l.pos:]) | ||
190 | afterMarker := Pos(0) | ||
191 | if trimSpace { | ||
192 | afterMarker = trimMarkerLen | ||
193 | @@ -342,7 +339,7 @@ func lexComment(l *lexer) stateFn { | ||
194 | |||
195 | // lexRightDelim scans the right delimiter, which is known to be present, possibly with a trim marker. | ||
196 | func lexRightDelim(l *lexer) stateFn { | ||
197 | - trimSpace := strings.HasPrefix(l.input[l.pos:], rightTrimMarker) | ||
198 | + trimSpace := hasRightTrimMarker(l.input[l.pos:]) | ||
199 | if trimSpace { | ||
200 | l.pos += trimMarkerLen | ||
201 | l.ignore() | ||
202 | @@ -369,7 +366,7 @@ func lexInsideAction(l *lexer) stateFn { | ||
203 | return l.errorf("unclosed left paren") | ||
204 | } | ||
205 | switch r := l.next(); { | ||
206 | - case r == eof || isEndOfLine(r): | ||
207 | + case r == eof: | ||
208 | return l.errorf("unclosed action") | ||
209 | case isSpace(r): | ||
210 | l.backup() // Put space back in case we have " -}}". | ||
211 | @@ -439,7 +436,7 @@ func lexSpace(l *lexer) stateFn { | ||
212 | } | ||
213 | // Be careful about a trim-marked closing delimiter, which has a minus | ||
214 | // after a space. We know there is a space, so check for the '-' that might follow. | ||
215 | - if strings.HasPrefix(l.input[l.pos-1:], l.trimRightDelim) { | ||
216 | + if hasRightTrimMarker(l.input[l.pos-1:]) && strings.HasPrefix(l.input[l.pos-1+trimMarkerLen:], l.rightDelim) { | ||
217 | l.backup() // Before the space. | ||
218 | if numSpaces == 1 { | ||
219 | return lexRightDelim // On the delim, so go right to that. | ||
220 | @@ -526,7 +523,7 @@ func lexFieldOrVariable(l *lexer, typ itemType) stateFn { | ||
221 | // day to implement arithmetic. | ||
222 | func (l *lexer) atTerminator() bool { | ||
223 | r := l.peek() | ||
224 | - if isSpace(r) || isEndOfLine(r) { | ||
225 | + if isSpace(r) { | ||
226 | return true | ||
227 | } | ||
228 | switch r { | ||
229 | @@ -657,15 +654,18 @@ Loop: | ||
230 | |||
231 | // isSpace reports whether r is a space character. | ||
232 | func isSpace(r rune) bool { | ||
233 | - return r == ' ' || r == '\t' | ||
234 | -} | ||
235 | - | ||
236 | -// isEndOfLine reports whether r is an end-of-line character. | ||
237 | -func isEndOfLine(r rune) bool { | ||
238 | - return r == '\r' || r == '\n' | ||
239 | + return r == ' ' || r == '\t' || r == '\r' || r == '\n' | ||
240 | } | ||
241 | |||
242 | // isAlphaNumeric reports whether r is an alphabetic, digit, or underscore. | ||
243 | func isAlphaNumeric(r rune) bool { | ||
244 | return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) | ||
245 | } | ||
246 | + | ||
247 | +func hasLeftTrimMarker(s string) bool { | ||
248 | + return len(s) >= 2 && s[0] == trimMarker && isSpace(rune(s[1])) | ||
249 | +} | ||
250 | + | ||
251 | +func hasRightTrimMarker(s string) bool { | ||
252 | + return len(s) >= 2 && isSpace(rune(s[0])) && s[1] == trimMarker | ||
253 | +} | ||
254 | diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go | ||
255 | index f6d5f28..6510eed 100644 | ||
256 | --- a/src/text/template/parse/lex_test.go | ||
257 | +++ b/src/text/template/parse/lex_test.go | ||
258 | @@ -323,7 +323,7 @@ var lexTests = []lexTest{ | ||
259 | tLeft, | ||
260 | mkItem(itemError, "unrecognized character in action: U+0001"), | ||
261 | }}, | ||
262 | - {"unclosed action", "{{\n}}", []item{ | ||
263 | + {"unclosed action", "{{", []item{ | ||
264 | tLeft, | ||
265 | mkItem(itemError, "unclosed action"), | ||
266 | }}, | ||
267 | diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go | ||
268 | index 496d8bf..5e6e512 100644 | ||
269 | --- a/src/text/template/parse/parse.go | ||
270 | +++ b/src/text/template/parse/parse.go | ||
271 | @@ -24,13 +24,14 @@ type Tree struct { | ||
272 | Mode Mode // parsing mode. | ||
273 | text string // text parsed to create the template (or its parent) | ||
274 | // Parsing only; cleared after parse. | ||
275 | - funcs []map[string]interface{} | ||
276 | - lex *lexer | ||
277 | - token [3]item // three-token lookahead for parser. | ||
278 | - peekCount int | ||
279 | - vars []string // variables defined at the moment. | ||
280 | - treeSet map[string]*Tree | ||
281 | - mode Mode | ||
282 | + funcs []map[string]interface{} | ||
283 | + lex *lexer | ||
284 | + token [3]item // three-token lookahead for parser. | ||
285 | + peekCount int | ||
286 | + vars []string // variables defined at the moment. | ||
287 | + treeSet map[string]*Tree | ||
288 | + actionLine int // line of left delim starting action | ||
289 | + mode Mode | ||
290 | } | ||
291 | |||
292 | // A mode value is a set of flags (or 0). Modes control parser behavior. | ||
293 | @@ -187,6 +188,16 @@ func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { | ||
294 | |||
295 | // unexpected complains about the token and terminates processing. | ||
296 | func (t *Tree) unexpected(token item, context string) { | ||
297 | + if token.typ == itemError { | ||
298 | + extra := "" | ||
299 | + if t.actionLine != 0 && t.actionLine != token.line { | ||
300 | + extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine) | ||
301 | + if strings.HasSuffix(token.val, " action") { | ||
302 | + extra = extra[len(" in action"):] // avoid "action in action" | ||
303 | + } | ||
304 | + } | ||
305 | + t.errorf("%s%s", token, extra) | ||
306 | + } | ||
307 | t.errorf("unexpected %s in %s", token, context) | ||
308 | } | ||
309 | |||
310 | @@ -350,6 +361,8 @@ func (t *Tree) textOrAction() Node { | ||
311 | case itemText: | ||
312 | return t.newText(token.pos, token.val) | ||
313 | case itemLeftDelim: | ||
314 | + t.actionLine = token.line | ||
315 | + defer t.clearActionLine() | ||
316 | return t.action() | ||
317 | case itemComment: | ||
318 | return t.newComment(token.pos, token.val) | ||
319 | @@ -359,6 +372,10 @@ func (t *Tree) textOrAction() Node { | ||
320 | return nil | ||
321 | } | ||
322 | |||
323 | +func (t *Tree) clearActionLine() { | ||
324 | + t.actionLine = 0 | ||
325 | +} | ||
326 | + | ||
327 | // Action: | ||
328 | // control | ||
329 | // command ("|" command)* | ||
330 | @@ -384,12 +401,12 @@ func (t *Tree) action() (n Node) { | ||
331 | t.backup() | ||
332 | token := t.peek() | ||
333 | // Do not pop variables; they persist until "end". | ||
334 | - return t.newAction(token.pos, token.line, t.pipeline("command")) | ||
335 | + return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) | ||
336 | } | ||
337 | |||
338 | // Pipeline: | ||
339 | // declarations? command ('|' command)* | ||
340 | -func (t *Tree) pipeline(context string) (pipe *PipeNode) { | ||
341 | +func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { | ||
342 | token := t.peekNonSpace() | ||
343 | pipe = t.newPipeline(token.pos, token.line, nil) | ||
344 | // Are there declarations or assignments? | ||
345 | @@ -430,12 +447,9 @@ decls: | ||
346 | } | ||
347 | for { | ||
348 | switch token := t.nextNonSpace(); token.typ { | ||
349 | - case itemRightDelim, itemRightParen: | ||
350 | + case end: | ||
351 | // At this point, the pipeline is complete | ||
352 | t.checkPipeline(pipe, context) | ||
353 | - if token.typ == itemRightParen { | ||
354 | - t.backup() | ||
355 | - } | ||
356 | return | ||
357 | case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, | ||
358 | itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: | ||
359 | @@ -464,7 +478,7 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) { | ||
360 | |||
361 | func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { | ||
362 | defer t.popVars(len(t.vars)) | ||
363 | - pipe = t.pipeline(context) | ||
364 | + pipe = t.pipeline(context, itemRightDelim) | ||
365 | var next Node | ||
366 | list, next = t.itemList() | ||
367 | switch next.Type() { | ||
368 | @@ -550,7 +564,7 @@ func (t *Tree) blockControl() Node { | ||
369 | |||
370 | token := t.nextNonSpace() | ||
371 | name := t.parseTemplateName(token, context) | ||
372 | - pipe := t.pipeline(context) | ||
373 | + pipe := t.pipeline(context, itemRightDelim) | ||
374 | |||
375 | block := New(name) // name will be updated once we know it. | ||
376 | block.text = t.text | ||
377 | @@ -580,7 +594,7 @@ func (t *Tree) templateControl() Node { | ||
378 | if t.nextNonSpace().typ != itemRightDelim { | ||
379 | t.backup() | ||
380 | // Do not pop variables; they persist until "end". | ||
381 | - pipe = t.pipeline(context) | ||
382 | + pipe = t.pipeline(context, itemRightDelim) | ||
383 | } | ||
384 | return t.newTemplate(token.pos, token.line, name, pipe) | ||
385 | } | ||
386 | @@ -614,13 +628,12 @@ func (t *Tree) command() *CommandNode { | ||
387 | switch token := t.next(); token.typ { | ||
388 | case itemSpace: | ||
389 | continue | ||
390 | - case itemError: | ||
391 | - t.errorf("%s", token.val) | ||
392 | case itemRightDelim, itemRightParen: | ||
393 | t.backup() | ||
394 | case itemPipe: | ||
395 | + // nothing here; break loop below | ||
396 | default: | ||
397 | - t.errorf("unexpected %s in operand", token) | ||
398 | + t.unexpected(token, "operand") | ||
399 | } | ||
400 | break | ||
401 | } | ||
402 | @@ -675,8 +688,6 @@ func (t *Tree) operand() Node { | ||
403 | // A nil return means the next item is not a term. | ||
404 | func (t *Tree) term() Node { | ||
405 | switch token := t.nextNonSpace(); token.typ { | ||
406 | - case itemError: | ||
407 | - t.errorf("%s", token.val) | ||
408 | case itemIdentifier: | ||
409 | if !t.hasFunction(token.val) { | ||
410 | t.errorf("function %q not defined", token.val) | ||
411 | @@ -699,11 +710,7 @@ func (t *Tree) term() Node { | ||
412 | } | ||
413 | return number | ||
414 | case itemLeftParen: | ||
415 | - pipe := t.pipeline("parenthesized pipeline") | ||
416 | - if token := t.next(); token.typ != itemRightParen { | ||
417 | - t.errorf("unclosed right paren: unexpected %s", token) | ||
418 | - } | ||
419 | - return pipe | ||
420 | + return t.pipeline("parenthesized pipeline", itemRightParen) | ||
421 | case itemString, itemRawString: | ||
422 | s, err := strconv.Unquote(token.val) | ||
423 | if err != nil { | ||
424 | diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go | ||
425 | index d9c13c5..220f984 100644 | ||
426 | --- a/src/text/template/parse/parse_test.go | ||
427 | +++ b/src/text/template/parse/parse_test.go | ||
428 | @@ -250,6 +250,13 @@ var parseTests = []parseTest{ | ||
429 | {"comment trim left and right", "x \r\n\t{{- /* */ -}}\n\n\ty", noError, `"x""y"`}, | ||
430 | {"block definition", `{{block "foo" .}}hello{{end}}`, noError, | ||
431 | `{{template "foo" .}}`}, | ||
432 | + | ||
433 | + {"newline in assignment", "{{ $x \n := \n 1 \n }}", noError, "{{$x := 1}}"}, | ||
434 | + {"newline in empty action", "{{\n}}", hasError, "{{\n}}"}, | ||
435 | + {"newline in pipeline", "{{\n\"x\"\n|\nprintf\n}}", noError, `{{"x" | printf}}`}, | ||
436 | + {"newline in comment", "{{/*\nhello\n*/}}", noError, ""}, | ||
437 | + {"newline in comment", "{{-\n/*\nhello\n*/\n-}}", noError, ""}, | ||
438 | + | ||
439 | // Errors. | ||
440 | {"unclosed action", "hello{{range", hasError, ""}, | ||
441 | {"unmatched end", "{{end}}", hasError, ""}, | ||
442 | @@ -426,23 +433,38 @@ var errorTests = []parseTest{ | ||
443 | // Check line numbers are accurate. | ||
444 | {"unclosed1", | ||
445 | "line1\n{{", | ||
446 | - hasError, `unclosed1:2: unexpected unclosed action in command`}, | ||
447 | + hasError, `unclosed1:2: unclosed action`}, | ||
448 | {"unclosed2", | ||
449 | "line1\n{{define `x`}}line2\n{{", | ||
450 | - hasError, `unclosed2:3: unexpected unclosed action in command`}, | ||
451 | + hasError, `unclosed2:3: unclosed action`}, | ||
452 | + {"unclosed3", | ||
453 | + "line1\n{{\"x\"\n\"y\"\n", | ||
454 | + hasError, `unclosed3:4: unclosed action started at unclosed3:2`}, | ||
455 | + {"unclosed4", | ||
456 | + "{{\n\n\n\n\n", | ||
457 | + hasError, `unclosed4:6: unclosed action started at unclosed4:1`}, | ||
458 | + {"var1", | ||
459 | + "line1\n{{\nx\n}}", | ||
460 | + hasError, `var1:3: function "x" not defined`}, | ||
461 | // Specific errors. | ||
462 | {"function", | ||
463 | "{{foo}}", | ||
464 | hasError, `function "foo" not defined`}, | ||
465 | - {"comment", | ||
466 | + {"comment1", | ||
467 | "{{/*}}", | ||
468 | - hasError, `unclosed comment`}, | ||
469 | + hasError, `comment1:1: unclosed comment`}, | ||
470 | + {"comment2", | ||
471 | + "{{/*\nhello\n}}", | ||
472 | + hasError, `comment2:1: unclosed comment`}, | ||
473 | {"lparen", | ||
474 | "{{.X (1 2 3}}", | ||
475 | hasError, `unclosed left paren`}, | ||
476 | {"rparen", | ||
477 | - "{{.X 1 2 3)}}", | ||
478 | - hasError, `unexpected ")"`}, | ||
479 | + "{{.X 1 2 3 ) }}", | ||
480 | + hasError, `unexpected ")" in command`}, | ||
481 | + {"rparen2", | ||
482 | + "{{(.X 1 2 3", | ||
483 | + hasError, `unclosed action`}, | ||
484 | {"space", | ||
485 | "{{`x`3}}", | ||
486 | hasError, `in operand`}, | ||
487 | @@ -488,7 +510,7 @@ var errorTests = []parseTest{ | ||
488 | hasError, `missing value for parenthesized pipeline`}, | ||
489 | {"multilinerawstring", | ||
490 | "{{ $v := `\n` }} {{", | ||
491 | - hasError, `multilinerawstring:2: unexpected unclosed action`}, | ||
492 | + hasError, `multilinerawstring:2: unclosed action`}, | ||
493 | {"rangeundefvar", | ||
494 | "{{range $k}}{{end}}", | ||
495 | hasError, `undefined variable`}, | ||
496 | -- | ||
497 | 2.7.4 | ||