1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "tst_qmakelib.h"
30
31#include <proitems.h>
32#include <qmakevfs.h>
33#include <qmakeparser.h>
34
35class TokenStream
36{
37public:
38 TokenStream() {}
39 QString toString() const { return ts; }
40
41 TokenStream &operator<<(ushort n) { ts += QChar(n); return *this; }
42 TokenStream &operator<<(uint n) { ts += QChar(n & 0xffff); ts += QChar(n >> 16); return *this; }
43 TokenStream &operator<<(const QStringRef &s) { ts += s; return *this; }
44 TokenStream &operator<<(const ProString &s) { return *this << ushort(s.length()) << s.toQStringRef(); }
45 TokenStream &operator<<(const ProKey &s) { return *this << s.hash() << s.toString(); }
46
47private:
48 QString ts;
49};
50
51#define TS(s) (TokenStream() s).toString()
52#define H(n) ushort(n)
53#define I(n) uint(n)
54#define S(s) ProString(QString::fromWCharArray(s))
55#define HS(s) ProKey(QString::fromWCharArray(s))
56
57QT_WARNING_PUSH
58QT_WARNING_DISABLE_MSVC(4003) // "not enough actual parameters for macro TS()"
59
60void tst_qmakelib::addParseOperators()
61{
62 QTest::newRow(dataTag: "assign none")
63 << "VAR ="
64 << TS(
65 /* 0 */ << H(TokLine) << H(1)
66 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
67 /* 9 */ << H(TokAssign) << H(0)
68 /* 11 */ << H(TokValueTerminator))
69 << ""
70 << true;
71
72 QTest::newRow(dataTag: "append none")
73 << "VAR +="
74 << TS(
75 /* 0 */ << H(TokLine) << H(1)
76 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
77 /* 9 */ << H(TokAppend) << H(0)
78 /* 11 */ << H(TokValueTerminator))
79 << ""
80 << true;
81
82 QTest::newRow(dataTag: "unique append none")
83 << "VAR *="
84 << TS(
85 /* 0 */ << H(TokLine) << H(1)
86 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
87 /* 9 */ << H(TokAppendUnique) << H(0)
88 /* 11 */ << H(TokValueTerminator))
89 << ""
90 << true;
91
92 QTest::newRow(dataTag: "remove none")
93 << "VAR -="
94 << TS(
95 /* 0 */ << H(TokLine) << H(1)
96 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
97 /* 9 */ << H(TokRemove) << H(0)
98 /* 11 */ << H(TokValueTerminator))
99 << ""
100 << true;
101
102 QTest::newRow(dataTag: "replace empty")
103 << "VAR ~="
104 << TS(
105 /* 0 */ << H(TokLine) << H(1)
106 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
107 /* 9 */ << H(TokReplace) << H(0)
108 /* 11 */ << H(TokValueTerminator))
109 << ""
110 << true;
111
112 QTest::newRow(dataTag: "assignment without variable")
113 << "="
114 << TS(
115 /* 0 */ << H(TokLine) << H(1)
116 /* 2 */ << H(TokAssign) << H(0)
117 /* 4 */ << H(TokValueTerminator))
118 << "in:1: Assignment needs exactly one word on the left hand side."
119 << false;
120
121 QTest::newRow(dataTag: "assignment with multiple variables")
122 << "VAR VAR ="
123 << TS(
124 /* 0 */ << H(TokLine) << H(1)
125 /* 2 */ << H(TokAssign) << H(0)
126 /* 4 */ << H(TokValueTerminator))
127 << "in:1: Assignment needs exactly one word on the left hand side."
128 << false;
129}
130
131void tst_qmakelib::addParseValues()
132{
133#define ASSIGN_VAR(h) \
134 H(TokLine) << H(1) \
135 << H(TokHashLiteral) << HS(L"VAR") \
136 << H(TokAssign) << H(h)
137
138 QTest::newRow(dataTag: "one literal")
139 << "VAR = val"
140 << TS(
141 /* 0 */ << ASSIGN_VAR(0)
142 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val")
143 /* 16 */ << H(TokValueTerminator))
144 << ""
145 << true;
146
147 QTest::newRow(dataTag: "one literal (squeezed)")
148 << "VAR=val"
149 << TS(
150 /* 0 */ << ASSIGN_VAR(0)
151 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val")
152 /* 16 */ << H(TokValueTerminator))
153 << ""
154 << true;
155
156 QTest::newRow(dataTag: "many literals")
157 << "VAR = foo barbaz bak hello"
158 << TS(
159 /* 0 */ << ASSIGN_VAR(4)
160 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo")
161 /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz")
162 /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak")
163 /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello")
164 /* 36 */ << H(TokValueTerminator))
165 << ""
166 << true;
167
168 QTest::newRow(dataTag: "many literals (tab-separated")
169 << "VAR\t=\tfoo\tbarbaz\tbak\thello"
170 << TS(
171 /* 0 */ << ASSIGN_VAR(4)
172 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo")
173 /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz")
174 /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak")
175 /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello")
176 /* 36 */ << H(TokValueTerminator))
177 << ""
178 << true;
179
180 QTest::newRow(dataTag: "one quoted literal")
181 << "VAR = \"val ue\""
182 << TS(
183 /* 0 */ << ASSIGN_VAR(0)
184 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue")
185 /* 19 */ << H(TokValueTerminator))
186 << ""
187 << true;
188
189 QTest::newRow(dataTag: "quoted literal with missing quote")
190 << "VAR = val \"ue"
191 << TS(
192 /* 0 */ << H(TokLine) << H(1)
193 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
194 /* 9 */ << H(TokAssign) << H(0)
195 /* 11 */ << H(TokValueTerminator))
196 << "in:1: Missing closing \" quote"
197 << false;
198
199 QTest::newRow(dataTag: "many quoted literals")
200 << "VAR = \"foo\" barbaz 'bak hello' \"\""
201 << TS(
202 /* 0 */ << ASSIGN_VAR(3)
203 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo")
204 /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz")
205 /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak hello")
206 /* 35 */ << H(TokValueTerminator))
207 << ""
208 << true;
209
210 QTest::newRow(dataTag: "many quoted literals (with tabs)")
211 << "VAR\t=\t\"foo\"\tbarbaz\t'bak\thello'"
212 << TS(
213 /* 0 */ << ASSIGN_VAR(3)
214 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo")
215 /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz")
216 /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak\thello")
217 /* 35 */ << H(TokValueTerminator))
218 << ""
219 << true;
220
221 QTest::newRow(dataTag: "quoted and unquoted spaces")
222 << " VAR = \"val ue \" "
223 << TS(
224 /* 0 */ << ASSIGN_VAR(0)
225 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue ")
226 /* 22 */ << H(TokValueTerminator))
227 << ""
228 << true;
229
230 QTest::newRow(dataTag: "funny literals")
231 << "VAR = foo:bar|!baz(blam!, ${foo})"
232 << TS(
233 /* 0 */ << ASSIGN_VAR(2)
234 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo:bar|!baz(blam!,")
235 /* 32 */ << H(TokLiteral | TokNewStr) << S(L"${foo})")
236 /* 41 */ << H(TokValueTerminator))
237 << ""
238 << true;
239
240 QTest::newRow(dataTag: "literals with escapes")
241 << "VAR = \\{hi\\} \\[ho\\] \\)uh\\( \"\\\\oh\\$\"\\' \\$\\${FOO}"
242 << TS(
243 /* 0 */ << ASSIGN_VAR(5)
244 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{hi}")
245 /* 17 */ << H(TokLiteral | TokNewStr) << S(L"[ho]")
246 /* 23 */ << H(TokLiteral | TokNewStr) << S(L")uh(")
247 /* 29 */ << H(TokLiteral | TokNewStr) << S(L"\\oh$'")
248 /* 36 */ << H(TokLiteral | TokNewStr) << S(L"$${FOO}")
249 /* 45 */ << H(TokValueTerminator))
250 << ""
251 << true;
252
253 QTest::newRow(dataTag: "magic variables")
254 << "VAR = $$LITERAL_HASH $$LITERAL_DOLLAR $$LITERAL_WHITESPACE $$_FILE_ $$_LINE_"
255 << TS(
256 /* 0 */ << ASSIGN_VAR(5)
257 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"#")
258 /* 14 */ << H(TokLiteral | TokNewStr) << S(L"$")
259 /* 17 */ << H(TokLiteral | TokNewStr) << S(L"\t")
260 /* 20 */ << H(TokLiteral | TokNewStr) << S(L"in")
261 /* 24 */ << H(TokLiteral | TokNewStr) << S(L"1")
262 /* 27 */ << H(TokValueTerminator))
263 << ""
264 << true;
265
266 QTest::newRow(dataTag: "continuations and comments")
267 << "VAR = foo \\\n bar\n \n"
268 "GAR = foo \\ # comment\n bar \\\n # comment\n baz \\\n"
269 "\"quoted \\ #comment\n escape\" \\\n right\\\n after \\\n gorilla!\n \n\n"
270 "MOO = \\\n kuh # comment\nLOO =\n\n"
271 "FOO = bar \\\n# comment\n baz \\\n \n# comment\n"
272 "GAZ="
273 << TS(
274 /* 0 */ << H(TokLine) << H(1)
275 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
276 /* 9 */ << H(TokAssign) << H(2)
277 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo")
278 /* 16 */ << H(TokLiteral | TokNewStr) << S(L"bar")
279 /* 21 */ << H(TokValueTerminator)
280 /* 22 */ << H(TokLine) << H(4)
281 /* 24 */ << H(TokHashLiteral) << HS(L"GAR")
282 /* 31 */ << H(TokAssign) << H(7)
283 /* 33 */ << H(TokLiteral | TokNewStr) << S(L"foo")
284 /* 38 */ << H(TokLiteral | TokNewStr) << S(L"bar")
285 /* 43 */ << H(TokLiteral | TokNewStr) << S(L"baz")
286 /* 48 */ << H(TokLiteral | TokNewStr) << S(L"quoted escape")
287 /* 64 */ << H(TokLiteral | TokNewStr) << S(L"right")
288 /* 71 */ << H(TokLiteral | TokNewStr) << S(L"after")
289 /* 78 */ << H(TokLiteral | TokNewStr) << S(L"gorilla!")
290 /* 88 */ << H(TokValueTerminator)
291 /* 89 */ << H(TokLine) << H(15)
292 /* 91 */ << H(TokHashLiteral) << HS(L"MOO")
293 /* 98 */ << H(TokAssign) << H(0)
294 /* 100 */ << H(TokLiteral | TokNewStr) << S(L"kuh")
295 /* 105 */ << H(TokValueTerminator)
296 /* 106 */ << H(TokLine) << H(17)
297 /* 108 */ << H(TokHashLiteral) << HS(L"LOO")
298 /* 115 */ << H(TokAssign) << H(0)
299 /* 117 */ << H(TokValueTerminator)
300 /* 118 */ << H(TokLine) << H(19)
301 /* 120 */ << H(TokHashLiteral) << HS(L"FOO")
302 /* 127 */ << H(TokAssign) << H(2)
303 /* 129 */ << H(TokLiteral | TokNewStr) << S(L"bar")
304 /* 134 */ << H(TokLiteral | TokNewStr) << S(L"baz")
305 /* 139 */ << H(TokValueTerminator)
306 /* 140 */ << H(TokLine) << H(24)
307 /* 142 */ << H(TokHashLiteral) << HS(L"GAZ")
308 /* 149 */ << H(TokAssign) << H(0)
309 /* 151 */ << H(TokValueTerminator))
310 << ""
311 << true;
312
313 QTest::newRow(dataTag: "accidental continuation")
314 << "VAR0 = \\\n this \\\n is \\\n ok\n"
315 "VAR1 = \\\n this \\\n is=still \\\n ok\n"
316 "VAR2 = \\\n this \\\n is \\\n"
317 "VAR3 = \\\n not ok\n"
318 << TS(
319 /* 0 */ << H(TokLine) << H(1)
320 /* 2 */ << H(TokHashLiteral) << HS(L"VAR0")
321 /* 10 */ << H(TokAssign) << H(3)
322 /* 12 */ << H(TokLiteral | TokNewStr) << S(L"this")
323 /* 18 */ << H(TokLiteral | TokNewStr) << S(L"is")
324 /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ok")
325 /* 26 */ << H(TokValueTerminator)
326 /* 27 */ << H(TokLine) << H(5)
327 /* 29 */ << H(TokHashLiteral) << HS(L"VAR1")
328 /* 37 */ << H(TokAssign) << H(3)
329 /* 39 */ << H(TokLiteral | TokNewStr) << S(L"this")
330 /* 45 */ << H(TokLiteral | TokNewStr) << S(L"is=still")
331 /* 55 */ << H(TokLiteral | TokNewStr) << S(L"ok")
332 /* 59 */ << H(TokValueTerminator)
333 /* 60 */ << H(TokLine) << H(9)
334 /* 62 */ << H(TokHashLiteral) << HS(L"VAR2")
335 /* 70 */ << H(TokAssign) << H(6)
336 /* 72 */ << H(TokLiteral | TokNewStr) << S(L"this")
337 /* 78 */ << H(TokLiteral | TokNewStr) << S(L"is")
338 /* 82 */ << H(TokLiteral | TokNewStr) << S(L"VAR3")
339 /* 88 */ << H(TokLiteral | TokNewStr) << S(L"=")
340 /* 91 */ << H(TokLiteral | TokNewStr) << S(L"not")
341 /* 96 */ << H(TokLiteral | TokNewStr) << S(L"ok")
342 /* 100 */ << H(TokValueTerminator))
343 << "WARNING: in:12: Possible accidental line continuation"
344 << true;
345
346 QTest::newRow(dataTag: "plain variable expansion")
347 << "VAR = $$bar"
348 << TS(
349 /* 0 */ << ASSIGN_VAR(0)
350 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar")
351 /* 18 */ << H(TokValueTerminator))
352 << ""
353 << true;
354
355 QTest::newRow(dataTag: "braced variable expansion")
356 << "VAR = $${foo/bar}"
357 << TS(
358 /* 0 */ << ASSIGN_VAR(0)
359 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"foo/bar")
360 /* 22 */ << H(TokValueTerminator))
361 << ""
362 << true;
363
364 QTest::newRow(dataTag: "bogus variable expansion")
365 << "VAR = $$ "
366 << TS(
367 /* 0 */ << ASSIGN_VAR(0)
368 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"")
369 /* 15 */ << H(TokValueTerminator))
370 << "WARNING: in:1: Missing name in expansion"
371 << true;
372
373 QTest::newRow(dataTag: "bogus braced variable expansion")
374 << "VAR = $${}"
375 << TS(
376 /* 0 */ << ASSIGN_VAR(0)
377 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"")
378 /* 15 */ << H(TokValueTerminator))
379 << "WARNING: in:1: Missing name in expansion"
380 << true;
381
382 QTest::newRow(dataTag: "unterminated braced variable expansion")
383 << "VAR = $${FOO"
384 << TS(
385 /* 0 */ << H(TokLine) << H(1)
386 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
387 /* 9 */ << H(TokAssign) << H(0)
388 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO")
389 /* 18 */ << H(TokValueTerminator))
390 << "in:1: Missing } terminator [found end-of-line]"
391 << false;
392
393 QTest::newRow(dataTag: "invalid identifier in braced variable expansion")
394 << "VAR = $${FOO/BAR+BAZ}"
395 << TS(
396 /* 0 */ << H(TokLine) << H(1)
397 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
398 /* 9 */ << H(TokAssign) << H(0)
399 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO/BAR")
400 /* 22 */ << H(TokLiteral) << S(L"+BAZ")
401 /* 28 */ << H(TokValueTerminator))
402 << "in:1: Missing } terminator [found +]"
403 << false;
404
405 QTest::newRow(dataTag: "property expansion")
406 << "VAR = $$[bar]"
407 << TS(
408 /* 0 */ << ASSIGN_VAR(0)
409 /* 11 */ << H(TokProperty | TokNewStr) << HS(L"bar")
410 /* 18 */ << H(TokValueTerminator))
411 << ""
412 << true;
413
414 QTest::newRow(dataTag: "environment expansion")
415 << "VAR = $$(bar)"
416 << TS(
417 /* 0 */ << ASSIGN_VAR(0)
418 /* 11 */ << H(TokEnvVar | TokNewStr) << S(L"bar")
419 /* 16 */ << H(TokValueTerminator))
420 << ""
421 << true;
422
423 QTest::newRow(dataTag: "plain function call")
424 << "VAR = $$bar()"
425 << TS(
426 /* 0 */ << ASSIGN_VAR(0)
427 /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar")
428 /* 18 */ << H(TokFuncTerminator)
429 /* 19 */ << H(TokValueTerminator))
430 << ""
431 << true;
432
433 QTest::newRow(dataTag: "braced function call")
434 << "VAR = $${bar()}"
435 << TS(
436 /* 0 */ << ASSIGN_VAR(0)
437 /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar")
438 /* 18 */ << H(TokFuncTerminator)
439 /* 19 */ << H(TokValueTerminator))
440 << ""
441 << true;
442
443 QTest::newRow(dataTag: "function call with one argument")
444 << "VAR = $$bar(blubb)"
445 << TS(
446 /* 0 */ << ASSIGN_VAR(0)
447 /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar")
448 /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb")
449 /* 25 */ << H(TokFuncTerminator)
450 /* 26 */ << H(TokValueTerminator))
451 << ""
452 << true;
453
454 QTest::newRow(dataTag: "function call with multiple arguments")
455 << "VAR = $$bar( blubb blubb, hey ,$$you)"
456 << TS(
457 /* 0 */ << ASSIGN_VAR(0)
458 /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar")
459 /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb")
460 /* 25 */ << H(TokLiteral | TokNewStr) << S(L"blubb")
461 /* 32 */ << H(TokArgSeparator)
462 /* 33 */ << H(TokLiteral | TokNewStr) << S(L"hey")
463 /* 38 */ << H(TokArgSeparator)
464 /* 39 */ << H(TokVariable | TokNewStr) << HS(L"you")
465 /* 46 */ << H(TokFuncTerminator)
466 /* 47 */ << H(TokValueTerminator))
467 << ""
468 << true;
469
470 QTest::newRow(dataTag: "nested function call")
471 << "VAR = $$foo(yo, $$bar(blubb))"
472 << TS(
473 /* 0 */ << ASSIGN_VAR(0)
474 /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"foo")
475 /* 18 */ << H(TokLiteral | TokNewStr) << S(L"yo")
476 /* 22 */ << H(TokArgSeparator)
477 /* 23 */ << H(TokFuncName | TokNewStr) << HS(L"bar")
478 /* 30 */ << H(TokLiteral | TokNewStr) << S(L"blubb")
479 /* 37 */ << H(TokFuncTerminator)
480 /* 38 */ << H(TokFuncTerminator)
481 /* 39 */ << H(TokValueTerminator))
482 << ""
483 << true;
484
485 // This is a rather questionable "feature"
486 QTest::newRow(dataTag: "function call with parenthesized argument")
487 << "VAR = $$bar(blubb (yo, man) blabb, nope)"
488 << TS(
489 /* 0 */ << ASSIGN_VAR(0)
490 /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar")
491 /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb")
492 /* 25 */ << H(TokLiteral | TokNewStr) << S(L"(yo,")
493 /* 31 */ << H(TokLiteral | TokNewStr) << S(L"man)")
494 /* 37 */ << H(TokLiteral | TokNewStr) << S(L"blabb")
495 /* 44 */ << H(TokArgSeparator)
496 /* 45 */ << H(TokLiteral | TokNewStr) << S(L"nope")
497 /* 51 */ << H(TokFuncTerminator)
498 /* 52 */ << H(TokValueTerminator))
499 << ""
500 << true;
501
502 QTest::newRow(dataTag: "separate literal and expansion")
503 << "VAR = foo $$bar"
504 << TS(
505 /* 0 */ << ASSIGN_VAR(2)
506 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo")
507 /* 16 */ << H(TokVariable | TokNewStr) << HS(L"bar")
508 /* 23 */ << H(TokValueTerminator))
509 << ""
510 << true;
511
512 QTest::newRow(dataTag: "separate expansion and literal")
513 << "VAR = $$bar foo"
514 << TS(
515 /* 0 */ << ASSIGN_VAR(0)
516 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar")
517 /* 18 */ << H(TokLiteral | TokNewStr) << S(L"foo")
518 /* 23 */ << H(TokValueTerminator))
519 << ""
520 << true;
521
522 QTest::newRow(dataTag: "joined literal and expansion")
523 << "VAR = foo$$bar"
524 << TS(
525 /* 0 */ << ASSIGN_VAR(0)
526 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo")
527 /* 16 */ << H(TokVariable) << HS(L"bar")
528 /* 23 */ << H(TokValueTerminator))
529 << ""
530 << true;
531
532 QTest::newRow(dataTag: "joined expansion and literal")
533 << "VAR = $${bar}foo"
534 << TS(
535 /* 0 */ << ASSIGN_VAR(0)
536 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar")
537 /* 18 */ << H(TokLiteral) << S(L"foo")
538 /* 23 */ << H(TokValueTerminator))
539 << ""
540 << true;
541
542 QTest::newRow(dataTag: "plain variable expansion with funny name and literal")
543 << "VAR = $$az_AZ_09.dot/nix"
544 << TS(
545 /* 0 */ << ASSIGN_VAR(0)
546 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot")
547 /* 27 */ << H(TokLiteral) << S(L"/nix")
548 /* 33 */ << H(TokValueTerminator))
549 << ""
550 << true;
551
552 QTest::newRow(dataTag: "braced variable expansion with funny name")
553 << "VAR = $${az_AZ_09.dot/nix}"
554 << TS(
555 /* 0 */ << ASSIGN_VAR(0)
556 /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot/nix")
557 /* 31 */ << H(TokValueTerminator))
558 << ""
559 << true;
560
561 QTest::newRow(dataTag: "quoted joined literal and expansion")
562 << "VAR = 'foo$$bar'"
563 << TS(
564 /* 0 */ << ASSIGN_VAR(0)
565 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo")
566 /* 16 */ << H(TokVariable | TokQuoted) << HS(L"bar")
567 /* 23 */ << H(TokValueTerminator))
568 << ""
569 << true;
570
571 QTest::newRow(dataTag: "assignment with expansion in variable name")
572 << "VAR$$EXTRA ="
573 << TS(
574 /* 0 */ << H(TokLine) << H(1)
575 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
576 /* 9 */ << H(TokVariable) << HS(L"EXTRA")
577 /* 18 */ << H(TokAssign) << H(0)
578 /* 20 */ << H(TokValueTerminator))
579 << ""
580 << true;
581}
582
583void tst_qmakelib::addParseConditions()
584{
585 QTest::newRow(dataTag: "one test")
586 << "foo"
587 << TS(
588 /* 0 */ << H(TokLine) << H(1)
589 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
590 /* 9 */ << H(TokCondition))
591 << ""
592 << true;
593
594 QTest::newRow(dataTag: "wildcard-test")
595 << "foo-*"
596 << TS(
597 /* 0 */ << H(TokLine) << H(1)
598 /* 2 */ << H(TokHashLiteral) << HS(L"foo-*")
599 /* 11 */ << H(TokCondition))
600 << ""
601 << true;
602
603 // This is a rather questionable "feature"
604 QTest::newRow(dataTag: "one quoted test")
605 << "\"foo\""
606 << TS(
607 /* 0 */ << H(TokLine) << H(1)
608 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
609 /* 9 */ << H(TokCondition))
610 << ""
611 << true;
612
613 QTest::newRow(dataTag: "two tests")
614 << "foo\nbar"
615 << TS(
616 /* 0 */ << H(TokLine) << H(1)
617 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
618 /* 9 */ << H(TokCondition)
619 /* 10 */ << H(TokLine) << H(2)
620 /* 12 */ << H(TokHashLiteral) << HS(L"bar")
621 /* 19 */ << H(TokCondition))
622 << ""
623 << true;
624
625 QTest::newRow(dataTag: "bogus two tests")
626 << "foo bar\nbaz"
627 << TS()
628 << "in:1: Extra characters after test expression."
629 << false;
630
631 QTest::newRow(dataTag: "test-AND-test")
632 << "foo:bar"
633 << TS(
634 /* 0 */ << H(TokLine) << H(1)
635 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
636 /* 9 */ << H(TokCondition)
637 /* 10 */ << H(TokAnd)
638 /* 11 */ << H(TokHashLiteral) << HS(L"bar")
639 /* 18 */ << H(TokCondition))
640 << ""
641 << true;
642
643 QTest::newRow(dataTag: "test-OR-test")
644 << " foo | bar "
645 << TS(
646 /* 0 */ << H(TokLine) << H(1)
647 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
648 /* 9 */ << H(TokCondition)
649 /* 10 */ << H(TokOr)
650 /* 11 */ << H(TokHashLiteral) << HS(L"bar")
651 /* 18 */ << H(TokCondition))
652 << ""
653 << true;
654
655 QTest::newRow(dataTag: "NOT-test")
656 << "!foo"
657 << TS(
658 /* 0 */ << H(TokLine) << H(1)
659 /* 2 */ << H(TokNot)
660 /* 3 */ << H(TokHashLiteral) << HS(L"foo")
661 /* 10 */ << H(TokCondition))
662 << ""
663 << true;
664
665 QTest::newRow(dataTag: "NOT-NOT-test")
666 << "!!foo"
667 << TS(
668 /* 0 */ << H(TokLine) << H(1)
669 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
670 /* 9 */ << H(TokCondition))
671 << ""
672 << true;
673
674 // This is a rather questionable "feature"
675 QTest::newRow(dataTag: "quoted-NOT-test")
676 << "\"!foo\""
677 << TS(
678 /* 0 */ << H(TokLine) << H(1)
679 /* 2 */ << H(TokNot)
680 /* 3 */ << H(TokHashLiteral) << HS(L"foo")
681 /* 10 */ << H(TokCondition))
682 << ""
683 << true;
684
685 // This is a rather questionable "feature"
686 QTest::newRow(dataTag: "NOT-quoted-test")
687 << "!\"foo\""
688 << TS(
689 /* 0 */ << H(TokLine) << H(1)
690 /* 2 */ << H(TokNot)
691 /* 3 */ << H(TokHashLiteral) << HS(L"foo")
692 /* 10 */ << H(TokCondition))
693 << ""
694 << true;
695
696 QTest::newRow(dataTag: "test-AND-NOT-test")
697 << "foo:!bar"
698 << TS(
699 /* 0 */ << H(TokLine) << H(1)
700 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
701 /* 9 */ << H(TokCondition)
702 /* 10 */ << H(TokAnd)
703 /* 11 */ << H(TokNot)
704 /* 12 */ << H(TokHashLiteral) << HS(L"bar")
705 /* 19 */ << H(TokCondition))
706 << ""
707 << true;
708
709 QTest::newRow(dataTag: "test-assignment")
710 << "foo\nVAR="
711 << TS(
712 /* 0 */ << H(TokLine) << H(1)
713 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
714 /* 9 */ << H(TokCondition)
715 /* 10 */ << H(TokLine) << H(2)
716 /* 12 */ << H(TokHashLiteral) << HS(L"VAR")
717 /* 19 */ << H(TokAssign) << H(0)
718 /* 21 */ << H(TokValueTerminator))
719 << ""
720 << true;
721
722 QTest::newRow(dataTag: "test-AND-assignment")
723 << "foo: VAR ="
724 << TS(
725 /* 0 */ << H(TokLine) << H(1)
726 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
727 /* 9 */ << H(TokCondition)
728 /* 10 */ << H(TokBranch)
729 /* 11 */ /* then branch */ << I(11)
730 /* 13 */ << H(TokHashLiteral) << HS(L"VAR")
731 /* 20 */ << H(TokAssign) << H(0)
732 /* 22 */ << H(TokValueTerminator)
733 /* 23 */ << H(TokTerminator)
734 /* 24 */ /* else branch */ << I(0))
735 << ""
736 << true;
737
738 QTest::newRow(dataTag: "test-else-test")
739 << "foo\nelse: bar"
740 << TS(
741 /* 0 */ << H(TokLine) << H(1)
742 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
743 /* 9 */ << H(TokCondition)
744 /* 10 */ << H(TokBranch)
745 /* 11 */ /* then branch */ << I(0)
746 /* 13 */ /* else branch */ << I(11)
747 /* 15 */ << H(TokLine) << H(2)
748 /* 17 */ << H(TokHashLiteral) << HS(L"bar")
749 /* 24 */ << H(TokCondition)
750 /* 25 */ << H(TokTerminator))
751 << ""
752 << true;
753
754 QTest::newRow(dataTag: "function-else-test")
755 << "foo()\nelse: bar"
756 << TS(
757 /* 0 */ << H(TokLine) << H(1)
758 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
759 /* 9 */ << H(TokTestCall)
760 /* 10 */ << H(TokFuncTerminator)
761 /* 11 */ << H(TokBranch)
762 /* 12 */ /* then branch */ << I(0)
763 /* 14 */ /* else branch */ << I(11)
764 /* 16 */ << H(TokLine) << H(2)
765 /* 18 */ << H(TokHashLiteral) << HS(L"bar")
766 /* 25 */ << H(TokCondition)
767 /* 26 */ << H(TokTerminator))
768 << ""
769 << true;
770
771 QTest::newRow(dataTag: "test-AND-test-else-test")
772 << "foo:bar\nelse: baz"
773 << TS(
774 /* 0 */ << H(TokLine) << H(1)
775 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
776 /* 9 */ << H(TokCondition)
777 /* 10 */ << H(TokAnd)
778 /* 11 */ << H(TokHashLiteral) << HS(L"bar")
779 /* 18 */ << H(TokCondition)
780 /* 19 */ << H(TokBranch)
781 /* 20 */ /* then branch */ << I(0)
782 /* 22 */ /* else branch */ << I(11)
783 /* 24 */ << H(TokLine) << H(2)
784 /* 26 */ << H(TokHashLiteral) << HS(L"baz")
785 /* 33 */ << H(TokCondition)
786 /* 34 */ << H(TokTerminator))
787 << ""
788 << true;
789
790 QTest::newRow(dataTag: "test-AND-test-else-test-else-test-function")
791 << "foo:bar\nelse: baz\nelse: bak\nbuzz()"
792 << TS(
793 /* 0 */ << H(TokLine) << H(1)
794 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
795 /* 9 */ << H(TokCondition)
796 /* 10 */ << H(TokAnd)
797 /* 11 */ << H(TokHashLiteral) << HS(L"bar")
798 /* 18 */ << H(TokCondition)
799 /* 19 */ << H(TokBranch)
800 /* 20 */ /* then branch */ << I(0)
801 /* 22 */ /* else branch */ << I(27)
802 /* 24 */ << H(TokLine) << H(2)
803 /* 26 */ << H(TokHashLiteral) << HS(L"baz")
804 /* 33 */ << H(TokCondition)
805 /* 34 */ << H(TokBranch)
806 /* 35 */ /* then branch */ << I(0)
807 /* 37 */ /* else branch */ << I(11)
808 /* 39 */ << H(TokLine) << H(3)
809 /* 41 */ << H(TokHashLiteral) << HS(L"bak")
810 /* 48 */ << H(TokCondition)
811 /* 49 */ << H(TokTerminator)
812 /* 50 */ << H(TokTerminator)
813 /* 51 */ << H(TokLine) << H(4)
814 /* 53 */ << H(TokHashLiteral) << HS(L"buzz")
815 /* 61 */ << H(TokTestCall)
816 /* 62 */ << H(TokFuncTerminator))
817 << ""
818 << true;
819
820 QTest::newRow(dataTag: "test-assignment-else-assignment")
821 << "foo: VAR =\nelse: VAR="
822 << TS(
823 /* 0 */ << H(TokLine) << H(1)
824 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
825 /* 9 */ << H(TokCondition)
826 /* 10 */ << H(TokBranch)
827 /* 11 */ /* then branch */ << I(11)
828 /* 13 */ << H(TokHashLiteral) << HS(L"VAR")
829 /* 20 */ << H(TokAssign) << H(0)
830 /* 22 */ << H(TokValueTerminator)
831 /* 23 */ << H(TokTerminator)
832 /* 24 */ /* else branch */ << I(13)
833 /* 26 */ << H(TokLine) << H(2)
834 /* 28 */ << H(TokHashLiteral) << HS(L"VAR")
835 /* 35 */ << H(TokAssign) << H(0)
836 /* 37 */ << H(TokValueTerminator)
837 /* 38 */ << H(TokTerminator))
838 << ""
839 << true;
840
841 QTest::newRow(dataTag: "test-else-test-assignment")
842 << "foo\nelse: bar: VAR ="
843 << TS(
844 /* 0 */ << H(TokLine) << H(1)
845 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
846 /* 9 */ << H(TokCondition)
847 /* 10 */ << H(TokBranch)
848 /* 11 */ /* then branch */ << I(0)
849 /* 13 */ /* else branch */ << I(27)
850 /* 15 */ << H(TokLine) << H(2)
851 /* 17 */ << H(TokHashLiteral) << HS(L"bar")
852 /* 24 */ << H(TokCondition)
853 /* 25 */ << H(TokBranch)
854 /* 26 */ /* then branch */ << I(11)
855 /* 28 */ << H(TokHashLiteral) << HS(L"VAR")
856 /* 35 */ << H(TokAssign) << H(0)
857 /* 37 */ << H(TokValueTerminator)
858 /* 38 */ << H(TokTerminator)
859 /* 39 */ /* else branch */ << I(0)
860 /* 41 */ << H(TokTerminator))
861 << ""
862 << true;
863
864 QTest::newRow(dataTag: "one function")
865 << "foo()"
866 << TS(
867 /* 0 */ << H(TokLine) << H(1)
868 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
869 /* 9 */ << H(TokTestCall)
870 /* 10 */ << H(TokFuncTerminator))
871 << ""
872 << true;
873
874 QTest::newRow(dataTag: "one function (with spaces)")
875 << " foo( ) "
876 << TS(
877 /* 0 */ << H(TokLine) << H(1)
878 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
879 /* 9 */ << H(TokTestCall)
880 /* 10 */ << H(TokFuncTerminator))
881 << ""
882 << true;
883
884 QTest::newRow(dataTag: "unterminated function call")
885 << "foo(\nfoo"
886 << TS()
887 << "in:1: Missing closing parenthesis in function call"
888 << false;
889
890 QTest::newRow(dataTag: "function with arguments")
891 << "foo(blah, hi ho)"
892 << TS(
893 /* 0 */ << H(TokLine) << H(1)
894 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
895 /* 9 */ << H(TokTestCall)
896 /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah")
897 /* 16 */ << H(TokArgSeparator)
898 /* 17 */ << H(TokLiteral | TokNewStr) << S(L"hi")
899 /* 21 */ << H(TokLiteral | TokNewStr) << S(L"ho")
900 /* 25 */ << H(TokFuncTerminator))
901 << ""
902 << true;
903
904 QTest::newRow(dataTag: "function with empty arguments")
905 << "foo(,)"
906 << TS(
907 /* 0 */ << H(TokLine) << H(1)
908 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
909 /* 9 */ << H(TokTestCall)
910 /* 10 */ << H(TokArgSeparator)
911 /* 11 */ << H(TokFuncTerminator))
912 << ""
913 << true;
914
915 QTest::newRow(dataTag: "function with funny arguments")
916 << "foo(blah\\, \"hi , \\ho\" ,uh\\ ,\\oh ,, )"
917 << TS(
918 /* 0 */ << H(TokLine) << H(1)
919 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
920 /* 9 */ << H(TokTestCall)
921 /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah\\")
922 /* 17 */ << H(TokArgSeparator)
923 /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi , \\ho")
924 /* 29 */ << H(TokArgSeparator)
925 /* 30 */ << H(TokLiteral | TokNewStr) << S(L"uh\\")
926 /* 35 */ << H(TokArgSeparator)
927 /* 36 */ << H(TokLiteral | TokNewStr) << S(L"\\oh")
928 /* 41 */ << H(TokArgSeparator)
929 /* 42 */ << H(TokArgSeparator)
930 /* 43 */ << H(TokFuncTerminator))
931 << "WARNING: in:1: Unescaped backslashes are deprecated\n"
932 "WARNING: in:1: Unescaped backslashes are deprecated\n"
933 "WARNING: in:1: Unescaped backslashes are deprecated\n"
934 "WARNING: in:1: Unescaped backslashes are deprecated"
935 << true;
936
937 QTest::newRow(dataTag: "function with nested call")
938 << "foo($$blah(hi ho))"
939 << TS(
940 /* 0 */ << H(TokLine) << H(1)
941 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
942 /* 9 */ << H(TokTestCall)
943 /* 10 */ << H(TokFuncName | TokNewStr) << HS(L"blah")
944 /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi")
945 /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ho")
946 /* 26 */ << H(TokFuncTerminator)
947 /* 27 */ << H(TokFuncTerminator))
948 << ""
949 << true;
950
951 QTest::newRow(dataTag: "stand-alone parentheses")
952 << "()"
953 << TS(
954 /* 0 */ << H(TokLine) << H(1)
955 /* 2 */ << H(TokTestCall)
956 /* 3 */ << H(TokFuncTerminator))
957 << "in:1: Opening parenthesis without prior test name."
958 << false;
959
960 QTest::newRow(dataTag: "bogus test and function")
961 << "foo bar()"
962 << TS(
963 /* 0 */ << H(TokLine) << H(1)
964 /* 2 */ << H(TokTestCall)
965 /* 3 */ << H(TokFuncTerminator))
966 << "in:1: Extra characters after test expression."
967 << false;
968
969 // This is a rather questionable "feature"
970 QTest::newRow(dataTag: "two functions")
971 << "foo() bar()"
972 << TS(
973 /* 0 */ << H(TokLine) << H(1)
974 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
975 /* 9 */ << H(TokTestCall)
976 /* 10 */ << H(TokFuncTerminator)
977 /* 11 */ << H(TokHashLiteral) << HS(L"bar")
978 /* 18 */ << H(TokTestCall)
979 /* 19 */ << H(TokFuncTerminator))
980 << ""
981 << true;
982
983 QTest::newRow(dataTag: "function-AND-test")
984 << "foo():bar"
985 << TS(
986 /* 0 */ << H(TokLine) << H(1)
987 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
988 /* 9 */ << H(TokTestCall)
989 /* 10 */ << H(TokFuncTerminator)
990 /* 11 */ << H(TokAnd)
991 /* 12 */ << H(TokHashLiteral) << HS(L"bar")
992 /* 19 */ << H(TokCondition))
993 << ""
994 << true;
995
996 QTest::newRow(dataTag: "test-AND-function")
997 << "foo:bar()"
998 << TS(
999 /* 0 */ << H(TokLine) << H(1)
1000 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
1001 /* 9 */ << H(TokCondition)
1002 /* 10 */ << H(TokAnd)
1003 /* 11 */ << H(TokHashLiteral) << HS(L"bar")
1004 /* 18 */ << H(TokTestCall)
1005 /* 19 */ << H(TokFuncTerminator))
1006 << ""
1007 << true;
1008
1009 QTest::newRow(dataTag: "NOT-function-AND-test")
1010 << "!foo():bar"
1011 << TS(
1012 /* 0 */ << H(TokLine) << H(1)
1013 /* 2 */ << H(TokNot)
1014 /* 3 */ << H(TokHashLiteral) << HS(L"foo")
1015 /* 10 */ << H(TokTestCall)
1016 /* 11 */ << H(TokFuncTerminator)
1017 /* 12 */ << H(TokAnd)
1018 /* 13 */ << H(TokHashLiteral) << HS(L"bar")
1019 /* 20 */ << H(TokCondition))
1020 << ""
1021 << true;
1022
1023 QTest::newRow(dataTag: "test-AND-NOT-function")
1024 << "foo:!bar()"
1025 << TS(
1026 /* 0 */ << H(TokLine) << H(1)
1027 /* 2 */ << H(TokHashLiteral) << HS(L"foo")
1028 /* 9 */ << H(TokCondition)
1029 /* 10 */ << H(TokAnd)
1030 /* 11 */ << H(TokNot)
1031 /* 12 */ << H(TokHashLiteral) << HS(L"bar")
1032 /* 19 */ << H(TokTestCall)
1033 /* 20 */ << H(TokFuncTerminator))
1034 << ""
1035 << true;
1036}
1037
1038void tst_qmakelib::addParseControlStatements()
1039{
1040 QTest::newRow(dataTag: "for(VAR, LIST) loop")
1041 << "for(VAR, LIST)"
1042 << TS(
1043 /* 0 */ << H(TokLine) << H(1)
1044 /* 2 */ << H(TokForLoop) << HS(L"VAR")
1045 /* 9 */ /* iterator */ << I(7)
1046 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"LIST")
1047 /* 17 */ << H(TokValueTerminator)
1048 /* 18 */ /* body */ << I(1)
1049 /* 20 */ << H(TokTerminator))
1050 << ""
1051 << true;
1052
1053 QTest::newRow(dataTag: "for(ever) loop")
1054 << "for(ever)"
1055 << TS(
1056 /* 0 */ << H(TokLine) << H(1)
1057 /* 2 */ << H(TokForLoop) << HS(L"")
1058 /* 6 */ /* iterator */ << I(9)
1059 /* 8 */ << H(TokHashLiteral) << HS(L"ever")
1060 /* 16 */ << H(TokValueTerminator)
1061 /* 17 */ /* body */ << I(1)
1062 /* 19 */ << H(TokTerminator))
1063 << ""
1064 << true;
1065
1066 // This is a rather questionable "feature"
1067 QTest::newRow(dataTag: "for($$blub) loop")
1068 << "for($$blub)"
1069 << TS(
1070 /* 0 */ << H(TokLine) << H(1)
1071 /* 2 */ << H(TokForLoop) << HS(L"")
1072 /* 6 */ /* iterator */ << I(9)
1073 /* 8 */ << H(TokVariable | TokNewStr) << HS(L"blub")
1074 /* 16 */ << H(TokValueTerminator)
1075 /* 17 */ /* body */ << I(1)
1076 /* 19 */ << H(TokTerminator))
1077 << ""
1078 << true;
1079
1080 QTest::newRow(dataTag: "test-for-test-else-test")
1081 << "true:for(VAR, LIST): true\nelse: true"
1082 << TS(
1083 /* 0 */ << H(TokLine) << H(1)
1084 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1085 /* 10 */ << H(TokCondition)
1086 /* 11 */ << H(TokBranch)
1087 /* 12 */ /* then branch */ << I(31)
1088 /* 14 */ << H(TokForLoop) << HS(L"VAR")
1089 /* 21 */ /* iterator */ << I(7)
1090 /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST")
1091 /* 29 */ << H(TokValueTerminator)
1092 /* 30 */ /* body */ << I(12)
1093 /* 32 */ << H(TokLine) << H(1)
1094 /* 34 */ << H(TokHashLiteral) << HS(L"true")
1095 /* 42 */ << H(TokCondition)
1096 /* 43 */ << H(TokTerminator)
1097 /* 44 */ << H(TokTerminator)
1098 /* 45 */ /* else branch */ << I(12)
1099 /* 47 */ << H(TokLine) << H(2)
1100 /* 49 */ << H(TokHashLiteral) << HS(L"true")
1101 /* 57 */ << H(TokCondition)
1102 /* 58 */ << H(TokTerminator))
1103 << ""
1104 << true;
1105
1106 QTest::newRow(dataTag: "next()")
1107 << "for(ever): next()"
1108 << TS(
1109 /* 0 */ << H(TokLine) << H(1)
1110 /* 2 */ << H(TokForLoop) << HS(L"")
1111 /* 6 */ /* iterator */ << I(9)
1112 /* 8 */ << H(TokHashLiteral) << HS(L"ever")
1113 /* 16 */ << H(TokValueTerminator)
1114 /* 17 */ /* body */ << I(4)
1115 /* 19 */ << H(TokLine) << H(1)
1116 /* 21 */ << H(TokNext)
1117 /* 22 */ << H(TokTerminator))
1118 << ""
1119 << true;
1120
1121 QTest::newRow(dataTag: "break()")
1122 << "for(ever): break()"
1123 << TS(
1124 /* 0 */ << H(TokLine) << H(1)
1125 /* 2 */ << H(TokForLoop) << HS(L"")
1126 /* 6 */ /* iterator */ << I(9)
1127 /* 8 */ << H(TokHashLiteral) << HS(L"ever")
1128 /* 16 */ << H(TokValueTerminator)
1129 /* 17 */ /* body */ << I(4)
1130 /* 19 */ << H(TokLine) << H(1)
1131 /* 21 */ << H(TokBreak)
1132 /* 22 */ << H(TokTerminator))
1133 << ""
1134 << true;
1135
1136 QTest::newRow(dataTag: "top-level return()")
1137 << "return()"
1138 << TS(
1139 /* 0 */ << H(TokLine) << H(1)
1140 /* 2 */ << H(TokReturn))
1141 << ""
1142 << true;
1143
1144 QTest::newRow(dataTag: "else")
1145 << "else"
1146 << TS()
1147 << "in:1: Unexpected 'else'."
1148 << false;
1149
1150 QTest::newRow(dataTag: "test-{else}")
1151 << "test { else }"
1152 << TS(
1153 /* 0 */ << H(TokLine) << H(1)
1154 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1155 /* 10 */ << H(TokCondition)
1156 /* 11 */ << H(TokBranch)
1157 /* 12 */ /* then branch */ << I(1)
1158 /* 14 */ << H(TokTerminator)
1159 /* 15 */ /* else branch */ << I(0))
1160 << "in:1: Unexpected 'else'."
1161 << false;
1162
1163 QTest::newRow(dataTag: "defineTest-{else}")
1164 << "defineTest(fn) { else }"
1165 << TS(
1166 /* 0 */ << H(TokLine) << H(1)
1167 /* 2 */ << H(TokTestDef) << HS(L"fn")
1168 /* 8 */ /* body */ << I(1)
1169 /* 10 */ << H(TokTerminator))
1170 << "in:1: Unexpected 'else'."
1171 << false;
1172
1173 QTest::newRow(dataTag: "for-else")
1174 << "for(ever) { else }"
1175 << TS(
1176 /* 0 */ << H(TokLine) << H(1)
1177 /* 2 */ << H(TokForLoop) << HS(L"")
1178 /* 6 */ /* iterator */ << I(9)
1179 /* 8 */ << H(TokHashLiteral) << HS(L"ever")
1180 /* 16 */ << H(TokValueTerminator)
1181 /* 17 */ /* body */ << I(1)
1182 /* 19 */ << H(TokTerminator))
1183 << "in:1: Unexpected 'else'."
1184 << false;
1185
1186 QTest::newRow(dataTag: "double-test-else")
1187 << "foo bar\nelse"
1188 << TS(
1189 /* 0 */ << H(TokBranch)
1190 /* 1 */ /* then branch */ << I(0)
1191 /* 3 */ /* else branch */ << I(1) // This seems weird
1192 /* 5 */ << H(TokTerminator))
1193 << "in:1: Extra characters after test expression."
1194 << false;
1195
1196 QTest::newRow(dataTag: "test-function-else")
1197 << "foo bar()\nelse"
1198 << TS(
1199 /* 0 */ << H(TokLine) << H(1)
1200 /* 2 */ << H(TokTestCall) // This seems pointless
1201 /* 3 */ << H(TokFuncTerminator)
1202 /* 4 */ << H(TokBranch)
1203 /* 5 */ /* then branch */ << I(0)
1204 /* 7 */ /* else branch */ << I(1) // This seems weird
1205 /* 9 */ << H(TokTerminator))
1206 << "in:1: Extra characters after test expression."
1207 << false;
1208}
1209
1210void tst_qmakelib::addParseBraces()
1211{
1212 QTest::newRow(dataTag: "{}")
1213 << "{ }"
1214 << TS()
1215 << ""
1216 << true;
1217
1218 QTest::newRow(dataTag: "{}-newlines")
1219 << "\n\n{ }\n\n"
1220 << TS()
1221 << ""
1222 << true;
1223
1224 QTest::newRow(dataTag: "{")
1225 << "{"
1226 << TS()
1227 << "in:2: Missing closing brace(s)."
1228 << false;
1229
1230 QTest::newRow(dataTag: "test {")
1231 << "test {"
1232 << TS(
1233 /* 0 */ << H(TokLine) << H(1)
1234 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1235 /* 10 */ << H(TokCondition)
1236 /* 11 */ << H(TokBranch)
1237 /* 12 */ /* then branch */ << I(1)
1238 /* 14 */ << H(TokTerminator)
1239 /* 15 */ /* else branch */ << I(0))
1240 << "in:2: Missing closing brace(s)."
1241 << false;
1242
1243 QTest::newRow(dataTag: "}")
1244 << "}"
1245 << TS()
1246 << "in:1: Excess closing brace."
1247 << false;
1248
1249 QTest::newRow(dataTag: "{test}")
1250 << "{ true }"
1251 << TS(
1252 /* 0 */ << H(TokLine) << H(1)
1253 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1254 /* 10 */ << H(TokCondition))
1255 << ""
1256 << true;
1257
1258 QTest::newRow(dataTag: "{test-newlines}")
1259 << "{\ntrue\n}"
1260 << TS(
1261 /* 0 */ << H(TokLine) << H(2)
1262 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1263 /* 10 */ << H(TokCondition))
1264 << ""
1265 << true;
1266
1267 QTest::newRow(dataTag: "{assignment-test}-test")
1268 << "{ VAR = { foo } bar } true"
1269 << TS(
1270 /* 0 */ << H(TokLine) << H(1)
1271 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
1272 /* 9 */ << H(TokAssign) << H(4)
1273 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{")
1274 /* 14 */ << H(TokLiteral | TokNewStr) << S(L"foo")
1275 /* 19 */ << H(TokLiteral | TokNewStr) << S(L"}")
1276 /* 22 */ << H(TokLiteral | TokNewStr) << S(L"bar")
1277 /* 27 */ << H(TokValueTerminator)
1278 /* 28 */ << H(TokHashLiteral) << HS(L"true")
1279 /* 36 */ << H(TokCondition))
1280 << ""
1281 << true;
1282
1283 QTest::newRow(dataTag: "assignment with excess opening brace")
1284 << "VAR = { { foo }"
1285 << TS(
1286 /* 0 */ << H(TokLine) << H(1)
1287 /* 2 */ << H(TokHashLiteral) << HS(L"VAR")
1288 /* 9 */ << H(TokAssign) << H(4)
1289 /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{")
1290 /* 14 */ << H(TokLiteral | TokNewStr) << S(L"{")
1291 /* 17 */ << H(TokLiteral | TokNewStr) << S(L"foo")
1292 /* 22 */ << H(TokLiteral | TokNewStr) << S(L"}")
1293 /* 25 */ << H(TokValueTerminator))
1294 << "WARNING: in:1: Possible braces mismatch"
1295 << true;
1296
1297 QTest::newRow(dataTag: "test-{}")
1298 << "true {}"
1299 << TS(
1300 /* 0 */ << H(TokLine) << H(1)
1301 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1302 /* 10 */ << H(TokCondition)
1303 /* 11 */ << H(TokBranch)
1304 /* 12 */ /* then branch */ << I(1)
1305 /* 14 */ << H(TokTerminator)
1306 /* 15 */ /* else branch */ << I(0))
1307 << ""
1308 << true;
1309
1310 QTest::newRow(dataTag: "test-{newlines}")
1311 << "true {\n}"
1312 << TS(
1313 /* 0 */ << H(TokLine) << H(1)
1314 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1315 /* 10 */ << H(TokCondition)
1316 /* 11 */ << H(TokBranch)
1317 /* 12 */ /* then branch */ << I(1)
1318 /* 14 */ << H(TokTerminator)
1319 /* 15 */ /* else branch */ << I(0))
1320 << ""
1321 << true;
1322
1323 QTest::newRow(dataTag: "test-{test}")
1324 << "true { true }"
1325 << TS(
1326 /* 0 */ << H(TokLine) << H(1)
1327 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1328 /* 10 */ << H(TokCondition)
1329 /* 11 */ << H(TokBranch)
1330 /* 12 */ /* then branch */ << I(10)
1331 /* 14 */ << H(TokHashLiteral) << HS(L"true")
1332 /* 22 */ << H(TokCondition)
1333 /* 23 */ << H(TokTerminator)
1334 /* 24 */ /* else branch */ << I(0))
1335 << ""
1336 << true;
1337
1338 QTest::newRow(dataTag: "test:-{test}")
1339 << "true: { true }"
1340 << TS(
1341 /* 0 */ << H(TokLine) << H(1)
1342 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1343 /* 10 */ << H(TokCondition)
1344 /* 11 */ << H(TokBranch)
1345 /* 12 */ /* then branch */ << I(10)
1346 /* 14 */ << H(TokHashLiteral) << HS(L"true")
1347 /* 22 */ << H(TokCondition)
1348 /* 23 */ << H(TokTerminator)
1349 /* 24 */ /* else branch */ << I(0))
1350 << "WARNING: in:1: Excess colon in front of opening brace."
1351 << true;
1352
1353 QTest::newRow(dataTag: "test-{test-newlines}")
1354 << "true {\ntrue\n}"
1355 << TS(
1356 /* 0 */ << H(TokLine) << H(1)
1357 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1358 /* 10 */ << H(TokCondition)
1359 /* 11 */ << H(TokBranch)
1360 /* 12 */ /* then branch */ << I(12)
1361 /* 14 */ << H(TokLine) << H(2)
1362 /* 16 */ << H(TokHashLiteral) << HS(L"true")
1363 /* 24 */ << H(TokCondition)
1364 /* 25 */ << H(TokTerminator)
1365 /* 26 */ /* else branch */ << I(0))
1366 << ""
1367 << true;
1368
1369 QTest::newRow(dataTag: "test:-{test-newlines}")
1370 << "true: {\ntrue\n}"
1371 << TS(
1372 /* 0 */ << H(TokLine) << H(1)
1373 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1374 /* 10 */ << H(TokCondition)
1375 /* 11 */ << H(TokBranch)
1376 /* 12 */ /* then branch */ << I(12)
1377 /* 14 */ << H(TokLine) << H(2)
1378 /* 16 */ << H(TokHashLiteral) << HS(L"true")
1379 /* 24 */ << H(TokCondition)
1380 /* 25 */ << H(TokTerminator)
1381 /* 26 */ /* else branch */ << I(0))
1382 << "WARNING: in:1: Excess colon in front of opening brace."
1383 << true;
1384
1385 QTest::newRow(dataTag: "test-{assignment}")
1386 << "true { VAR = {foo} }"
1387 << TS(
1388 /* 0 */ << H(TokLine) << H(1)
1389 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1390 /* 10 */ << H(TokCondition)
1391 /* 11 */ << H(TokBranch)
1392 /* 12 */ /* then branch */ << I(18)
1393 /* 14 */ << H(TokHashLiteral) << HS(L"VAR")
1394 /* 21 */ << H(TokAssign) << H(0)
1395 /* 23 */ << H(TokLiteral | TokNewStr) << S(L"{foo}")
1396 /* 30 */ << H(TokValueTerminator)
1397 /* 31 */ << H(TokTerminator)
1398 /* 32 */ /* else branch */ << I(0))
1399 << ""
1400 << true;
1401
1402 QTest::newRow(dataTag: "test-{test-assignment}")
1403 << "true { true: VAR = {foo} }"
1404 << TS(
1405 /* 0 */ << H(TokLine) << H(1)
1406 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1407 /* 10 */ << H(TokCondition)
1408 /* 11 */ << H(TokBranch)
1409 /* 12 */ /* then branch */ << I(33)
1410 /* 14 */ << H(TokHashLiteral) << HS(L"true")
1411 /* 22 */ << H(TokCondition)
1412 /* 23 */ << H(TokBranch)
1413 /* 24 */ /* then branch */ << I(18)
1414 /* 26 */ << H(TokHashLiteral) << HS(L"VAR")
1415 /* 33 */ << H(TokAssign) << H(0)
1416 /* 35 */ << H(TokLiteral | TokNewStr) << S(L"{foo}")
1417 /* 42 */ << H(TokValueTerminator)
1418 /* 43 */ << H(TokTerminator)
1419 /* 44 */ /* else branch */ << I(0)
1420 /* 46 */ << H(TokTerminator)
1421 /* 47 */ /* else branch */ << I(0))
1422 << ""
1423 << true;
1424
1425 QTest::newRow(dataTag: "test-{assignment-newlines}")
1426 << "true {\nVAR = {foo}\n}"
1427 << TS(
1428 /* 0 */ << H(TokLine) << H(1)
1429 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1430 /* 10 */ << H(TokCondition)
1431 /* 11 */ << H(TokBranch)
1432 /* 12 */ /* then branch */ << I(20)
1433 /* 14 */ << H(TokLine) << H(2)
1434 /* 16 */ << H(TokHashLiteral) << HS(L"VAR")
1435 /* 23 */ << H(TokAssign) << H(0)
1436 /* 25 */ << H(TokLiteral | TokNewStr) << S(L"{foo}")
1437 /* 32 */ << H(TokValueTerminator)
1438 /* 33 */ << H(TokTerminator)
1439 /* 34 */ /* else branch */ << I(0))
1440 << ""
1441 << true;
1442
1443 QTest::newRow(dataTag: "test-{}-else-test-{}")
1444 << "true {} else: true {}"
1445 << TS(
1446 /* 0 */ << H(TokLine) << H(1)
1447 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1448 /* 10 */ << H(TokCondition)
1449 /* 11 */ << H(TokBranch)
1450 /* 12 */ /* then branch */ << I(1)
1451 /* 14 */ << H(TokTerminator)
1452 /* 15 */ /* else branch */ << I(18)
1453 /* 17 */ << H(TokLine) << H(1)
1454 /* 19 */ << H(TokHashLiteral) << HS(L"true")
1455 /* 27 */ << H(TokCondition)
1456 /* 28 */ << H(TokBranch)
1457 /* 29 */ /* then branch */ << I(1)
1458 /* 31 */ << H(TokTerminator)
1459 /* 32 */ /* else branch */ << I(0)
1460 /* 34 */ << H(TokTerminator))
1461 << ""
1462 << true;
1463
1464 QTest::newRow(dataTag: "test-{}-else-test-{}-newlines")
1465 << "true {\n}\nelse: true {\n}"
1466 << TS(
1467 /* 0 */ << H(TokLine) << H(1)
1468 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1469 /* 10 */ << H(TokCondition)
1470 /* 11 */ << H(TokBranch)
1471 /* 12 */ /* then branch */ << I(1)
1472 /* 14 */ << H(TokTerminator)
1473 /* 15 */ /* else branch */ << I(18)
1474 /* 17 */ << H(TokLine) << H(3)
1475 /* 19 */ << H(TokHashLiteral) << HS(L"true")
1476 /* 27 */ << H(TokCondition)
1477 /* 28 */ << H(TokBranch)
1478 /* 29 */ /* then branch */ << I(1)
1479 /* 31 */ << H(TokTerminator)
1480 /* 32 */ /* else branch */ << I(0)
1481 /* 34 */ << H(TokTerminator))
1482 << ""
1483 << true;
1484
1485 QTest::newRow(dataTag: "test-{test}-else-test-{}-newlines")
1486 << "true {\ntrue\n}\nelse: true {\n}"
1487 << TS(
1488 /* 0 */ << H(TokLine) << H(1)
1489 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1490 /* 10 */ << H(TokCondition)
1491 /* 11 */ << H(TokBranch)
1492 /* 12 */ /* then branch */ << I(12)
1493 /* 14 */ << H(TokLine) << H(2)
1494 /* 16 */ << H(TokHashLiteral) << HS(L"true")
1495 /* 24 */ << H(TokCondition)
1496 /* 25 */ << H(TokTerminator)
1497 /* 26 */ /* else branch */ << I(18)
1498 /* 28 */ << H(TokLine) << H(4)
1499 /* 30 */ << H(TokHashLiteral) << HS(L"true")
1500 /* 38 */ << H(TokCondition)
1501 /* 39 */ << H(TokBranch)
1502 /* 40 */ /* then branch */ << I(1)
1503 /* 42 */ << H(TokTerminator)
1504 /* 43 */ /* else branch */ << I(0)
1505 /* 45 */ << H(TokTerminator))
1506 << ""
1507 << true;
1508
1509 QTest::newRow(dataTag: "for-{next}")
1510 << "for(ever) { next() }"
1511 << TS(
1512 /* 0 */ << H(TokLine) << H(1)
1513 /* 2 */ << H(TokForLoop) << HS(L"")
1514 /* 6 */ /* iterator */ << I(9)
1515 /* 8 */ << H(TokHashLiteral) << HS(L"ever")
1516 /* 16 */ << H(TokValueTerminator)
1517 /* 17 */ /* body */ << I(4)
1518 /* 19 */ << H(TokLine) << H(1)
1519 /* 21 */ << H(TokNext)
1520 /* 22 */ << H(TokTerminator))
1521 << ""
1522 << true;
1523
1524 QTest::newRow(dataTag: "for:-{next}")
1525 << "for(ever): { next() }"
1526 << TS(
1527 /* 0 */ << H(TokLine) << H(1)
1528 /* 2 */ << H(TokForLoop) << HS(L"")
1529 /* 6 */ /* iterator */ << I(9)
1530 /* 8 */ << H(TokHashLiteral) << HS(L"ever")
1531 /* 16 */ << H(TokValueTerminator)
1532 /* 17 */ /* body */ << I(4)
1533 /* 19 */ << H(TokLine) << H(1)
1534 /* 21 */ << H(TokNext)
1535 /* 22 */ << H(TokTerminator))
1536 << "WARNING: in:1: Excess colon in front of opening brace."
1537 << true;
1538
1539 QTest::newRow(dataTag: "test-for-{test-else-test-newlines}")
1540 << "true:for(VAR, LIST) {\ntrue\nelse: true\n}"
1541 << TS(
1542 /* 0 */ << H(TokLine) << H(1)
1543 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1544 /* 10 */ << H(TokCondition)
1545 /* 11 */ << H(TokBranch)
1546 /* 12 */ /* then branch */ << I(48)
1547 /* 14 */ << H(TokForLoop) << HS(L"VAR")
1548 /* 21 */ /* iterator */ << I(7)
1549 /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST")
1550 /* 29 */ << H(TokValueTerminator)
1551 /* 30 */ /* body */ << I(29)
1552 /* 32 */ << H(TokLine) << H(2)
1553 /* 34 */ << H(TokHashLiteral) << HS(L"true")
1554 /* 42 */ << H(TokCondition)
1555 /* 43 */ << H(TokBranch)
1556 /* 44 */ /* then branch */ << I(0)
1557 /* 46 */ /* else branch */ << I(12)
1558 /* 48 */ << H(TokLine) << H(3)
1559 /* 50 */ << H(TokHashLiteral) << HS(L"true")
1560 /* 58 */ << H(TokCondition)
1561 /* 59 */ << H(TokTerminator)
1562 /* 60 */ << H(TokTerminator)
1563 /* 61 */ << H(TokTerminator)
1564 /* 62 */ /* else branch */ << I(0))
1565 << ""
1566 << true;
1567
1568 QTest::newRow(dataTag: "test-for-{test-else-test}")
1569 << "true:for(VAR, LIST) { true\nelse: true }"
1570 << TS(
1571 /* 0 */ << H(TokLine) << H(1)
1572 /* 2 */ << H(TokHashLiteral) << HS(L"true")
1573 /* 10 */ << H(TokCondition)
1574 /* 11 */ << H(TokBranch)
1575 /* 12 */ /* then branch */ << I(48)
1576 /* 14 */ << H(TokForLoop) << HS(L"VAR")
1577 /* 21 */ /* iterator */ << I(7)
1578 /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST")
1579 /* 29 */ << H(TokValueTerminator)
1580 /* 30 */ /* body */ << I(29)
1581 /* 32 */ << H(TokLine) << H(1)
1582 /* 34 */ << H(TokHashLiteral) << HS(L"true")
1583 /* 42 */ << H(TokCondition)
1584 /* 43 */ << H(TokBranch)
1585 /* 44 */ /* then branch */ << I(0)
1586 /* 46 */ /* else branch */ << I(12)
1587 /* 48 */ << H(TokLine) << H(2)
1588 /* 50 */ << H(TokHashLiteral) << HS(L"true")
1589 /* 58 */ << H(TokCondition)
1590 /* 59 */ << H(TokTerminator)
1591 /* 60 */ << H(TokTerminator)
1592 /* 61 */ << H(TokTerminator)
1593 /* 62 */ /* else branch */ << I(0))
1594 << ""
1595 << true;
1596}
1597
1598void tst_qmakelib::addParseCustomFunctions()
1599{
1600 QTest::newRow(dataTag: "defineTest-{newlines}")
1601 << "defineTest(test) {\n}"
1602 << TS(
1603 /* 0 */ << H(TokLine) << H(1)
1604 /* 2 */ << H(TokTestDef) << HS(L"test")
1605 /* 10 */ /* body */ << I(1)
1606 /* 12 */ << H(TokTerminator))
1607 << ""
1608 << true;
1609
1610 QTest::newRow(dataTag: "defineTest:-test")
1611 << "defineTest(test): test"
1612 << TS(
1613 /* 0 */ << H(TokLine) << H(1)
1614 /* 2 */ << H(TokTestDef) << HS(L"test")
1615 /* 10 */ /* body */ << I(12)
1616 /* 12 */ << H(TokLine) << H(1)
1617 /* 14 */ << H(TokHashLiteral) << HS(L"test")
1618 /* 22 */ << H(TokCondition)
1619 /* 23 */ << H(TokTerminator))
1620 << ""
1621 << true;
1622
1623 QTest::newRow(dataTag: "defineTest-{test}")
1624 << "defineTest(test) { test }"
1625 << TS(
1626 /* 0 */ << H(TokLine) << H(1)
1627 /* 2 */ << H(TokTestDef) << HS(L"test")
1628 /* 10 */ /* body */ << I(12)
1629 /* 12 */ << H(TokLine) << H(1)
1630 /* 14 */ << H(TokHashLiteral) << HS(L"test")
1631 /* 22 */ << H(TokCondition)
1632 /* 23 */ << H(TokTerminator))
1633 << ""
1634 << true;
1635
1636 QTest::newRow(dataTag: "defineTest-{return}")
1637 << "defineTest(test) { return() }"
1638 << TS(
1639 /* 0 */ << H(TokLine) << H(1)
1640 /* 2 */ << H(TokTestDef) << HS(L"test")
1641 /* 10 */ /* body */ << I(4)
1642 /* 12 */ << H(TokLine) << H(1)
1643 /* 14 */ << H(TokReturn)
1644 /* 15 */ << H(TokTerminator))
1645 << ""
1646 << true;
1647
1648 QTest::newRow(dataTag: "defineReplace-{return-stuff}")
1649 << "defineReplace(stuff) { return(foo bar) }"
1650 << TS(
1651 /* 0 */ << H(TokLine) << H(1)
1652 /* 2 */ << H(TokReplaceDef) << HS(L"stuff")
1653 /* 11 */ /* body */ << I(14)
1654 /* 13 */ << H(TokLine) << H(1)
1655 /* 15 */ << H(TokLiteral | TokNewStr) << S(L"foo")
1656 /* 20 */ << H(TokLiteral | TokNewStr) << S(L"bar")
1657 /* 25 */ << H(TokReturn)
1658 /* 26 */ << H(TokTerminator))
1659 << ""
1660 << true;
1661
1662 QTest::newRow(dataTag: "test-AND-defineTest-{}")
1663 << "test: defineTest(test) {}"
1664 << TS(
1665 /* 0 */ << H(TokLine) << H(1)
1666 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1667 /* 10 */ << H(TokCondition)
1668 /* 11 */ << H(TokAnd)
1669 /* 12 */ << H(TokTestDef) << HS(L"test")
1670 /* 20 */ /* body */ << I(1)
1671 /* 22 */ << H(TokTerminator))
1672 << ""
1673 << true;
1674
1675 QTest::newRow(dataTag: "test-OR-defineTest-{}")
1676 << "test| defineTest(test) {}"
1677 << TS(
1678 /* 0 */ << H(TokLine) << H(1)
1679 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1680 /* 10 */ << H(TokCondition)
1681 /* 11 */ << H(TokOr)
1682 /* 12 */ << H(TokTestDef) << HS(L"test")
1683 /* 20 */ /* body */ << I(1)
1684 /* 22 */ << H(TokTerminator))
1685 << ""
1686 << true;
1687
1688 QTest::newRow(dataTag: "bypassNesting()-{return}")
1689 << "defineTest(test) { bypassNesting() { return(true) } }"
1690 << TS(
1691 /* 0 */ << H(TokLine) << H(1)
1692 /* 2 */ << H(TokTestDef) << HS(L"test")
1693 /* 10 */ /* body */ << I(16)
1694 /* 12 */ << H(TokLine) << H(1)
1695 /* 14 */ << H(TokBypassNesting)
1696 /* 15 */ /* block */ << I(10)
1697 /* 17 */ << H(TokLine) << H(1)
1698 /* 19 */ << H(TokLiteral | TokNewStr) << S(L"true")
1699 /* 25 */ << H(TokReturn)
1700 /* 26 */ << H(TokTerminator)
1701 /* 27 */ << H(TokTerminator))
1702 << ""
1703 << true;
1704
1705 QTest::newRow(dataTag: "test-AND-bypassNesting()-{}")
1706 << "defineTest(test) { test: bypassNesting() {} }"
1707 << TS(
1708 /* 0 */ << H(TokLine) << H(1)
1709 /* 2 */ << H(TokTestDef) << HS(L"test")
1710 /* 10 */ /* body */ << I(17)
1711 /* 12 */ << H(TokLine) << H(1)
1712 /* 14 */ << H(TokHashLiteral) << HS(L"test")
1713 /* 22 */ << H(TokCondition)
1714 /* 23 */ << H(TokAnd)
1715 /* 24 */ << H(TokBypassNesting)
1716 /* 25 */ /* block */ << I(1)
1717 /* 27 */ << H(TokTerminator)
1718 /* 28 */ << H(TokTerminator))
1719 << ""
1720 << true;
1721
1722 QTest::newRow(dataTag: "test-OR-bypassNesting()-{}")
1723 << "defineTest(test) { test| bypassNesting() {} }"
1724 << TS(
1725 /* 0 */ << H(TokLine) << H(1)
1726 /* 2 */ << H(TokTestDef) << HS(L"test")
1727 /* 10 */ /* body */ << I(17)
1728 /* 12 */ << H(TokLine) << H(1)
1729 /* 14 */ << H(TokHashLiteral) << HS(L"test")
1730 /* 22 */ << H(TokCondition)
1731 /* 23 */ << H(TokOr)
1732 /* 24 */ << H(TokBypassNesting)
1733 /* 25 */ /* block */ << I(1)
1734 /* 27 */ << H(TokTerminator)
1735 /* 28 */ << H(TokTerminator))
1736 << ""
1737 << true;
1738}
1739
1740void tst_qmakelib::addParseAbuse()
1741{
1742 QTest::newRow(dataTag: "!")
1743 << ""
1744 << TS()
1745 << ""
1746 << true;
1747
1748 QTest::newRow(dataTag: "|")
1749 << ""
1750 << TS()
1751 << ""
1752 << true;
1753
1754 QTest::newRow(dataTag: ":")
1755 << ""
1756 << TS()
1757 << ""
1758 << true;
1759
1760 QTest::newRow(dataTag: "NOT-assignment")
1761 << "!VAR ="
1762 << TS()
1763 << "in:1: Unexpected NOT operator in front of assignment."
1764 << false;
1765
1766 QTest::newRow(dataTag: "NOT-{}")
1767 << "!{}"
1768 << TS()
1769 << "in:1: Unexpected NOT operator in front of opening brace."
1770 << false;
1771
1772 QTest::newRow(dataTag: "NOT-else")
1773 << "test\n!else {}"
1774 << TS()
1775 << "in:2: Unexpected NOT operator in front of else."
1776 << false;
1777
1778 QTest::newRow(dataTag: "NOT-for-{}")
1779 << "!for(ever) {}"
1780 << TS()
1781 << "in:1: Unexpected NOT operator in front of for()."
1782 << false;
1783
1784 QTest::newRow(dataTag: "NOT-defineTest-{}")
1785 << "!defineTest(test) {}"
1786 << TS()
1787 << "in:1: Unexpected NOT operator in front of function definition."
1788 << false;
1789
1790 QTest::newRow(dataTag: "outer-bypassNesting()-{}")
1791 << "bypassNesting() {}"
1792 << TS()
1793 << "in:1: Unexpected bypassNesting()."
1794 << false;
1795
1796 QTest::newRow(dataTag: "bypassNesting(arg)-{}")
1797 << "defineTest(test) { bypassNesting(arg) {} }"
1798 << TS()
1799 << "in:1: bypassNesting() requires zero arguments."
1800 << false;
1801
1802 QTest::newRow(dataTag: "NOT-bypassNesting()-{}")
1803 << "defineTest(test) { !bypassNesting() {} }"
1804 << TS()
1805 << "in:1: Unexpected NOT operator in front of bypassNesting()."
1806 << false;
1807
1808 QTest::newRow(dataTag: "AND-test")
1809 << ":test"
1810 << TS(
1811 /* 0 */ << H(TokLine) << H(1)
1812 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1813 /* 10 */ << H(TokCondition))
1814 << "in:1: AND operator without prior condition."
1815 << false;
1816
1817 QTest::newRow(dataTag: "test-AND-else")
1818 << "test:else"
1819 << TS(
1820 /* 0 */ << H(TokLine) << H(1)
1821 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1822 /* 10 */ << H(TokCondition))
1823 << "in:1: Unexpected AND operator in front of else."
1824 << false;
1825
1826 QTest::newRow(dataTag: "test-AND-AND-test")
1827 << "test::test"
1828 << TS(
1829 /* 0 */ << H(TokLine) << H(1)
1830 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1831 /* 10 */ << H(TokCondition)
1832 /* 11 */ << H(TokAnd)
1833 /* 12 */ << H(TokHashLiteral) << HS(L"test")
1834 /* 20 */ << H(TokCondition))
1835 << "WARNING: in:1: Stray AND operator in front of AND operator."
1836 << true;
1837
1838 QTest::newRow(dataTag: "test-AND-OR-test")
1839 << "test:|test"
1840 << TS(
1841 /* 0 */ << H(TokLine) << H(1)
1842 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1843 /* 10 */ << H(TokCondition)
1844 /* 11 */ << H(TokOr)
1845 /* 12 */ << H(TokHashLiteral) << HS(L"test")
1846 /* 20 */ << H(TokCondition))
1847 << "WARNING: in:1: Stray AND operator in front of OR operator."
1848 << true;
1849
1850 QTest::newRow(dataTag: "test-{AND-test}")
1851 << "test { :test }"
1852 << TS(
1853 /* 0 */ << H(TokLine) << H(1)
1854 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1855 /* 10 */ << H(TokCondition)
1856 /* 11 */ << H(TokBranch)
1857 /* 12 */ /* then branch */ << I(10)
1858 /* 14 */ << H(TokHashLiteral) << HS(L"test")
1859 /* 22 */ << H(TokCondition)
1860 /* 23 */ << H(TokTerminator)
1861 /* 24 */ /* else branch */ << I(0))
1862 << "in:1: AND operator without prior condition."
1863 << false;
1864
1865 QTest::newRow(dataTag: "test-OR-assignment")
1866 << "foo| VAR ="
1867 << TS()
1868 << "in:1: Unexpected OR operator in front of assignment."
1869 << false;
1870
1871 QTest::newRow(dataTag: "test-OR-{}")
1872 << "foo|{}"
1873 << TS()
1874 << "in:1: Unexpected OR operator in front of opening brace."
1875 << false;
1876
1877 QTest::newRow(dataTag: "test-OR-for")
1878 << "foo|for(ever) {}"
1879 << TS()
1880 << "in:1: Unexpected OR operator in front of for()."
1881 << false;
1882
1883 QTest::newRow(dataTag: "OR-test")
1884 << "|test"
1885 << TS(
1886 /* 0 */ << H(TokLine) << H(1)
1887 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1888 /* 10 */ << H(TokCondition))
1889 << "in:1: OR operator without prior condition."
1890 << false;
1891
1892 QTest::newRow(dataTag: "test-OR-else")
1893 << "test|else"
1894 << TS(
1895 /* 0 */ << H(TokLine) << H(1)
1896 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1897 /* 10 */ << H(TokCondition))
1898 << "in:1: Unexpected OR operator in front of else."
1899 << false;
1900
1901 QTest::newRow(dataTag: "test-OR-OR-test")
1902 << "test||test"
1903 << TS(
1904 /* 0 */ << H(TokLine) << H(1)
1905 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1906 /* 10 */ << H(TokCondition)
1907 /* 11 */ << H(TokOr)
1908 /* 12 */ << H(TokHashLiteral) << HS(L"test")
1909 /* 20 */ << H(TokCondition))
1910 << "WARNING: in:1: Stray OR operator in front of OR operator."
1911 << true;
1912
1913 QTest::newRow(dataTag: "test-OR-AND-test")
1914 << "test|:test"
1915 << TS(
1916 /* 0 */ << H(TokLine) << H(1)
1917 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1918 /* 10 */ << H(TokCondition)
1919 /* 11 */ << H(TokAnd)
1920 /* 12 */ << H(TokHashLiteral) << HS(L"test")
1921 /* 20 */ << H(TokCondition))
1922 << "WARNING: in:1: Stray OR operator in front of AND operator."
1923 << true;
1924
1925 QTest::newRow(dataTag: "test-{OR-test}")
1926 << "test { |test }"
1927 << TS(
1928 /* 0 */ << H(TokLine) << H(1)
1929 /* 2 */ << H(TokHashLiteral) << HS(L"test")
1930 /* 10 */ << H(TokCondition)
1931 /* 11 */ << H(TokBranch)
1932 /* 12 */ /* then branch */ << I(10)
1933 /* 14 */ << H(TokHashLiteral) << HS(L"test")
1934 /* 22 */ << H(TokCondition)
1935 /* 23 */ << H(TokTerminator)
1936 /* 24 */ /* else branch */ << I(0))
1937 << "in:1: OR operator without prior condition."
1938 << false;
1939
1940 // Token buffer overflow. Verify with Valgrind or asan.
1941 QTest::newRow(dataTag: "QTCREATORBUG-16508")
1942 << "a{b{c{d{"
1943 << TS()
1944 << "in:2: Missing closing brace(s)."
1945 << false;
1946}
1947
1948void tst_qmakelib::proParser_data()
1949{
1950 QTest::addColumn<QString>(name: "in");
1951 QTest::addColumn<QString>(name: "out");
1952 QTest::addColumn<QString>(name: "msgs");
1953 QTest::addColumn<bool>(name: "ok");
1954
1955 QTest::newRow(dataTag: "empty")
1956 << ""
1957 << TS()
1958 << ""
1959 << true;
1960
1961 QTest::newRow(dataTag: "empty (whitespace)")
1962 << " \t \t"
1963 << TS()
1964 << ""
1965 << true;
1966
1967 addParseOperators(); // Variable operators
1968
1969 addParseValues();
1970
1971 addParseConditions(); // "Tests"
1972
1973 addParseControlStatements();
1974
1975 addParseBraces();
1976
1977 addParseCustomFunctions();
1978
1979 addParseAbuse(); // Mostly operator abuse
1980
1981 // option() (these produce no tokens)
1982
1983 QTest::newRow(dataTag: "option(host_build)")
1984 << "option(host_build)"
1985 << TS()
1986 << ""
1987 << true;
1988
1989 QTest::newRow(dataTag: "option()")
1990 << "option()"
1991 << TS()
1992 << "in:1: option() requires one literal argument."
1993 << false;
1994
1995 QTest::newRow(dataTag: "option(host_build magic)")
1996 << "option(host_build magic)"
1997 << TS()
1998 << "in:1: option() requires one literal argument."
1999 << false;
2000
2001 QTest::newRow(dataTag: "option(host_build, magic)")
2002 << "option(host_build, magic)"
2003 << TS()
2004 << "in:1: option() requires one literal argument."
2005 << false;
2006
2007 QTest::newRow(dataTag: "option($$OPTION)")
2008 << "option($$OPTION)"
2009 << TS()
2010 << "in:1: option() requires one literal argument."
2011 << false;
2012
2013 QTest::newRow(dataTag: "{option(host_build)}")
2014 << "{option(host_build)}"
2015 << TS()
2016 << "in:1: option() must appear outside any control structures."
2017 << false;
2018}
2019
2020QT_WARNING_POP
2021
2022void tst_qmakelib::proParser()
2023{
2024 QFETCH(QString, in);
2025 QFETCH(QString, out);
2026 QFETCH(QString, msgs);
2027 QFETCH(bool, ok);
2028
2029 bool verified = true;
2030 QMakeTestHandler handler;
2031 handler.setExpectedMessages(msgs.split(sep: '\n', behavior: Qt::SkipEmptyParts));
2032 QMakeVfs vfs;
2033 QMakeParser parser(0, &vfs, &handler);
2034 ProFile *pro = parser.parsedProBlock(contents: QStringRef(&in), id: 0, name: "in", line: 1, grammar: QMakeParser::FullGrammar);
2035 if (handler.printedMessages()) {
2036 qWarning(msg: "Got unexpected message(s)");
2037 verified = false;
2038 }
2039 QStringList missingMsgs = handler.expectedMessages();
2040 if (!missingMsgs.isEmpty()) {
2041 foreach (const QString &msg, missingMsgs)
2042 qWarning(msg: "Missing message: %s", qPrintable(msg));
2043 verified = false;
2044 }
2045 if (pro->isOk() != ok) {
2046 static const char * const lbl[] = { "failure", "success" };
2047 qWarning(msg: "Expected %s, got %s", lbl[int(ok)], lbl[1 - int(ok)]);
2048 verified = false;
2049 }
2050 if (pro->items() != out && (ok || !out.isEmpty())) {
2051 qWarning(msg: "Bytecode mismatch.\nActual:%s\nExpected:%s",
2052 qPrintable(QMakeParser::formatProBlock(pro->items())),
2053 qPrintable(QMakeParser::formatProBlock(out)));
2054 verified = false;
2055 }
2056 pro->deref();
2057 QVERIFY(verified);
2058}
2059

source code of qtbase/tests/auto/tools/qmakelib/parsertest.cpp