DEFINE: Only expand macro functions when the name is followed by '('.
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 26 Aug 2021 16:32:31 +0000 (09:32 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 26 Aug 2021 16:32:31 +0000 (09:32 -0700)
Frans Houweling reported that PSPP was flagging an error for !EVAL(!len)
when !len was the name of a defined macro.  This was because !len is short
for the !LENGTH macro function.  This commit fixes the problem.

src/language/lexer/macro.c
tests/language/control/define.at

index 977436a6041b32a7dc39f31d57daebc7262ceb9b..742b8771ac8d353ed113cf97367ce59ff59da10c 100644 (file)
@@ -986,12 +986,7 @@ parse_function_args (const struct macro_expander *me,
                      const char *function,
                      struct string_array *args)
 {
-  if (n < 2 || mts[1].token.type != T_LPAREN)
-    {
-      macro_error (me->stack, n > 1 ? &mts[1] : NULL,
-                   _("`(' expected following %s."), function);
-      return 0;
-    }
+  assert (n >= 2 && mts[1].token.type == T_LPAREN);
 
   for (size_t i = 2; i < n; )
     {
@@ -1090,7 +1085,6 @@ expand_macro_function (const struct macro_expander *me,
       MF_HEAD,
       MF_INDEX,
       MF_LENGTH,
-      MF_NULL,
       MF_QUOTE,
       MF_SUBSTR,
       MF_TAIL,
@@ -1104,7 +1098,6 @@ expand_macro_function (const struct macro_expander *me,
     [MF_HEAD]    = { "!HEAD",    1, 1 },
     [MF_INDEX]   = { "!INDEX",   2, 2 },
     [MF_LENGTH]  = { "!LENGTH",  1, 1 },
-    [MF_NULL]    = { "!NULL",    0, 0 },
     [MF_QUOTE]   = { "!QUOTE",   1, 1 },
     [MF_SUBSTR]  = { "!SUBSTR",  2, 3 },
     [MF_TAIL]    = { "!TAIL",    1, 1 },
@@ -1112,7 +1105,16 @@ expand_macro_function (const struct macro_expander *me,
     [MF_UPCASE]  = { "!UPCASE",  1, 1 },
   };
 
-  /* Is this a macro function? */
+  if (lex_id_match_n (ss_cstr ("!NULL"), input[0].token.string, 4))
+    return 1;
+
+  if (n_input < 2 || input[1].token.type != T_LPAREN)
+    {
+      /* Only consider macro functions when the name is followed by '('. */
+      return 0;
+    }
+
+  /* Is this a macro function name? */
   const struct macro_function *mf;
   for (mf = mfs; ; mf++)
     {
@@ -1127,8 +1129,6 @@ expand_macro_function (const struct macro_expander *me,
     }
 
   enum macro_function_id id = mf - mfs;
-  if (id == MF_NULL)
-    return 1;
 
   struct string_array args = STRING_ARRAY_INITIALIZER;
   size_t n_consumed = parse_function_args (me, input, n_input, mf->name, &args);
index 3c940c151380149e252bb4a7af7c17884f90b6f2..9a7594b81bda47ca3d243dfe621f3449def4360d 100644 (file)
@@ -1633,10 +1633,26 @@ not a multiple of 2.
 ])
 AT_CLEANUP
 
+AT_SETUP([macro name overlaps with macro function name])
+dnl !len is short for macro function !LENGTH.  PSPP used to
+dnl reject the following with "`(' expected following !LENGTH".
+dnl Now PSPP only consider macro functions when the name is
+dnl followed by '('.
+AT_DATA([define.sps], [dnl
+DEFINE !len() 5 !ENDDEFINE.
+DEFINE !x() !eval(!len) !ENDDEFINE.
+DEBUG EXPAND.
+!x
+])
+AT_CHECK([pspp -O format=csv define.sps --testing-mode], [0], [dnl
+5
+])
+AT_CLEANUP
+
 AT_SETUP([generic macro function syntax errors])
 AT_DATA([define.sps], [dnl
-DEFINE !a() !SUBSTR !ENDDEFINE.
-DEFINE !b() !SUBSTR x !ENDDEFINE.
+
+
 DEFINE !c() !SUBSTR(1x) !ENDDEFINE.
 DEFINE !d() !SUBSTR(1 !ENDDEFINE.
 DEFINE !narg_blanks() !BLANKS() !ENDDEFINE.
@@ -1653,8 +1669,8 @@ DEFINE !narg_unquote() !UNQUOTE() !ENDDEFINE.
 DEFINE !narg_upcase() !UPCASE() !ENDDEFINE.
 dnl )
 DEBUG EXPAND.
-!a.
-!b.
+
+
 !c.
 !d.
 !narg_blanks.
@@ -1671,16 +1687,6 @@ DEBUG EXPAND.
 !narg_upcase.
 ])
 AT_CHECK([pspp --testing-mode define.sps], [1], [dnl
-define.sps:1: In the expansion of `!a',
-define.sps:18.1-18.2: error: DEBUG EXPAND: `@{:@' expected following !SUBSTR.
-
-!SUBSTR
-
-define.sps:2: At `x' in the expansion of `!b',
-define.sps:19.1-19.2: error: DEBUG EXPAND: `@{:@' expected following !SUBSTR.
-
-!SUBSTR x
-
 define.sps:3: At `x' in the expansion of `!c',
 define.sps:20.1-20.2: error: DEBUG EXPAND: `,' or `@:}@' expected in call to macro
 function !SUBSTR.