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]) m4_define([PSPP_CHECK_MACRO_EXPANSION], [AT_SETUP([macro expansion - $1]) AT_KEYWORDS([m4_bpatsubst([$1], [!], [])]) AT_DATA([define.sps], [$2 DEBUG EXPAND. $3 ]) AT_CAPTURE_FILE([define.sps]) AT_DATA([expout], [$4 ]) AT_CHECK([pspp --testing-mode define.sps | sed '/^$/d'], [$6], [expout]) AT_CLEANUP]) 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 PSPP_CHECK_MACRO_EXPANSION([one !TOKENS(1) positional argument], [DEFINE !t1(!positional !tokens(1)) t1 (!1) !ENDDEFINE.], [!t1 a. !t1 b. !t1 a b.], [t1(a) t1(b) t1(a) note: unexpanded token "b"]) 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: 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: error: DEBUG EXPAND: Unexpected end of command reading argument !2 to macro !p. note: unexpanded token "!p" note: unexpanded token "a" define.sps:15: error: DEBUG EXPAND: Unexpected end of command reading argument !1 to macro !p. note: unexpanded token "!p" "Missing charend delimiter." define.sps:18: 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: 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: 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 PSPP_CHECK_MACRO_EXPANSION([one !TOKENS(1) keyword argument], [DEFINE !k(arg1 = !TOKENS(1)) k(!arg1) !ENDDEFINE.], [!k arg1=x. !k arg1=x y. !k.], [k(x) k(x) note: unexpanded token "y" k( )]) PSPP_CHECK_MACRO_EXPANSION([one !TOKENS(1) keyword argument - negative], [DEFINE !k(arg1 = !TOKENS(1)) k(!arg1) !ENDDEFINE.], [!k arg1. !k arg1=.], [dnl define.sps:3: error: DEBUG EXPAND: Found `.' while expecting `=' reading argument !arg1 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" define.sps:4: error: DEBUG EXPAND: Unexpected end of command reading argument ! arg1 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" note: unexpanded token "="], [1]) PSPP_CHECK_MACRO_EXPANSION([!CHAREND('/') keyword arguments], [dnl DEFINE !k(arg1 = !CHAREND('/') /arg2 = !CHAREND('/')) k(!arg1, !arg2) !ENDDEFINE.], [!k arg1=x/ arg2=y/. !k arg1=x/. !k arg2=y/. !k.], [k(x, y) k(x, ) k(, y) k(, )]) PSPP_CHECK_MACRO_EXPANSION([!CHAREND('/') keyword arguments - negative], [dnl DEFINE !k(arg1 = !CHAREND('/') /arg2 = !CHAREND('/')) k(!arg1, !arg2) !ENDDEFINE.], [!k arg1. !k arg1=. !k arg1=x. !k arg1=x/ arg2=y.], [define.sps:6: error: DEBUG EXPAND: Found `.' while expecting `=' reading argument !arg1 to macro !k. note: unexpanded token "!k" note: unexpanded token "arg1" define.sps:7: 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: 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: 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"]) PSPP_CHECK_MACRO_EXPANSION([default keyword arguments], [DEFINE !k(arg1 = !DEFAULT(a b c) !CMDEND) k(!arg1) !ENDDEFINE], [!k arg1=x. !k], [k(x) k(a b c)]) dnl Keep this test in sync with the examples for !BLANKS in the manual. PSPP_CHECK_MACRO_EXPANSION([!BLANKS], [DEFINE !b() !BLANKS(0). !QUOTE(!BLANKS(0)). !BLANKS(1). !QUOTE(!BLANKS(1)). !BLANKS(2). !QUOTE(!BLANKS(2)). !BLANKS(5). !QUOTE(!BLANKS(5)). !ENDDEFINE], [!b.], [. ''. . ' '. . ' '. . ' '.]) dnl Keep this test in sync with the examples for !CONCAT in the manual. PSPP_CHECK_MACRO_EXPANSION([!CONCAT], [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], [!c.], [xy. xy. 1234. 123. x0. x0y. 0 x. 0 xy.]) dnl Keep this test in sync with the examples for !EVAL in the manual. PSPP_CHECK_MACRO_EXPANSION([!EVAL], [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], [!e. !e2(!vars)], [a b c. '!vars'. a b c. 'a b c'. a b c. '!vars'. a b c. 'a b c'.]) dnl Keep this test in sync with the examples for !HEAD in the manual. PSPP_CHECK_MACRO_EXPANSION([!HEAD], [DEFINE !h() !HEAD('a b c'). !HEAD('a'). !HEAD(!NULL). !HEAD(''). !ENDDEFINE], [!h.], [a. a. . .]) dnl Keep this test in sync with the examples for !TAIL in the manual. PSPP_CHECK_MACRO_EXPANSION([!TAIL], [DEFINE !t() !TAIL('a b c'). !TAIL('a'). !TAIL(!NULL). !TAIL(''). !ENDDEFINE], [!t.], [b c. . . .]) dnl Keep this test in sync with the examples for !INDEX in the manual. PSPP_CHECK_MACRO_EXPANSION([!INDEX], [DEFINE !i() !INDEX(banana, an). !INDEX(banana, nan). !INDEX(banana, apple). !INDEX("banana", nan). !INDEX("banana", "nan"). !INDEX(!UNQUOTE("banana"), !UNQUOTE("nan")). !ENDDEFINE], [!i.], [2. 3. 0. 4. 0. 3.]) dnl Keep this test in sync with the examples for !LENGTH in the manual. PSPP_CHECK_MACRO_EXPANSION([!LENGTH], [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.], [!l. !la(a b c). !la().], [3. 6. 3. 5. 5. 7. 9. 5. 6. 0. 5. 0.]) dnl Keep this test in sync with the examples for !SUBSTR in the manual. PSPP_CHECK_MACRO_EXPANSION([!SUBSTR], [DEFINE !s() !SUBSTR(banana, 3). !SUBSTR(banana, 3, 3). !SUBSTR("banana", 3). !SUBSTR(!UNQUOTE("banana"), 3). !SUBSTR("banana", 3, 3). !SUBSTR(banana, 3, 0). !SUBSTR(banana, 3, 10). !SUBSTR(banana, 10, 3). !ENDDEFINE.], [!s.], [error nana. nan. anana. nana. ana. . nana. .]) dnl Keep this test in sync with the examples for !UPCASE in the manual. PSPP_CHECK_MACRO_EXPANSION([!UPCASE], [DEFINE !u() !UPCASE(freckle). !UPCASE('freckle'). !UPCASE('a b c'). !UPCASE('A B C'). !ENDDEFINE.], [!u.], [FRECKLE. FRECKLE. A B C. A B C.]) dnl !* is implemented separately inside and outside function arguments dnl so this test makes sure to include both. PSPP_CHECK_MACRO_EXPANSION([!*], [dnl DEFINE !m(!POSITIONAL !TOKENS(1) /!POSITIONAL !TOKENS(1)) !*/ !LENGTH(!*)/ !SUBSTR(!*, 3)/ !QUOTE(!*). !ENDDEFINE.], [!m 123 b !m 2 3 !m '' 'b'. ], [123 b / 5 / 3 b / '123 b'. 2 3 / 3 / 3 / '2 3'. '' 'b' / 6 / 'b' / ''''' ''b'''.]) AT_SETUP([macro maximum nesting level (MNEST)]) AT_KEYWORDS([MNEST]) AT_DATA([define.sps], [dnl DEFINE !macro() !macro !ENDDEFINE. !macro. ]) AT_CHECK([pspp define.sps], [1], [dnl maximum nesting level exceeded define.sps.1: error: Syntax error at `!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 <