Assorted improvements to diagnostics.
[pspp] / tests / language / expressions / parse.at
1 dnl PSPP - a program for statistical analysis.
2 dnl Copyright (C) 2017 Free Software Foundation, Inc.
3 dnl
4 dnl This program is free software: you can redistribute it and/or modify
5 dnl it under the terms of the GNU General Public License as published by
6 dnl the Free Software Foundation, either version 3 of the License, or
7 dnl (at your option) any later version.
8 dnl
9 dnl This program is distributed in the hope that it will be useful,
10 dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
11 dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 dnl GNU General Public License for more details.
13 dnl
14 dnl You should have received a copy of the GNU General Public License
15 dnl along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 dnl
17 AT_BANNER([expression parsing])
18
19 AT_SETUP([parse expression with unknown variable crash])
20 AT_KEYWORDS([expression expressions parse])
21 AT_DATA([parse.sps], [dnl
22 INPUT PROGRAM.
23 LOOP c=1 to 10.
24 COMPUTE var1=NORMAL(100).
25 END CASE.
26 END LOOP.
27 END FILE.
28 END INPUT PROGRAM.
29
30
31 IF ( y > 0 ) .
32 COMPUTE x=y.
33 END IF.
34 ])
35 AT_CHECK([pspp -O format=csv parse.sps], [1], [dnl
36 "parse.sps:10.6: error: IF: Unknown identifier y.
37    10 | IF ( y > 0 ) .
38       |      ^"
39
40 parse.sps:11: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
41 ])
42 AT_CLEANUP
43
44 AT_SETUP([parsing boolean expression with type mismatch])
45 AT_KEYWORDS([expression expressions parse])
46 AT_DATA([parse.sps], [dnl
47 DATA LIST NOTABLE/x 1(A).
48 IF 'foo'.
49 ])
50 AT_CHECK([pspp parse.sps], [1], [dnl
51 parse.sps:2.4-2.8: error: IF: Type mismatch: expression has string type, but a
52 boolean value is required here.
53     2 | IF 'foo'.
54       |    ^~~~~
55 ])
56 AT_CLEANUP
57
58 AT_SETUP([parsing numeric expression with type mismatch])
59 AT_KEYWORDS([expression expressions parse])
60 AT_DATA([parse.sps], [dnl
61 DATA LIST NOTABLE/x 1.
62 COMPUTE x='foo'.
63 ])
64 AT_CHECK([pspp parse.sps], [1], [dnl
65 parse.sps:2.11-2.15: error: COMPUTE: Type mismatch: expression has type
66 'string', but a numeric value is required.
67     2 | COMPUTE x='foo'.
68       |           ^~~~~
69 ])
70 AT_CLEANUP
71
72 AT_SETUP([parsing string expression with type mismatch])
73 AT_KEYWORDS([expression expressions parse negative])
74 AT_DATA([parse.sps], [dnl
75 DATA LIST NOTABLE/x 1(A).
76 COMPUTE x=1.
77 ])
78 AT_CHECK([pspp parse.sps], [1], [dnl
79 parse.sps:2.11: error: COMPUTE: Type mismatch: expression has type 'number',
80 but a string value is required.
81     2 | COMPUTE x=1.
82       |           ^
83 ])
84 AT_CLEANUP
85
86 AT_SETUP([assigning string expression to new variable])
87 AT_KEYWORDS([expression expressions parse negative])
88 AT_DATA([parse.sps], [dnl
89 DATA LIST NOTABLE/x 1(A).
90 COMPUTE y='a'.
91 ])
92 AT_CHECK([pspp parse.sps], [1], [dnl
93 parse.sps:2.9: error: COMPUTE: This command tries to create a new variable y by
94 assigning a string value to it, but this is not supported.  Use the STRING
95 command to create the new variable with the correct width before assigning to
96 it, e.g. STRING y(A20).
97     2 | COMPUTE y='a'.
98       |         ^
99 ])
100 AT_CLEANUP
101
102 AT_SETUP([parse expression with unknown system variable])
103 AT_KEYWORDS([expression expressions parse negative])
104 AT_DATA([parse.sps], [dnl
105 DATA LIST NOTABLE/x 1.
106 COMPUTE x=$nonexistent.
107 ])
108 AT_CHECK([pspp parse.sps], [1], [dnl
109 parse.sps:2.11-2.22: error: COMPUTE: Unknown system variable $nonexistent.
110     2 | COMPUTE x=$nonexistent.
111       |           ^~~~~~~~~~~~
112 ])
113 AT_CLEANUP
114
115 AT_SETUP([parse expression with unknown identifier])
116 AT_KEYWORDS([expression expressions parse negative])
117 AT_DATA([parse.sps], [dnl
118 DATA LIST NOTABLE/x 1.
119 COMPUTE x=y.
120 ])
121 AT_CHECK([pspp parse.sps], [1], [dnl
122 parse.sps:2.11: error: COMPUTE: Unknown identifier y.
123     2 | COMPUTE x=y.
124       |           ^
125 ])
126 AT_CLEANUP
127
128 AT_SETUP([parse expression with extension function in compatibility mode])
129 AT_KEYWORDS([expression expressions parse negative])
130 AT_DATA([parse.sps], [dnl
131 DEBUG EVALUATE/ACOS(0)*0.
132 ])
133 AT_CHECK([pspp --testing-mode --syntax=compatible parse.sps], [0], [dnl
134 parse.sps:1.16-1.22: warning: DEBUG EVALUATE: ACOS(number) is a PSPP extension.
135     1 | DEBUG EVALUATE/ACOS(0)*0.
136       |                ^~~~~~~
137
138 ACOS(0)*0 => 0.00
139 ])
140 AT_CLEANUP
141
142 AT_SETUP([LAG expression following TEMPORARY])
143 AT_KEYWORDS([expression expressions parse negative])
144 AT_DATA([parse.sps], [dnl
145 DATA LIST NOTABLE/x 1.
146 TEMPORARY
147 COMPUTE y=LAG(x).
148 ])
149 AT_CHECK([pspp parse.sps], [1], [dnl
150 parse.sps:3.11-3.16: error: COMPUTE: LAG(num_variable) may not appear after
151 TEMPORARY.
152     3 | COMPUTE y=LAG(x).
153       |           ^~~~~~
154 ])
155 AT_CLEANUP
156
157 AT_SETUP([parse expression with invalid logical expression])
158 AT_KEYWORDS([expression expressions parse negative])
159 AT_DATA([parse.sps], [dnl
160 INPUT PROGRAM.
161 LOOP c=1 to 10.
162 COMPUTE var1=NORMAL(100).
163 END CASE.
164 END LOOP.
165 END FILE.
166 END INPUT PROGRAM.
167
168 SELECT IF 2.
169 ])
170 AT_CHECK([pspp parse.sps], [1], [dnl
171 parse.sps:9.11: error: SELECT IF: This expression, which must be 0 or 1,
172 evaluated to 2.  It will be treated as 0.
173     9 | SELECT IF 2.
174       |           ^
175 ])
176 AT_CLEANUP
177
178 AT_SETUP([chaining operators that shouldn't be])
179 AT_KEYWORDS([expression expressions parse negative])
180 AT_DATA([parse.sps], [dnl
181 INPUT PROGRAM.
182 * These should provoke warnings.
183 COMPUTE a = 1 < 2 < 3.
184 COMPUTE b = 1 > 2 < 0.
185 COMPUTE c = 2**3**4.
186
187 * These should not provoke warnings.
188 COMPUTE d = (1 < 2) < 3.
189 COMPUTE e = (2**3)**4.
190 END INPUT PROGRAM.
191 ])
192 AT_CHECK([pspp parse.sps], [1], [dnl
193 parse.sps:3.13-3.21: warning: COMPUTE: Chaining relational operators (e.g. `a <
194 b < c') will not produce the mathematically expected result.  Use the AND
195 logical operator to fix the problem (e.g. `a < b AND b < c').  To disable this
196 warning, insert parentheses.
197     3 | COMPUTE a = 1 < 2 < 3.
198       |             ^~~~~~~~~
199
200 parse.sps:4.13-4.21: warning: COMPUTE: Chaining relational operators (e.g. `a <
201 b < c') will not produce the mathematically expected result.  Use the AND
202 logical operator to fix the problem (e.g. `a < b AND b < c').  To disable this
203 warning, insert parentheses.
204     4 | COMPUTE b = 1 > 2 < 0.
205       |             ^~~~~~~~~
206
207 parse.sps:5.13-5.19: warning: COMPUTE: The exponentiation operator (`**') is
208 left-associative: `a**b**c' equals `(a**b)**c', not `a**(b**c)'.  To disable
209 this warning, insert parentheses.
210     5 | COMPUTE c = 2**3**4.
211       |             ^~~~~~~
212
213 parse.sps:1.1-10.17: error: INPUT PROGRAM: Input program does not contain DATA
214 LIST or END FILE.
215     1 | INPUT PROGRAM.
216     2 | * These should provoke warnings.
217   ... |
218    10 | END INPUT PROGRAM.
219 ])
220 AT_CLEANUP
221
222 AT_SETUP([binary operator type mismatch])
223 AT_KEYWORDS([expression expressions parse negative])
224 AT_DATA([parse.sps], [dnl
225 DEBUG EVALUATE /1 + 'a'.
226 DEBUG EVALUATE /'a' + 1.
227 DEBUG EVALUATE /'a' + 'a'.
228 DEBUG EVALUATE /'a' + ('a').
229
230 DEBUG EVALUATE /1 < 'a'.
231 DEBUG EVALUATE /'a' < 1.
232 DEBUG EVALUATE /'a' < 'b' < 'c'.
233 ])
234 AT_CHECK([pspp --testing-mode parse.sps], [1], [dnl
235 parse.sps:1.17-1.23: error: DEBUG EVALUATE: Both operands of + must be numeric.
236     1 | DEBUG EVALUATE /1 + 'a'.
237       |                 ^~~~~~~
238
239 parse.sps:1.17: note: DEBUG EVALUATE: This operand has type 'number'.
240     1 | DEBUG EVALUATE /1 + 'a'.
241       |                 ^
242
243 parse.sps:1.21-1.23: note: DEBUG EVALUATE: This operand has type 'string'.
244     1 | DEBUG EVALUATE /1 + 'a'.
245       |                     ^~~
246
247 1 + 'a' => error
248
249 parse.sps:2.17-2.23: error: DEBUG EVALUATE: Both operands of + must be numeric.
250     2 | DEBUG EVALUATE /'a' + 1.
251       |                 ^~~~~~~
252
253 parse.sps:2.17-2.19: note: DEBUG EVALUATE: This operand has type 'string'.
254     2 | DEBUG EVALUATE /'a' + 1.
255       |                 ^~~
256
257 parse.sps:2.23: note: DEBUG EVALUATE: This operand has type 'number'.
258     2 | DEBUG EVALUATE /'a' + 1.
259       |                       ^
260
261 'a' + 1 => error
262
263 'a' + 'a' => "aa"
264
265 parse.sps:4.17-4.26: error: DEBUG EVALUATE: Both operands of + must be numeric.
266     4 | DEBUG EVALUATE /'a' + ('a').
267       |                 ^~~~~~~~~~
268
269 parse.sps:4.17-4.19: note: DEBUG EVALUATE: This operand has type 'string'.
270     4 | DEBUG EVALUATE /'a' + ('a').
271       |                 ^~~
272
273 parse.sps:4.24-4.26: note: DEBUG EVALUATE: This operand has type 'string'.
274     4 | DEBUG EVALUATE /'a' + ('a').
275       |                        ^~~
276
277 'a' + ('a') => error
278
279 parse.sps:6.17-6.23: error: DEBUG EVALUATE: Both operands of < must have the
280 same type.
281     6 | DEBUG EVALUATE /1 < 'a'.
282       |                 ^~~~~~~
283
284 parse.sps:6.17: note: DEBUG EVALUATE: This operand has type 'number'.
285     6 | DEBUG EVALUATE /1 < 'a'.
286       |                 ^
287
288 parse.sps:6.21-6.23: note: DEBUG EVALUATE: This operand has type 'string'.
289     6 | DEBUG EVALUATE /1 < 'a'.
290       |                     ^~~
291
292 1 < 'a' => error
293
294 parse.sps:7.17-7.23: error: DEBUG EVALUATE: Both operands of < must have the
295 same type.
296     7 | DEBUG EVALUATE /'a' < 1.
297       |                 ^~~~~~~
298
299 parse.sps:7.17-7.19: note: DEBUG EVALUATE: This operand has type 'string'.
300     7 | DEBUG EVALUATE /'a' < 1.
301       |                 ^~~
302
303 parse.sps:7.23: note: DEBUG EVALUATE: This operand has type 'number'.
304     7 | DEBUG EVALUATE /'a' < 1.
305       |                       ^
306
307 'a' < 1 => error
308
309 parse.sps:8.17-8.31: error: DEBUG EVALUATE: Both operands of < must have the
310 same type.
311     8 | DEBUG EVALUATE /'a' < 'b' < 'c'.
312       |                 ^~~~~~~~~~~~~~~
313
314 parse.sps:8.17-8.25: note: DEBUG EVALUATE: This operand has type 'number'.
315     8 | DEBUG EVALUATE /'a' < 'b' < 'c'.
316       |                 ^~~~~~~~~
317
318 parse.sps:8.29-8.31: note: DEBUG EVALUATE: This operand has type 'string'.
319     8 | DEBUG EVALUATE /'a' < 'b' < 'c'.
320       |                             ^~~
321
322 'a' < 'b' < 'c' => error
323 ])
324 AT_CLEANUP
325
326 AT_SETUP([unary operator type mismatch])
327 AT_KEYWORDS([expression expressions parse negative])
328 AT_DATA([parse.sps], [dnl
329 DEBUG EVALUATE /-'a'.
330 DEBUG EVALUATE /----'a'.
331 DEBUG EVALUATE /NOT 'a'.
332 DEBUG EVALUATE /NOT NOT NOT 'a'.
333 DEBUG EVALUATE /NOT F5.2.
334 ])
335 AT_CHECK([pspp --testing-mode parse.sps], [1], [dnl
336 parse.sps:1.17-1.20: error: DEBUG EVALUATE: The unary - operator requires a
337 numeric operand.
338     1 | DEBUG EVALUATE /-'a'.
339       |                 ^~~~
340
341 parse.sps:1.18-1.20: note: DEBUG EVALUATE: The operand of - has type 'string'.
342     1 | DEBUG EVALUATE /-'a'.
343       |                  ^~~
344
345 -'a' => error
346
347 parse.sps:2.17-2.23: error: DEBUG EVALUATE: The unary - operator requires a
348 numeric operand.
349     2 | DEBUG EVALUATE /----'a'.
350       |                 ^~~~~~~
351
352 parse.sps:2.21-2.23: note: DEBUG EVALUATE: The operand of - has type 'string'.
353     2 | DEBUG EVALUATE /----'a'.
354       |                     ^~~
355
356 ----'a' => error
357
358 parse.sps:3.17-3.23: error: DEBUG EVALUATE: The unary NOT operator requires a
359 numeric operand.
360     3 | DEBUG EVALUATE /NOT 'a'.
361       |                 ^~~~~~~
362
363 parse.sps:3.21-3.23: note: DEBUG EVALUATE: The operand of NOT has type
364 'string'.
365     3 | DEBUG EVALUATE /NOT 'a'.
366       |                     ^~~
367
368 NOT 'a' => error
369
370 parse.sps:4.17-4.31: error: DEBUG EVALUATE: The unary NOT operator requires a
371 numeric operand.
372     4 | DEBUG EVALUATE /NOT NOT NOT 'a'.
373       |                 ^~~~~~~~~~~~~~~
374
375 parse.sps:4.29-4.31: note: DEBUG EVALUATE: The operand of NOT has type
376 'string'.
377     4 | DEBUG EVALUATE /NOT NOT NOT 'a'.
378       |                             ^~~
379
380 NOT NOT NOT 'a' => error
381
382 parse.sps:5.17-5.24: error: DEBUG EVALUATE: The unary NOT operator requires a
383 numeric operand.
384     5 | DEBUG EVALUATE /NOT F5.2.
385       |                 ^~~~~~~~
386
387 parse.sps:5.21-5.24: note: DEBUG EVALUATE: The operand of NOT has type
388 'format'.
389     5 | DEBUG EVALUATE /NOT F5.2.
390       |                     ^~~~
391
392 NOT F5.2 => error
393 ])
394 AT_CLEANUP
395
396 AT_SETUP([parsing with negative numbers])
397 AT_KEYWORDS([expression expressions parse])
398 AT_DATA([parse.sps], [dnl
399 DEBUG EVALUATE NOOPT POSTFIX /-2**3.
400 DEBUG EVALUATE NOOPT POSTFIX /-2**-3**-4.
401 DEBUG EVALUATE/1 - 2.
402 ])
403 AT_CHECK([pspp --testing-mode parse.sps], [0], [dnl
404 number: n<2> number: n<3> POW NEG return_number
405
406 parse.sps:2.31-2.40: warning: DEBUG EVALUATE: The exponentiation operator
407 (`**') is left-associative: `a**b**c' equals `(a**b)**c', not `a**(b**c)'.  To
408 disable this warning, insert parentheses.
409     2 | DEBUG EVALUATE NOOPT POSTFIX /-2**-3**-4.
410       |                               ^~~~~~~~~~
411
412 number: n<2> number: n<-3> POW number: n<-4> POW NEG return_number
413
414 1 - 2 => -1.00
415 ])
416 AT_CLEANUP
417
418 AT_SETUP([system variables])
419 AT_KEYWORDS([expression expressions parse])
420 AT_DATA([parse.sps], [dnl
421 DEBUG EVALUATE /$WIDTH.
422 DEBUG EVALUATE /$LENGTH.
423 DEBUG EVALUATE /$SYSMIS.
424 ])
425 AT_CHECK([pspp --testing-mode parse.sps], [0], [dnl
426 $WIDTH => 79.00
427
428 $LENGTH => 24.00
429
430 $SYSMIS => sysmis
431 ])
432 AT_CLEANUP
433
434 # This test will fail if the current date changes during the test.
435 AT_SETUP([system variables - $DATE $DATE11 $JDATE $TIME])
436 AT_KEYWORDS([expression expressions parse])
437 # Get the date in the formats that $DATE and $DATE11 support.
438 date=$(date +%d-%^b-%y)
439 date11=$(date +%d-%^b-%Y)
440 echo "date=$date"               # Should be date=DD-MMM-YY.
441 echo "date11=$date11"   # Should be date11=DD-MMM-YYYY.
442
443 # Maybe we don't have the 'date' program or it doesn't work as we
444 # expect.  Check by trying to see if $date and $date11 are in the
445 # expected format.  If not, skip the test.
446 AS_CASE([$date],
447   [[[0-9][0-9]-[A-Z][A-Z][A-Z]-[0-9][0-9]]], [],
448   [AT_SKIP_IF([:])])
449 AS_CASE([$date11],
450   [[[0-9][0-9]-[A-Z][A-Z][A-Z]-[0-9][0-9][0-9][0-9]]], [],
451   [AT_SKIP_IF([:])])
452
453 AT_DATA([parse.sps], [dnl
454 DEBUG EVALUATE /$DATE.
455 DEBUG EVALUATE /$DATE11.
456 DEBUG EVALUATE FORMAT=DATE9 /$JDATE * 86400.
457 DEBUG EVALUATE FORMAT=DATE9 /$TIME.
458 ])
459 AT_CHECK_UNQUOTED([pspp --testing-mode parse.sps], [0], [dnl
460 \$DATE => "$date"
461
462 \$DATE11 => "$date11"
463
464 \$JDATE * 86400 => $date
465
466 \$TIME => $date
467 ])
468 AT_CLEANUP
469
470 AT_SETUP([expressions - negative checks])
471 AT_KEYWORDS([expression expressions parse])
472 AT_DATA([evaluate-base.sps], [dnl
473 SET EPOCH 1940.
474 DEBUG EVALUATE SET opt.
475 DEBUG EVALUATE /$nonexistent.
476 DEBUG EVALUATE /RANGE(1, 2).
477 DEBUG EVALUATE /CONCAT.1('a', 'b').
478 DEBUG EVALUATE /foobar(x).
479 DEBUG EVALUATE /CONCAT.1('a' b).
480 DEBUG EVALUATE /NCDF.CHISQ(1, 2, 3).
481 DEBUG EVALUATE (a=1)(b=2) VECTOR/v('abc').
482 ])
483
484 for opt in OPT NOOPT; do
485     AS_BOX([$opt])
486     sed "s/opt/$opt/" < evaluate-base.sps > evaluate.sps
487     AT_CHECK([pspp --testing-mode evaluate.sps], [1], [dnl
488 evaluate.sps:3.17-3.28: error: DEBUG EVALUATE: Unknown system variable
489 $nonexistent.
490     3 | DEBUG EVALUATE /$nonexistent.
491       |                 ^~~~~~~~~~~~
492
493 $nonexistent => error
494
495 evaluate.sps:4.17-4.27: error: DEBUG EVALUATE: RANGE(number, number, number[[,
496 number, number]]...) must have an odd number of arguments.
497     4 | DEBUG EVALUATE /RANGE(1, 2).
498       |                 ^~~~~~~~~~~
499
500 RANGE(1, 2) => error
501
502 evaluate.sps:5.17-5.34: error: DEBUG EVALUATE: CONCAT(string[[, string]]...)
503 function cannot accept suffix .1 to specify the minimum number of valid
504 arguments.
505     5 | DEBUG EVALUATE /CONCAT.1('a', 'b').
506       |                 ^~~~~~~~~~~~~~~~~~
507
508 CONCAT.1('a', 'b') => error
509
510 evaluate.sps:6.17-6.22: error: DEBUG EVALUATE: No function or vector named
511 foobar.
512     6 | DEBUG EVALUATE /foobar(x).
513       |                 ^~~~~~
514
515 foobar(x) => error
516
517 evaluate.sps:7.30: error: DEBUG EVALUATE: Syntax error expecting `,' or `@:}@'.
518     7 | DEBUG EVALUATE /CONCAT.1('a' b).
519       |                              ^
520
521 CONCAT.1('a' b) => error
522
523 evaluate.sps:8.17-8.35: error: DEBUG EVALUATE: NCDF.CHISQ(number, number,
524 number) is not available in this version of PSPP.
525     8 | DEBUG EVALUATE /NCDF.CHISQ(1, 2, 3).
526       |                 ^~~~~~~~~~~~~~~~~~~
527
528 NCDF.CHISQ(1, 2, 3) => error
529
530 evaluate.sps:9.34-9.41: error: DEBUG EVALUATE: A vector index must be numeric.
531     9 | DEBUG EVALUATE (a=1)(b=2) VECTOR/v('abc').
532       |                                  ^~~~~~~~
533
534 evaluate.sps:9.36-9.40: note: DEBUG EVALUATE: This vector index has type
535 'string'.
536     9 | DEBUG EVALUATE (a=1)(b=2) VECTOR/v('abc').
537       |                                    ^~~~~
538
539 v('abc') => error
540 ])
541 done
542 AT_CLEANUP