!LET
[pspp] / tests / language / control / define.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 nGeneral 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([DEFINE])
18
19 m4_define([PSPP_CHECK_MACRO_EXPANSION],
20   [AT_SETUP([macro expansion - $1])
21    AT_KEYWORDS([m4_bpatsubst([$1], [!], [])])
22    AT_DATA([define.sps], [$2
23 DEBUG EXPAND.
24 $3
25 ])
26    AT_CAPTURE_FILE([define.sps])
27    AT_DATA([expout], [$4
28 ])
29    AT_CHECK([pspp --testing-mode define.sps | sed '/^$/d'], [$6], [expout])
30    AT_CLEANUP])
31
32 AT_SETUP([simple macro expansion])
33 AT_DATA([define.sps], [dnl
34 DEFINE !macro()
35 a b c d
36 e f g h.
37 i j k l
38 1,2,3,4.
39 5+6+7.
40 m(n,o).
41 "a" "b" "c" 'a' 'b' 'c'.
42 "x "" y".
43 !ENDDEFINE.
44 DEBUG EXPAND.
45 !macro
46 ])
47 AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
48 a b c d e f g h.
49 i j k l 1, 2, 3, 4.
50 5 + 6 + 7.
51 m(n, o).
52 "a" "b" "c" 'a' 'b' 'c'.
53 "x "" y".
54 ])
55 AT_CLEANUP
56
57 PSPP_CHECK_MACRO_EXPANSION([one !TOKENS(1) positional argument],
58   [DEFINE !t1(!positional !tokens(1)) t1 (!1) !ENDDEFINE.],
59   [!t1 a.
60 !t1 b.
61 !t1 a b.],
62   [t1(a)
63 t1(b)
64 t1(a)
65 note: unexpanded token "b"])
66
67 AT_SETUP([macro expansion with positional arguments])
68 AT_DATA([define.sps], [dnl
69 DEFINE !title(!positional !tokens(1)) !1 !ENDDEFINE.
70 DEFINE !t1(!positional !tokens(1)) t1 (!1) !ENDDEFINE.
71 DEFINE !t2(!positional !tokens(2)) t2 (!1) !ENDDEFINE.
72
73 DEFINE !ce(!positional !charend('/')) ce (!1) !ENDDEFINE.
74 DEFINE !ce2(!positional !charend('(')
75            /!positional !charend(')'))
76 ce2 (!1, !2)
77 !ENDDEFINE.
78
79 DEFINE !e(!positional !enclose('{','}')) e (!1) !ENDDEFINE.
80
81 DEFINE !cmd(!positional !cmdend) cmd(!1) !ENDDEFINE.
82 DEFINE !cmd2(!positional !cmdend
83             /!positional !tokens(1))
84 cmd2(!1, !2)
85 !ENDDEFINE.
86
87 DEFINE !p(!positional !tokens(1)
88          /!positional !tokens(1)
89          /!positional !tokens(1))
90 p(!1, !2, !3)(!*)
91 !ENDDEFINE.
92
93 DEBUG EXPAND.
94 !title "!TOKENS(1) argument."
95 !t1 a.
96 !t1 b.
97 !t1 a b.
98
99 !title "!TOKENS(2) argument."
100 !t2 a b.
101 !t2 b c d.
102
103 !title "!CHAREND argument."
104 !ce/.
105 !ce x/.
106 !ce x y/.
107 !ce x y z/.
108
109 !title "Two !CHAREND arguments."
110 !ce2 x(y).
111 !ce2 1 2 3 4().
112
113 !title "!ENCLOSE argument."
114 !e {}.
115 !e {a}.
116 !e {a b}.
117
118 !title "!CMDEND argument."
119 !cmd 1 2 3 4.
120 !cmd2 5 6.
121 7.
122
123 !title "Three !TOKENS(1) arguments."
124 !p a b c.
125 !p 1 -2 -3.
126 ])
127 AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
128 "!TOKENS(1) argument."
129
130 t1(a)
131
132 t1(b)
133
134 t1(a)
135
136 note: unexpanded token "b"
137
138 "!TOKENS(2) argument."
139
140 t2(a b)
141
142 t2(b c)
143
144 note: unexpanded token "d"
145
146 "!CHAREND argument."
147
148 ce( )
149
150 ce(x)
151
152 ce(x y)
153
154 ce(x y z)
155
156 "Two !CHAREND arguments."
157
158 ce2(x, y)
159
160 ce2(1 2 3 4, )
161
162 "!ENCLOSE argument."
163
164 e( )
165
166 e(a)
167
168 e(a b)
169
170 "!CMDEND argument."
171
172 cmd(1 2 3 4)
173
174 cmd2(5 6, 7)
175
176 "Three !TOKENS(1) arguments."
177
178 p(a, b, c) (a b c)
179
180 p(1, -2, -3) (1 -2 -3)
181 ])
182 AT_CLEANUP
183
184 AT_SETUP([macro expansion with positional arguments - negative])
185 AT_DATA([define.sps], [dnl
186 DEFINE !title(!positional !tokens(1)) !1 !ENDDEFINE.
187 DEFINE !p(!positional !tokens(1)
188          /!positional !tokens(1)
189          /!positional !tokens(1))
190 (!1, !2, !3)
191 !ENDDEFINE.
192
193 DEFINE !ce(!positional !charend('/')) ce(!1) !ENDDEFINE.
194
195 DEFINE !enc1(!positional !enclose('{', '}')) enc1(!1) !ENDDEFINE.
196 DEBUG EXPAND.
197 !title "Too few tokens for !TOKENS."
198 !p a b.
199 !p a.
200 !p.
201
202 !title "Missing charend delimiter."
203 !ce a b c.
204
205 !title "Missing start delimiter."
206 !enc1 a b c.
207
208 !title "Missing end delimiter."
209 !enc1{a b c.
210 ])
211 AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
212 "Too few tokens for !TOKENS."
213
214 define.sps:13: error: DEBUG EXPAND: Unexpected end of command reading
215 argument !3 to macro !p.
216
217 note: unexpanded token "!p"
218
219 note: unexpanded token "a"
220
221 note: unexpanded token "b"
222
223 define.sps:14: error: DEBUG EXPAND: Unexpected end of command reading
224 argument !2 to macro !p.
225
226 note: unexpanded token "!p"
227
228 note: unexpanded token "a"
229
230 define.sps:15: error: DEBUG EXPAND: Unexpected end of command reading
231 argument !1 to macro !p.
232
233 note: unexpanded token "!p"
234
235 "Missing charend delimiter."
236
237 define.sps:18: error: DEBUG EXPAND: Unexpected end of command reading
238 argument !1 to macro !ce.
239
240 note: unexpanded token "!ce"
241
242 note: unexpanded token "a"
243
244 note: unexpanded token "b"
245
246 note: unexpanded token "c"
247
248 "Missing start delimiter."
249
250 define.sps:21: error: DEBUG EXPAND: Found `a' while expecting `{' reading
251 argument !1 to macro !enc1.
252
253 note: unexpanded token "!enc1"
254
255 note: unexpanded token "a"
256
257 note: unexpanded token "b"
258
259 note: unexpanded token "c"
260
261 "Missing end delimiter."
262
263 define.sps:24: error: DEBUG EXPAND: Unexpected end of command reading
264 argument !1 to macro !enc1.
265
266 note: unexpanded token "!enc1"
267
268 note: unexpanded token "{"
269
270 note: unexpanded token "a"
271
272 note: unexpanded token "b"
273
274 note: unexpanded token "c"
275 ])
276 AT_CLEANUP
277
278 PSPP_CHECK_MACRO_EXPANSION([one !TOKENS(1) keyword argument],
279   [DEFINE !k(arg1 = !TOKENS(1)) k(!arg1) !ENDDEFINE.],
280   [!k arg1=x.
281 !k arg1=x y.
282 !k.],
283   [k(x)
284 k(x)
285 note: unexpanded token "y"
286 k( )])
287
288 PSPP_CHECK_MACRO_EXPANSION([one !TOKENS(1) keyword argument - negative],
289   [DEFINE !k(arg1 = !TOKENS(1)) k(!arg1) !ENDDEFINE.],
290   [!k arg1.
291 !k arg1=.], [dnl
292 define.sps:3: error: DEBUG EXPAND: Found `.' while expecting `=' reading
293 argument !arg1 to macro !k.
294 note: unexpanded token "!k"
295 note: unexpanded token "arg1"
296 define.sps:4: error: DEBUG EXPAND: Unexpected end of command reading argument !
297 arg1 to macro !k.
298 note: unexpanded token "!k"
299 note: unexpanded token "arg1"
300 note: unexpanded token "="], [1])
301
302 PSPP_CHECK_MACRO_EXPANSION([!CHAREND('/') keyword arguments], [dnl
303 DEFINE !k(arg1 = !CHAREND('/')
304          /arg2 = !CHAREND('/'))
305 k(!arg1, !arg2)
306 !ENDDEFINE.],
307   [!k arg1=x/ arg2=y/.
308 !k arg1=x/.
309 !k arg2=y/.
310 !k.],
311   [k(x, y)
312 k(x, )
313 k(, y)
314 k(, )])
315
316 PSPP_CHECK_MACRO_EXPANSION([!CHAREND('/') keyword arguments - negative], [dnl
317 DEFINE !k(arg1 = !CHAREND('/')
318          /arg2 = !CHAREND('/'))
319 k(!arg1, !arg2)
320 !ENDDEFINE.],
321   [!k arg1.
322 !k arg1=.
323 !k arg1=x.
324 !k arg1=x/ arg2=y.],
325   [define.sps:6: error: DEBUG EXPAND: Found `.' while expecting `=' reading
326 argument !arg1 to macro !k.
327 note: unexpanded token "!k"
328 note: unexpanded token "arg1"
329 define.sps:7: error: DEBUG EXPAND: Unexpected end of command reading argument !
330 arg1 to macro !k.
331 note: unexpanded token "!k"
332 note: unexpanded token "arg1"
333 note: unexpanded token "="
334 define.sps:8: error: DEBUG EXPAND: Unexpected end of command reading argument !
335 arg1 to macro !k.
336 note: unexpanded token "!k"
337 note: unexpanded token "arg1"
338 note: unexpanded token "="
339 note: unexpanded token "x"
340 define.sps:9: error: DEBUG EXPAND: Unexpected end of command reading argument !
341 arg2 to macro !k.
342 note: unexpanded token "!k"
343 note: unexpanded token "arg1"
344 note: unexpanded token "="
345 note: unexpanded token "x"
346 note: unexpanded token "/"
347 note: unexpanded token "arg2"
348 note: unexpanded token "="
349 note: unexpanded token "y"])
350
351 PSPP_CHECK_MACRO_EXPANSION([default keyword arguments],
352   [DEFINE !k(arg1 = !DEFAULT(a b c) !CMDEND) k(!arg1) !ENDDEFINE],
353   [!k arg1=x.
354 !k],
355   [k(x)
356 k(a b c)])
357
358 dnl Keep this test in sync with the examples for !BLANKS in the manual.
359 PSPP_CHECK_MACRO_EXPANSION([!BLANKS],
360   [DEFINE !b()
361 !BLANKS(0).
362 !QUOTE(!BLANKS(0)).
363 !BLANKS(1).
364 !QUOTE(!BLANKS(1)).
365 !BLANKS(2).
366 !QUOTE(!BLANKS(2)).
367 !BLANKS(5).
368 !QUOTE(!BLANKS(5)).
369 !ENDDEFINE],
370   [!b.],
371   [.
372 ''.
373 .
374 ' '.
375 .
376 '  '.
377 .
378 '     '.])
379
380 dnl Keep this test in sync with the examples for !CONCAT in the manual.
381 PSPP_CHECK_MACRO_EXPANSION([!CONCAT],
382   [DEFINE !c()
383 !CONCAT(x, y).
384 !CONCAT('x', 'y').
385 !CONCAT(12, 34).
386 !CONCAT(!NULL, 123).
387 !CONCAT(x, 0).
388 !CONCAT(x, 0, y).
389 !CONCAT(0, x).
390 !CONCAT(0, x, y).
391 !ENDDEFINE],
392   [!c.],
393   [xy.
394 xy.
395 1234.
396 123.
397 x0.
398 x0y.
399 0 x.
400 0 xy.])
401
402 dnl Keep this test in sync with the examples for !EVAL in the manual.
403 PSPP_CHECK_MACRO_EXPANSION([!EVAL],
404   [DEFINE !vars() a b c !ENDDEFINE.
405 DEFINE !e()
406 !vars.
407 !QUOTE(!vars).
408 !EVAL(!vars).
409 !QUOTE(!EVAL(!vars)).
410 !ENDDEFINE
411 DEFINE !e2(!positional !enclose('(',')'))
412 !1.
413 !QUOTE(!1).
414 !EVAL(!1).
415 !QUOTE(!EVAL(!1)).
416 !ENDDEFINE],
417   [!e.
418 !e2(!vars)],
419   [a b c.
420 '!vars'.
421 a b c.
422 'a b c'.
423 a b c.
424 '!vars'.
425 a b c.
426 'a b c'.])
427
428 dnl Keep this test in sync with the examples for !HEAD in the manual.
429 PSPP_CHECK_MACRO_EXPANSION([!HEAD],
430   [DEFINE !h()
431 !HEAD('a b c').
432 !HEAD('a').
433 !HEAD(!NULL).
434 !HEAD('').
435 !ENDDEFINE],
436   [!h.],
437   [a.
438 a.
439 .
440 .])
441
442 dnl Keep this test in sync with the examples for !TAIL in the manual.
443 PSPP_CHECK_MACRO_EXPANSION([!TAIL],
444   [DEFINE !t()
445 !TAIL('a b c').
446 !TAIL('a').
447 !TAIL(!NULL).
448 !TAIL('').
449 !ENDDEFINE],
450   [!t.],
451   [b c.
452 .
453 .
454 .])
455
456 dnl Keep this test in sync with the examples for !INDEX in the manual.
457 PSPP_CHECK_MACRO_EXPANSION([!INDEX],
458   [DEFINE !i()
459 !INDEX(banana, an).
460 !INDEX(banana, nan).
461 !INDEX(banana, apple).
462 !INDEX("banana", nan).
463 !INDEX("banana", "nan").
464 !INDEX(!UNQUOTE("banana"), !UNQUOTE("nan")).
465 !ENDDEFINE],
466   [!i.],
467   [2.
468 3.
469 0.
470 4.
471 0.
472 3.])
473
474 dnl Keep this test in sync with the examples for !LENGTH in the manual.
475 PSPP_CHECK_MACRO_EXPANSION([!LENGTH],
476   [DEFINE !l()
477 !LENGTH(123).
478 !LENGTH(123.00).
479 !LENGTH( 123 ).
480 !LENGTH("123").
481 !LENGTH(xyzzy).
482 !LENGTH("xyzzy").
483 !LENGTH("xy""zzy").
484 !LENGTH(!UNQUOTE("xyzzy")).
485 !LENGTH(!UNQUOTE("xy""zzy")).
486 !LENGTH(!NULL).
487 !ENDDEFINE.
488 DEFINE !la(!positional !enclose('(',')'))
489 !LENGTH(!1).
490 !ENDDEFINE.],
491   [!l.
492 !la(a b c).
493 !la().],
494   [3.
495 6.
496 3.
497 5.
498 5.
499 7.
500 9.
501 5.
502 6.
503 0.
504 5.
505 0.])
506
507 dnl Keep this test in sync with the examples for !SUBSTR in the manual.
508 PSPP_CHECK_MACRO_EXPANSION([!SUBSTR],
509   [DEFINE !s()
510 !SUBSTR(banana, 3).
511 !SUBSTR(banana, 3, 3).
512 !SUBSTR("banana", 3).
513 !SUBSTR(!UNQUOTE("banana"), 3).
514 !SUBSTR("banana", 3, 3).
515 !SUBSTR(banana, 3, 0).
516 !SUBSTR(banana, 3, 10).
517 !SUBSTR(banana, 10, 3).
518 !ENDDEFINE.],
519   [!s.],
520   [error
521 nana.
522 nan.
523 anana.
524 nana.
525 ana.
526 .
527 nana.
528 .])
529
530 dnl Keep this test in sync with the examples for !UPCASE in the manual.
531 PSPP_CHECK_MACRO_EXPANSION([!UPCASE],
532   [DEFINE !u()
533 !UPCASE(freckle).
534 !UPCASE('freckle').
535 !UPCASE('a b c').
536 !UPCASE('A B C').
537 !ENDDEFINE.],
538   [!u.],
539   [FRECKLE.
540 FRECKLE.
541 A B C.
542 A B C.])
543
544
545 dnl !* is implemented separately inside and outside function arguments
546 dnl so this test makes sure to include both.
547 PSPP_CHECK_MACRO_EXPANSION([!*], [dnl
548 DEFINE !m(!POSITIONAL !TOKENS(1)
549          /!POSITIONAL !TOKENS(1))
550 !*/
551 !LENGTH(!*)/
552 !SUBSTR(!*, 3)/
553 !QUOTE(!*).
554 !ENDDEFINE.],
555   [!m 123 b
556 !m 2 3
557 !m '' 'b'.
558 ], [123 b / 5 / 3 b / '123 b'.
559 2 3 / 3 / 3 / '2 3'.
560 '' 'b' / 6 / 'b' / ''''' ''b'''.])
561
562 AT_SETUP([macro maximum nesting level (MNEST)])
563 AT_KEYWORDS([MNEST])
564 AT_DATA([define.sps], [dnl
565 DEFINE !macro()
566 !macro
567 !ENDDEFINE.
568 !macro.
569 ])
570 AT_CHECK([pspp define.sps], [1], [dnl
571 maximum nesting level exceeded
572 define.sps.1: error: Syntax error at `!macro': expecting command name.
573 ])
574 AT_CLEANUP
575
576 AT_SETUP([macro !IF condition])
577 AT_KEYWORDS([if])
578 for operators in \
579     '!eq !ne !lt !gt !le !ge' \
580     '  =  <>   <   >  <=  >='
581 do
582     set $operators
583     AS_BOX([$operators])
584     cat > define.sps <<EOF
585 DEFINE !test(!positional !tokens(1))
586 !if (!1 $1 1) !then true !else false !ifend
587 !if (!1 $2 1) !then true !else false !ifend
588 !if (!1 $3 1) !then true !else false !ifend
589 !if (!1 $4 1) !then true !else false !ifend
590 !if (!1 $5 1) !then true !else false !ifend
591 !if (!1 $6 1) !then true !else false !ifend.
592 !ENDDEFINE.
593 DEBUG EXPAND.
594 !test 0
595 !test 1
596 !test 2
597 !test '1'
598 !test 1.0
599 EOF
600     AT_CAPTURE_FILE([define.sps])
601     AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
602 false true true false true false.
603
604 true false false false true true.
605
606 false true false true false true.
607
608 true false false false true true.
609
610 false true false true false true.
611 ])
612 done
613 AT_CLEANUP
614
615 AT_SETUP([macro !IF condition -- case sensitivity])
616 AT_KEYWORDS([if])
617 for operators in \
618     '!eq !ne !lt !gt !le !ge' \
619     '  =  <>   <   >  <=  >='
620 do
621     set $operators
622     AS_BOX([$operators])
623     cat > define.sps <<EOF
624 DEFINE !test(!positional !tokens(1))
625 !if (!1 $1 a) !then true !else false !ifend
626 !if (!1 $1 A) !then true !else false !ifend
627 !if (!1 $2 a) !then true !else false !ifend
628 !if (!1 $2 A) !then true !else false !ifend
629 !if (!1 $3 a) !then true !else false !ifend
630 !if (!1 $3 A) !then true !else false !ifend
631 !if (!1 $4 a) !then true !else false !ifend
632 !if (!1 $4 A) !then true !else false !ifend
633 !if (!1 $5 a) !then true !else false !ifend
634 !if (!1 $5 A) !then true !else false !ifend
635 !if (!1 $6 a) !then true !else false !ifend
636 !if (!1 $6 A) !then true !else false !ifend
637 !if (!1 $1 !null) !then true !else false !ifend
638 !if (!1 $2 !null) !then true !else false !ifend.
639 !ENDDEFINE.
640 DEBUG EXPAND.
641 !test a
642 !test A
643 !test b
644 !test B
645 EOF
646     AT_CAPTURE_FILE([define.sps])
647     AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
648 true false false true false false false true true false true true false true.
649
650 false true true false true false false false true true false true false true.
651
652 false false true true false false true true false false true true false true.
653
654 false false true true true false false true true false false true false true.
655 ])
656 done
657 AT_CLEANUP
658
659 AT_SETUP([macro !IF condition -- logical operators])
660 AT_KEYWORDS([if])
661 for operators in \
662     '!and !or !not' \
663     '   &   |    ~'
664 do
665     set $operators
666     AS_BOX([$operators])
667     cat > define.sps <<EOF
668 DEFINE !test_binary(!positional !tokens(1)/!positional !tokens(1))
669 !if !1 $1 !2 !then true !else false !ifend
670 !if !1 $2 !2 !then true !else false !ifend.
671 !ENDDEFINE.
672
673 DEFINE !test_unary(!positional !tokens(1))
674 !if $3 !1 !then true !else false !ifend.
675 !ENDDEFINE.
676
677 * These are:
678   ((not A) and B) or C
679   not (A and B) or C
680   not A and (B or C)
681 DEFINE !test_prec(!pos !tokens(1)/!pos !tokens(1)/!pos !tokens(1))
682 !if $3 !1 $1 !2 $2 !3 !then true !else false !ifend
683 !if $3 (!1 $1 !2) $2 !3 !then true !else false !ifend
684 !if $3 !1 $1 (!2 $2 !3) !then true !else false !ifend
685 !ENDDEFINE.
686
687 DEBUG EXPAND.
688 !test_binary 0 0
689 !test_binary 0 1
690 !test_binary 1 0
691 !test_binary 1 1
692 !test_unary 0
693 !test_unary 1
694 !test_prec 0 0 0 !test_prec 0 0 1 !test_prec 0 1 0 !test_prec 0 1 1.
695 !test_prec 1 0 0 !test_prec 1 0 1 !test_prec 1 1 0 !test_prec 1 1 1.
696 EOF
697     AT_CAPTURE_FILE([define.sps])
698     AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
699 false false.
700
701 false true.
702
703 false true.
704
705 true true.
706
707 true.
708
709 false.
710
711 false true false
712 true true true
713 true true true
714 true true true
715
716 false true false
717 true true false
718 false false false
719 true true false
720 ])
721 done
722 AT_CLEANUP
723
724 AT_SETUP([macro !LET])
725 AT_KEYWORDS([let])
726 AT_DATA([define.sps], [dnl
727 DEFINE !macro(!POS !CMDEND)
728 !LET !v1 = !CONCAT('x',!1,'y')
729 !LET !v2 = !QUOTE(!v1)
730 !LET !v3 = (!LENGTH(!1) = 1)
731 !LET !v4 = (!SUBSTR(!1, 3) = !NULL)
732 v1=!v1.
733 v2=!v2.
734 v3=!v3.
735 v4=!v4.
736 !ENDDEFINE.
737 DEBUG EXPAND.
738 !macro 0.
739 !macro.
740 !macro xyzzy.
741 ])
742 AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
743 v1 = x0y.
744 v2 = 'x0y'.
745 v3 = 1.
746 v4 = 1.
747
748 v1 = xy.
749 v2 = 'xy'.
750 v3 = 0.
751 v4 = 1.
752
753 v1 = xxyzzyy.
754 v2 = 'xxyzzyy'.
755 v3 = 0.
756 v4 = 0.
757 ])
758 AT_CLEANUP