dnl PSPP - a program for statistical analysis. dnl Copyright (C) 2017 Free Software Foundation, Inc. dnl dnl This program is free software: you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation, either version 3 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU nGeneral Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see . dnl AT_BANNER([DEFINE]) AT_SETUP([simple macro expansion]) AT_DATA([define.sps], [dnl DEFINE !macro() a b c d e f g h. i j k l 1,2,3,4. 5+6+7. m(n,o). "a" "b" "c" 'a' 'b' 'c'. "x "" y". !ENDDEFINE. DEBUG EXPAND. !macro ]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl a b c d e f g h. i j k l 1, 2, 3, 4. 5 + 6 + 7. m(n, o). "a" "b" "c" 'a' 'b' 'c'. "x "" y". ]) AT_CLEANUP AT_SETUP([macro expansion - one !TOKENS(1) positional argument]) AT_KEYWORDS([TOKENS]) AT_DATA([define.sps], [dnl DEFINE !t1(!positional !tokens(1)) t1 (!1) !ENDDEFINE. DEBUG EXPAND. !t1 a. !t1 b. !t1 a b. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl t1(a) t1(b) t1(a) note: unexpanded token "b" ]) AT_CLEANUP AT_SETUP([macro expansion with positional arguments]) AT_DATA([define.sps], [dnl DEFINE !title(!positional !tokens(1)) !1 !ENDDEFINE. DEFINE !t1(!positional !tokens(1)) t1 (!1) !ENDDEFINE. DEFINE !t2(!positional !tokens(2)) t2 (!1) !ENDDEFINE. DEFINE !ce(!positional !charend('/')) ce (!1) !ENDDEFINE. DEFINE !ce2(!positional !charend('(') /!positional !charend(')')) ce2 (!1, !2) !ENDDEFINE. DEFINE !e(!positional !enclose('{','}')) e (!1) !ENDDEFINE. DEFINE !cmd(!positional !cmdend) cmd(!1) !ENDDEFINE. DEFINE !cmd2(!positional !cmdend /!positional !tokens(1)) cmd2(!1, !2) !ENDDEFINE. DEFINE !p(!positional !tokens(1) /!positional !tokens(1) /!positional !tokens(1)) p(!1, !2, !3)(!*) !ENDDEFINE. DEBUG EXPAND. !title "!TOKENS(1) argument." !t1 a. !t1 b. !t1 a b. !title "!TOKENS(2) argument." !t2 a b. !t2 b c d. !title "!CHAREND argument." !ce/. !ce x/. !ce x y/. !ce x y z/. !title "Two !CHAREND arguments." !ce2 x(y). !ce2 1 2 3 4(). !title "!ENCLOSE argument." !e {}. !e {a}. !e {a b}. !title "!CMDEND argument." !cmd 1 2 3 4. !cmd2 5 6. 7. !title "Three !TOKENS(1) arguments." !p a b c. !p 1 -2 -3. ]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl "!TOKENS(1) argument." t1(a) t1(b) t1(a) note: unexpanded token "b" "!TOKENS(2) argument." t2(a b) t2(b c) note: unexpanded token "d" "!CHAREND argument." ce( ) ce(x) ce(x y) ce(x y z) "Two !CHAREND arguments." ce2(x, y) ce2(1 2 3 4, ) "!ENCLOSE argument." e( ) e(a) e(a b) "!CMDEND argument." cmd(1 2 3 4) cmd2(5 6, 7) "Three !TOKENS(1) arguments." p(a, b, c) (a b c) p(1, -2, -3) (1 -2 -3) ]) AT_CLEANUP AT_SETUP([macro expansion with positional arguments - negative]) AT_DATA([define.sps], [dnl DEFINE !title(!positional !tokens(1)) !1 !ENDDEFINE. DEFINE !p(!positional !tokens(1) /!positional !tokens(1) /!positional !tokens(1)) (!1, !2, !3) !ENDDEFINE. DEFINE !ce(!positional !charend('/')) ce(!1) !ENDDEFINE. DEFINE !enc1(!positional !enclose('{', '}')) enc1(!1) !ENDDEFINE. DEBUG EXPAND. !title "Too few tokens for !TOKENS." !p a b. !p a. !p. !title "Missing charend delimiter." !ce a b c. !title "Missing start delimiter." !enc1 a b c. !title "Missing end delimiter." !enc1{a b c. ]) AT_CHECK([pspp --testing-mode define.sps], [1], [dnl "Too few tokens for !TOKENS." define.sps:13.7: error: DEBUG EXPAND: Unexpected end of command reading argument !3 to macro !p. note: unexpanded token "!p" note: unexpanded token "a" note: unexpanded token "b" define.sps:14.5: error: DEBUG EXPAND: Unexpected end of command reading argument !2 to macro !p. note: unexpanded token "!p" note: unexpanded token "a" define.sps:15.3: error: DEBUG EXPAND: Unexpected end of command reading argument !1 to macro !p. note: unexpanded token "!p" "Missing charend delimiter." define.sps:18.10: error: DEBUG EXPAND: Unexpected end of command reading argument !1 to macro !ce. note: unexpanded token "!ce" note: unexpanded token "a" note: unexpanded token "b" note: unexpanded token "c" "Missing start delimiter." define.sps:21.7: error: DEBUG EXPAND: Found `a' while expecting `{' reading argument !1 to macro !enc1. note: unexpanded token "!enc1" note: unexpanded token "a" note: unexpanded token "b" note: unexpanded token "c" "Missing end delimiter." define.sps:24.12: error: DEBUG EXPAND: Unexpected end of command reading argument !1 to macro !enc1. note: unexpanded token "!enc1" note: unexpanded token "{" note: unexpanded token "a" note: unexpanded token "b" note: unexpanded token "c" ]) AT_CLEANUP AT_SETUP([keyword macro argument name with ! prefix]) AT_DATA([define.sps], [dnl DEFINE !macro(!x=!TOKENS(1). ]) AT_CHECK([pspp -O format=csv define.sps], [1], [dnl "define.sps:1.15-1.16: error: DEFINE: Syntax error at `!x': Keyword macro parameter must be named in definition without ""!"" prefix." ]) AT_CLEANUP AT_SETUP([reserved macro keyword argument name]) AT_DATA([define.sps], [dnl DEFINE !macro(if=!TOKENS(1). ]) AT_CHECK([pspp -O format=csv define.sps], [1], [dnl "define.sps:1.15-1.16: error: DEFINE: Syntax error at `if': Cannot use macro keyword ""if"" as an argument name." ]) AT_CLEANUP AT_SETUP([macro expansion - one !TOKENS(1) keyword argument]) AT_KEYWORDS([TOKENS]) AT_DATA([define.sps], [dnl DEFINE !k(arg1 = !TOKENS(1)) k(!arg1) !ENDDEFINE. DEBUG EXPAND. !k arg1=x. !k arg1=x y. !k. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl k(x) k(x) note: unexpanded token "y" k( ) ]) AT_CLEANUP AT_SETUP([macro expansion - one !TOKENS(1) keyword argument - negative]) AT_KEYWORDS([TOKENS]) AT_DATA([define.sps], [dnl DEFINE !k(arg1 = !TOKENS(1)) k(!arg1) !ENDDEFINE. DEBUG EXPAND. !k arg1. !k arg1=. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:3.8: error: DEBUG EXPAND: Found `.' while expecting `=' reading argument !arg1 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" define.sps:4.9: error: DEBUG EXPAND: Unexpected end of command reading argument !arg1 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" note: unexpanded token "=" ]) AT_CLEANUP AT_SETUP([macro expansion - !CHAREND('/') keyword arguments]) AT_KEYWORDS([CHAREND]) AT_DATA([define.sps], [dnl DEFINE !k(arg1 = !CHAREND('/') /arg2 = !CHAREND('/')) k(!arg1, !arg2) !ENDDEFINE. DEBUG EXPAND. !k arg1=x/ arg2=y/. !k arg1=x/. !k arg2=y/. !k. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl k(x, y) k(x, ) k(, y) k(, ) ]) AT_CLEANUP AT_SETUP([macro expansion - !CHAREND('/') keyword arguments - negative]) AT_KEYWORDS([CHAREND]) AT_DATA([define.sps], [dnl DEFINE !k(arg1 = !CHAREND('/') /arg2 = !CHAREND('/')) k(!arg1, !arg2) !ENDDEFINE. DEBUG EXPAND. !k arg1. !k arg1=. !k arg1=x. !k arg1=x/ arg2=y. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:6.8: error: DEBUG EXPAND: Found `.' while expecting `=' reading argument !arg1 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" define.sps:7.9: error: DEBUG EXPAND: Unexpected end of command reading argument !arg1 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" note: unexpanded token "=" define.sps:8.10: error: DEBUG EXPAND: Unexpected end of command reading argument !arg1 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" note: unexpanded token "=" note: unexpanded token "x" define.sps:9.18: error: DEBUG EXPAND: Unexpected end of command reading argument !arg2 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" note: unexpanded token "=" note: unexpanded token "x" note: unexpanded token "/" note: unexpanded token "arg2" note: unexpanded token "=" note: unexpanded token "y" ]) AT_CLEANUP dnl Keep this test in sync with the examples for !BLANKS in the manual. AT_SETUP([macro expansion - !BLANKS]) AT_KEYWORDS([BLANKS]) AT_DATA([define.sps], [dnl DEFINE !b() !BLANKS(0). !QUOTE(!BLANKS(0)). !BLANKS(1). !QUOTE(!BLANKS(1)). !BLANKS(2). !QUOTE(!BLANKS(2)). !BLANKS(5). !QUOTE(!BLANKS(5)). !ENDDEFINE. DEBUG EXPAND. !b. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl . ''. . ' '. . ' '. . ' '. ]) AT_CLEANUP dnl Keep this test in sync with the examples for !CONCAT in the manual. AT_SETUP([macro expansion - !CONCAT]) AT_KEYWORDS([CONCAT]) AT_DATA([define.sps], [dnl DEFINE !c() !CONCAT(x, y). !CONCAT('x', 'y'). !CONCAT(12, 34). !CONCAT(!NULL, 123). !CONCAT(x, 0). !CONCAT(x, 0, y). !CONCAT(0, x). !CONCAT(0, x, y). !ENDDEFINE. DEBUG EXPAND. !c ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl xy. xy. 1234. 123. x0. x0y. 0 x. 0 xy. ]) AT_CLEANUP dnl Keep this test in sync with the examples for !EVAL in the manual. AT_SETUP([macro expansion - !EVAL]) AT_KEYWORDS([EVAL]) AT_DATA([define.sps], [dnl DEFINE !vars() a b c !ENDDEFINE. DEFINE !e() !vars. !QUOTE(!vars). !EVAL(!vars). !QUOTE(!EVAL(!vars)). !ENDDEFINE DEFINE !e2(!positional !enclose('(',')')) !1. !QUOTE(!1). !EVAL(!1). !QUOTE(!EVAL(!1)). !ENDDEFINE. DEBUG EXPAND. !e. !e2(!vars). ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl a b c. '!vars'. a b c. 'a b c'. a b c. '!vars'. a b c. 'a b c'. ]) AT_CLEANUP dnl Keep this test in sync with the examples for !HEAD in the manual. AT_SETUP([macro expansion - !HEAD]) AT_KEYWORDS([HEAD]) AT_DATA([define.sps], [dnl DEFINE !h() !HEAD('a b c'). !HEAD('a'). !HEAD(!NULL). !HEAD(''). !ENDDEFINE. DEBUG EXPAND. !h. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl a. a. . . ]) AT_CLEANUP dnl Keep this test in sync with the examples for !TAIL in the manual. AT_SETUP([macro expansion - !TAIL]) AT_KEYWORDS([TAIL]) AT_DATA([define.sps], [dnl DEFINE !t() !TAIL('a b c'). !TAIL('a'). !TAIL(!NULL). !TAIL(''). !ENDDEFINE. DEBUG EXPAND. !t. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl b c. . . . ]) AT_CLEANUP dnl Keep this test in sync with the examples for !INDEX in the manual. AT_SETUP([macro expansion - !INDEX]) AT_KEYWORDS([INDEX]) AT_DATA([define.sps], [dnl DEFINE !i() !INDEX(banana, an). !INDEX(banana, nan). !INDEX(banana, apple). !INDEX("banana", nan). !INDEX("banana", "nan"). !INDEX(!UNQUOTE("banana"), !UNQUOTE("nan")). !ENDDEFINE. DEBUG EXPAND. !i. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl 2. 3. 0. 4. 0. 3. ]) AT_CLEANUP dnl Keep this test in sync with the examples for !LENGTH in the manual. AT_SETUP([macro expansion - !LENGTH]) AT_KEYWORDS([LENGTH]) AT_DATA([define.sps], [dnl DEFINE !l() !LENGTH(123). !LENGTH(123.00). !LENGTH( 123 ). !LENGTH("123"). !LENGTH(xyzzy). !LENGTH("xyzzy"). !LENGTH("xy""zzy"). !LENGTH(!UNQUOTE("xyzzy")). !LENGTH(!UNQUOTE("xy""zzy")). !LENGTH(!NULL). !ENDDEFINE. DEFINE !la(!positional !enclose('(',')')) !LENGTH(!1). !ENDDEFINE. DEBUG EXPAND. !l. !la(a b c). !la(). ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl 3. 6. 3. 5. 5. 7. 9. 5. 6. 0. 5. 0. ]) AT_CLEANUP dnl Keep this test in sync with the examples for !SUBSTR in the manual. AT_SETUP([macro expansion - !SUBSTR]) AT_KEYWORDS([SUBSTR]) AT_DATA([define.sps], [dnl DEFINE !s() !SUBSTR(banana, 3). !SUBSTR(banana, 3, 3). !SUBSTR("banana", 1, 3). !SUBSTR(!UNQUOTE("banana"), 3). !SUBSTR("banana", 3, 3). !SUBSTR(banana, 3, 0). !SUBSTR(banana, 3, 10). !SUBSTR(banana, 10, 3). !ENDDEFINE. DEBUG EXPAND. !s. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [1], [dnl define.sps:1-10: At `"ba' in the expansion of `!s',dnl " define.sps:12.1-12.2: error: DEBUG EXPAND: Unterminated string constant. nana. nan. . nana. ana. . nana. . ]) AT_CLEANUP dnl Keep this test in sync with the examples for !UPCASE in the manual. AT_SETUP([macro expansion - !UPCASE]) AT_KEYWORDS([UPCASE]) AT_DATA([define.sps], [dnl DEFINE !u() !UPCASE(freckle). !UPCASE('freckle'). !UPCASE('a b c'). !UPCASE('A B C'). !ENDDEFINE. DEBUG EXPAND. !u. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl FRECKLE. FRECKLE. A B C. A B C. ]) AT_CLEANUP dnl !* is implemented separately inside and outside function arguments dnl so this test makes sure to include both. AT_SETUP([macro expansion - !*]) AT_DATA([define.sps], [dnl DEFINE !m(!POSITIONAL !TOKENS(1) /!POSITIONAL !TOKENS(1)) !*/ !LENGTH(!*)/ !SUBSTR(!*, 3)/ !QUOTE(!*). !ENDDEFINE. DEBUG EXPAND. !m 123 b !m 2 3 !m '' 'b'. ]) AT_CAPTURE_FILE([define.sps]) AT_CHECK([pspp --testing-mode define.sps], [0], [dnl 123 b / 5 / 3 b / '123 b'. 2 3 / 3 / 3 / '2 3'. '' 'b' / 6 / 'b' / ''''' ''b'''. ]) AT_CLEANUP AT_SETUP([macro maximum nesting level (MNEST)]) AT_KEYWORDS([MNEST]) AT_DATA([define.sps], [dnl DEFINE !macro() !macro !ENDDEFINE. !macro. ]) AT_CHECK([pspp -O format=csv define.sps], [1], [dnl "define.sps:1-3: In the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:1-3: inside the expansion of `!macro', define.sps:4.1-4.6: error: DEFINE: Maximum nesting level 50 exceeded. (Use SET MNEST to change the limit.)" define.sps:4.1-4.6: error: Syntax error at `!macro' (in expansion of `!macro'): expecting command name. ]) AT_CLEANUP AT_SETUP([macro !IF condition]) AT_KEYWORDS([if]) for operators in \ '!eq !ne !lt !gt !le !ge' \ ' = <> < > <= >=' do set $operators AS_BOX([$operators]) cat > define.sps < < > <= >=' do set $operators AS_BOX([$operators]) cat > define.sps < define.sps <title.sps <expout <