96e42c13ea179aac7cd4b9d4005494013a8544e6
[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: 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 ])
98 AT_CLEANUP
99
100 AT_SETUP([parse expression with unknown system variable])
101 AT_KEYWORDS([expression expressions parse negative])
102 AT_DATA([parse.sps], [dnl
103 DATA LIST NOTABLE/x 1.
104 COMPUTE x=$nonexistent.
105 ])
106 AT_CHECK([pspp parse.sps], [1], [dnl
107 parse.sps:2.11-2.22: error: COMPUTE: Unknown system variable $nonexistent.
108     2 | COMPUTE x=$nonexistent.
109       |           ^~~~~~~~~~~~
110 ])
111 AT_CLEANUP
112
113 AT_SETUP([parse expression with unknown identifier])
114 AT_KEYWORDS([expression expressions parse negative])
115 AT_DATA([parse.sps], [dnl
116 DATA LIST NOTABLE/x 1.
117 COMPUTE x=y.
118 ])
119 AT_CHECK([pspp parse.sps], [1], [dnl
120 parse.sps:2.11: error: COMPUTE: Unknown identifier y.
121     2 | COMPUTE x=y.
122       |           ^
123 ])
124 AT_CLEANUP
125
126 AT_SETUP([parse expression with extension function in compatibility mode])
127 AT_KEYWORDS([expression expressions parse negative])
128 AT_DATA([parse.sps], [dnl
129 DEBUG EVALUATE/ACOS(0)*0.
130 ])
131 AT_CHECK([pspp --testing-mode --syntax=compatible parse.sps], [0], [dnl
132 parse.sps:1.16-1.22: warning: DEBUG EVALUATE: ACOS(number) is a PSPP extension.
133     1 | DEBUG EVALUATE/ACOS(0)*0.
134       |                ^~~~~~~
135
136 ACOS(0)*0 => 0.00
137 ])
138 AT_CLEANUP
139
140 AT_SETUP([LAG expression following TEMPORARY])
141 AT_KEYWORDS([expression expressions parse negative])
142 AT_DATA([parse.sps], [dnl
143 DATA LIST NOTABLE/x 1.
144 TEMPORARY
145 COMPUTE y=LAG(x).
146 ])
147 AT_CHECK([pspp parse.sps], [1], [dnl
148 parse.sps:3.11-3.16: error: COMPUTE: LAG(num_variable) may not appear after
149 TEMPORARY.
150     3 | COMPUTE y=LAG(x).
151       |           ^~~~~~
152 ])
153 AT_CLEANUP
154
155 AT_SETUP([parse expression with invalid logical expression])
156 AT_KEYWORDS([expression expressions parse negative])
157 AT_DATA([parse.sps], [dnl
158 INPUT PROGRAM.
159 LOOP c=1 to 10.
160 COMPUTE var1=NORMAL(100).
161 END CASE.
162 END LOOP.
163 END FILE.
164 END INPUT PROGRAM.
165
166 SELECT IF 2.
167 ])
168 AT_CHECK([pspp parse.sps], [1], [dnl
169 parse.sps:9.11: error: SELECT IF: This expression, which must be 0 or 1,
170 evaluated to 2.  It will be treated as 0.
171     9 | SELECT IF 2.
172       |           ^
173 ])
174 AT_CLEANUP
175
176 AT_SETUP([chaining operators that shouldn't be])
177 AT_KEYWORDS([expression expressions parse negative])
178 AT_DATA([parse.sps], [dnl
179 INPUT PROGRAM.
180 * These should provoke warnings.
181 COMPUTE a = 1 < 2 < 3.
182 COMPUTE b = 1 > 2 < 0.
183 COMPUTE c = 2**3**4.
184
185 * These should not provoke warnings.
186 COMPUTE d = (1 < 2) < 3.
187 COMPUTE e = (2**3)**4.
188 END INPUT PROGRAM.
189 ])
190 AT_CHECK([pspp parse.sps], [1], [dnl
191 parse.sps:3.13-3.21: warning: COMPUTE: Chaining relational operators (e.g. `a <
192 b < c') will not produce the mathematically expected result.  Use the AND
193 logical operator to fix the problem (e.g. `a < b AND b < c').  To disable this
194 warning, insert parentheses.
195     3 | COMPUTE a = 1 < 2 < 3.
196       |             ^~~~~~~~~
197
198 parse.sps:4.13-4.21: warning: COMPUTE: Chaining relational operators (e.g. `a <
199 b < c') will not produce the mathematically expected result.  Use the AND
200 logical operator to fix the problem (e.g. `a < b AND b < c').  To disable this
201 warning, insert parentheses.
202     4 | COMPUTE b = 1 > 2 < 0.
203       |             ^~~~~~~~~
204
205 parse.sps:5.13-5.19: warning: COMPUTE: The exponentiation operator (`**') is
206 left-associative: `a**b**c' equals `(a**b)**c', not `a**(b**c)'.  To disable
207 this warning, insert parentheses.
208     5 | COMPUTE c = 2**3**4.
209       |             ^~~~~~~
210
211 parse.sps:10: error: INPUT PROGRAM: Input program must contain DATA LIST or END
212 FILE.
213 ])
214 AT_CLEANUP
215
216 AT_SETUP([binary operator type mismatch])
217 AT_KEYWORDS([expression expressions parse negative])
218 AT_DATA([parse.sps], [dnl
219 DEBUG EVALUATE /1 + 'a'.
220 DEBUG EVALUATE /'a' + 1.
221 DEBUG EVALUATE /'a' + 'a'.
222 DEBUG EVALUATE /'a' + ('a').
223
224 DEBUG EVALUATE /1 < 'a'.
225 DEBUG EVALUATE /'a' < 1.
226 DEBUG EVALUATE /'a' < 'b' < 'c'.
227 ])
228 AT_CHECK([pspp --testing-mode parse.sps], [1], [dnl
229 parse.sps:1.17-1.23: error: DEBUG EVALUATE: Both operands of + must be numeric.
230     1 | DEBUG EVALUATE /1 + 'a'.
231       |                 ^~~~~~~
232
233 parse.sps:1.17: note: DEBUG EVALUATE: This operand has type 'number'.
234     1 | DEBUG EVALUATE /1 + 'a'.
235       |                 ^
236
237 parse.sps:1.21-1.23: note: DEBUG EVALUATE: This operand has type 'string'.
238     1 | DEBUG EVALUATE /1 + 'a'.
239       |                     ^~~
240
241 1 + 'a' => error
242
243 parse.sps:2.17-2.23: error: DEBUG EVALUATE: Both operands of + must be numeric.
244     2 | DEBUG EVALUATE /'a' + 1.
245       |                 ^~~~~~~
246
247 parse.sps:2.17-2.19: note: DEBUG EVALUATE: This operand has type 'string'.
248     2 | DEBUG EVALUATE /'a' + 1.
249       |                 ^~~
250
251 parse.sps:2.23: note: DEBUG EVALUATE: This operand has type 'number'.
252     2 | DEBUG EVALUATE /'a' + 1.
253       |                       ^
254
255 'a' + 1 => error
256
257 'a' + 'a' => "aa"
258
259 parse.sps:4.17-4.26: error: DEBUG EVALUATE: Both operands of + must be numeric.
260     4 | DEBUG EVALUATE /'a' + ('a').
261       |                 ^~~~~~~~~~
262
263 parse.sps:4.17-4.19: note: DEBUG EVALUATE: This operand has type 'string'.
264     4 | DEBUG EVALUATE /'a' + ('a').
265       |                 ^~~
266
267 parse.sps:4.24-4.26: note: DEBUG EVALUATE: This operand has type 'string'.
268     4 | DEBUG EVALUATE /'a' + ('a').
269       |                        ^~~
270
271 'a' + ('a') => error
272
273 parse.sps:6.17-6.23: error: DEBUG EVALUATE: Both operands of < must have the
274 same type.
275     6 | DEBUG EVALUATE /1 < 'a'.
276       |                 ^~~~~~~
277
278 parse.sps:6.17: note: DEBUG EVALUATE: This operand has type 'number'.
279     6 | DEBUG EVALUATE /1 < 'a'.
280       |                 ^
281
282 parse.sps:6.21-6.23: note: DEBUG EVALUATE: This operand has type 'string'.
283     6 | DEBUG EVALUATE /1 < 'a'.
284       |                     ^~~
285
286 1 < 'a' => error
287
288 parse.sps:7.17-7.23: error: DEBUG EVALUATE: Both operands of < must have the
289 same type.
290     7 | DEBUG EVALUATE /'a' < 1.
291       |                 ^~~~~~~
292
293 parse.sps:7.17-7.19: note: DEBUG EVALUATE: This operand has type 'string'.
294     7 | DEBUG EVALUATE /'a' < 1.
295       |                 ^~~
296
297 parse.sps:7.23: note: DEBUG EVALUATE: This operand has type 'number'.
298     7 | DEBUG EVALUATE /'a' < 1.
299       |                       ^
300
301 'a' < 1 => error
302
303 parse.sps:8.17-8.31: error: DEBUG EVALUATE: Both operands of < must have the
304 same type.
305     8 | DEBUG EVALUATE /'a' < 'b' < 'c'.
306       |                 ^~~~~~~~~~~~~~~
307
308 parse.sps:8.17-8.25: note: DEBUG EVALUATE: This operand has type 'number'.
309     8 | DEBUG EVALUATE /'a' < 'b' < 'c'.
310       |                 ^~~~~~~~~
311
312 parse.sps:8.29-8.31: note: DEBUG EVALUATE: This operand has type 'string'.
313     8 | DEBUG EVALUATE /'a' < 'b' < 'c'.
314       |                             ^~~
315
316 'a' < 'b' < 'c' => error
317 ])
318 AT_CLEANUP
319
320 AT_SETUP([unary operator type mismatch])
321 AT_KEYWORDS([expression expressions parse negative])
322 AT_DATA([parse.sps], [dnl
323 DEBUG EVALUATE /-'a'.
324 DEBUG EVALUATE /----'a'.
325 DEBUG EVALUATE /NOT 'a'.
326 DEBUG EVALUATE /NOT NOT NOT 'a'.
327 DEBUG EVALUATE /NOT F5.2.
328 ])
329 AT_CHECK([pspp --testing-mode parse.sps], [1], [dnl
330 parse.sps:1.17-1.20: error: DEBUG EVALUATE: The unary - operator requires a
331 numeric operand.
332     1 | DEBUG EVALUATE /-'a'.
333       |                 ^~~~
334
335 parse.sps:1.18-1.20: note: DEBUG EVALUATE: The operand of - has type 'string'.
336     1 | DEBUG EVALUATE /-'a'.
337       |                  ^~~
338
339 -'a' => error
340
341 parse.sps:2.17-2.23: error: DEBUG EVALUATE: The unary - operator requires a
342 numeric operand.
343     2 | DEBUG EVALUATE /----'a'.
344       |                 ^~~~~~~
345
346 parse.sps:2.21-2.23: note: DEBUG EVALUATE: The operand of - has type 'string'.
347     2 | DEBUG EVALUATE /----'a'.
348       |                     ^~~
349
350 ----'a' => error
351
352 parse.sps:3.17-3.23: error: DEBUG EVALUATE: The unary NOT operator requires a
353 numeric operand.
354     3 | DEBUG EVALUATE /NOT 'a'.
355       |                 ^~~~~~~
356
357 parse.sps:3.21-3.23: note: DEBUG EVALUATE: The operand of NOT has type
358 'string'.
359     3 | DEBUG EVALUATE /NOT 'a'.
360       |                     ^~~
361
362 NOT 'a' => error
363
364 parse.sps:4.17-4.31: error: DEBUG EVALUATE: The unary NOT operator requires a
365 numeric operand.
366     4 | DEBUG EVALUATE /NOT NOT NOT 'a'.
367       |                 ^~~~~~~~~~~~~~~
368
369 parse.sps:4.29-4.31: note: DEBUG EVALUATE: The operand of NOT has type
370 'string'.
371     4 | DEBUG EVALUATE /NOT NOT NOT 'a'.
372       |                             ^~~
373
374 NOT NOT NOT 'a' => error
375
376 parse.sps:5.17-5.24: error: DEBUG EVALUATE: The unary NOT operator requires a
377 numeric operand.
378     5 | DEBUG EVALUATE /NOT F5.2.
379       |                 ^~~~~~~~
380
381 parse.sps:5.21-5.24: note: DEBUG EVALUATE: The operand of NOT has type
382 'format'.
383     5 | DEBUG EVALUATE /NOT F5.2.
384       |                     ^~~~
385
386 NOT F5.2 => error
387 ])
388 AT_CLEANUP
389
390 AT_SETUP([parsing with negative numbers])
391 AT_KEYWORDS([expression expressions parse])
392 AT_DATA([parse.sps], [dnl
393 DEBUG EVALUATE NOOPT POSTFIX /-2**3.
394 DEBUG EVALUATE NOOPT POSTFIX /-2**-3**-4.
395 DEBUG EVALUATE/1 - 2.
396 ])
397 AT_CHECK([pspp --testing-mode parse.sps], [0], [dnl
398 number: n<2> number: n<3> POW NEG return_number
399
400 parse.sps:2.31-2.40: warning: DEBUG EVALUATE: The exponentiation operator
401 (`**') is left-associative: `a**b**c' equals `(a**b)**c', not `a**(b**c)'.  To
402 disable this warning, insert parentheses.
403     2 | DEBUG EVALUATE NOOPT POSTFIX /-2**-3**-4.
404       |                               ^~~~~~~~~~
405
406 number: n<2> number: n<-3> POW number: n<-4> POW NEG return_number
407
408 1 - 2 => -1.00
409 ])
410 AT_CLEANUP
411
412 AT_SETUP([system variables])
413 AT_KEYWORDS([expression expressions parse])
414 AT_DATA([parse.sps], [dnl
415 DEBUG EVALUATE /$WIDTH.
416 DEBUG EVALUATE /$LENGTH.
417 DEBUG EVALUATE /$SYSMIS.
418 ])
419 AT_CHECK([pspp --testing-mode parse.sps], [0], [dnl
420 $WIDTH => 79.00
421
422 $LENGTH => 24.00
423
424 $SYSMIS => sysmis
425 ])
426 AT_CLEANUP
427
428 # This test will fail if the current date changes during the test.
429 AT_SETUP([system variables - $DATE $DATE11 $JDATE $TIME])
430 AT_KEYWORDS([expression expressions parse])
431 # Get the date in the formats that $DATE and $DATE11 support.
432 date=$(date +%d-%^b-%y)
433 date11=$(date +%d-%^b-%Y)
434 echo "date=$date"               # Should be date=DD-MMM-YY.
435 echo "date11=$date11"   # Should be date11=DD-MMM-YYYY.
436
437 # Maybe we don't have the 'date' program or it doesn't work as we
438 # expect.  Check by trying to see if $date and $date11 are in the
439 # expected format.  If not, skip the test.
440 AS_CASE([$date],
441   [[[0-9][0-9]-[A-Z][A-Z][A-Z]-[0-9][0-9]]], [],
442   [AT_SKIP_IF([:])])
443 AS_CASE([$date11],
444   [[[0-9][0-9]-[A-Z][A-Z][A-Z]-[0-9][0-9][0-9][0-9]]], [],
445   [AT_SKIP_IF([:])])
446
447 AT_DATA([parse.sps], [dnl
448 DEBUG EVALUATE /$DATE.
449 DEBUG EVALUATE /$DATE11.
450 DEBUG EVALUATE FORMAT=DATE9 /$JDATE * 86400.
451 DEBUG EVALUATE FORMAT=DATE9 /$TIME.
452 ])
453 AT_CHECK_UNQUOTED([pspp --testing-mode parse.sps], [0], [dnl
454 \$DATE => "$date"
455
456 \$DATE11 => "$date11"
457
458 \$JDATE * 86400 => $date
459
460 \$TIME => $date
461 ])
462 AT_CLEANUP
463
464 AT_SETUP([expressions - negative checks])
465 AT_KEYWORDS([expression expressions parse])
466 AT_DATA([evaluate-base.sps], [dnl
467 SET EPOCH 1940.
468 DEBUG EVALUATE SET opt.
469 DEBUG EVALUATE /$nonexistent.
470 DEBUG EVALUATE /RANGE(1, 2).
471 DEBUG EVALUATE /CONCAT.1('a', 'b').
472 DEBUG EVALUATE /foobar(x).
473 DEBUG EVALUATE /CONCAT.1('a' b).
474 DEBUG EVALUATE /NCDF.CHISQ(1, 2, 3).
475 DEBUG EVALUATE (a=1)(b=2) VECTOR/v('abc').
476 ])
477
478 for opt in OPT NOOPT; do
479     AS_BOX([$opt])
480     sed "s/opt/$opt/" < evaluate-base.sps > evaluate.sps
481     AT_CHECK([pspp --testing-mode evaluate.sps], [1], [dnl
482 evaluate.sps:3.17-3.28: error: DEBUG EVALUATE: Unknown system variable
483 $nonexistent.
484     3 | DEBUG EVALUATE /$nonexistent.
485       |                 ^~~~~~~~~~~~
486
487 $nonexistent => error
488
489 evaluate.sps:4.17-4.27: error: DEBUG EVALUATE: RANGE(number, number, number[[,
490 number, number]]...) must have an odd number of arguments.
491     4 | DEBUG EVALUATE /RANGE(1, 2).
492       |                 ^~~~~~~~~~~
493
494 RANGE(1, 2) => error
495
496 evaluate.sps:5.17-5.34: error: DEBUG EVALUATE: CONCAT(string[[, string]]...)
497 function cannot accept suffix .1 to specify the minimum number of valid
498 arguments.
499     5 | DEBUG EVALUATE /CONCAT.1('a', 'b').
500       |                 ^~~~~~~~~~~~~~~~~~
501
502 CONCAT.1('a', 'b') => error
503
504 evaluate.sps:6.17-6.22: error: DEBUG EVALUATE: No function or vector named
505 foobar.
506     6 | DEBUG EVALUATE /foobar(x).
507       |                 ^~~~~~
508
509 foobar(x) => error
510
511 evaluate.sps:7.30: error: DEBUG EVALUATE: Syntax error expecting `,' or `@:}@'.
512     7 | DEBUG EVALUATE /CONCAT.1('a' b).
513       |                              ^
514
515 CONCAT.1('a' b) => error
516
517 evaluate.sps:8.17-8.35: error: DEBUG EVALUATE: NCDF.CHISQ(number, number,
518 number) is not available in this version of PSPP.
519     8 | DEBUG EVALUATE /NCDF.CHISQ(1, 2, 3).
520       |                 ^~~~~~~~~~~~~~~~~~~
521
522 NCDF.CHISQ(1, 2, 3) => error
523
524 evaluate.sps:9.34-9.41: error: DEBUG EVALUATE: A vector index must be numeric.
525     9 | DEBUG EVALUATE (a=1)(b=2) VECTOR/v('abc').
526       |                                  ^~~~~~~~
527
528 evaluate.sps:9.36-9.40: note: DEBUG EVALUATE: This vector index has type
529 'string'.
530     9 | DEBUG EVALUATE (a=1)(b=2) VECTOR/v('abc').
531       |                                    ^~~~~
532
533 v('abc') => error
534 ])
535 done
536 AT_CLEANUP