tons of progress on macros
[pspp] / src / language / lexer / macro.c
index 6d7decb40faccf0e97e85a40ca04379885c068c4..2accd94df95b752fa68dd5c90acdb2bc9ae61a63 100644 (file)
@@ -32,6 +32,7 @@
 #include "libpspp/str.h"
 #include "libpspp/string-array.h"
 #include "libpspp/string-map.h"
+#include "libpspp/stringi-set.h"
 
 #include "gl/c-ctype.h"
 #include "gl/ftoastr.h"
@@ -59,6 +60,41 @@ macro_token_to_representation (struct macro_token *mt, struct string *s)
   ds_put_substring (s, mt->representation);
 }
 
+bool
+is_macro_keyword (struct substring s)
+{
+  static struct stringi_set keywords = STRINGI_SET_INITIALIZER (keywords);
+  if (stringi_set_is_empty (&keywords))
+    {
+      static const char *kws[] = {
+        "BREAK",
+        "CHAREND",
+        "CMDEND",
+        "DEFAULT",
+        "DO",
+        "DOEND",
+        "ELSE",
+        "ENCLOSE",
+        "ENDDEFINE",
+        "IF",
+        "IFEND",
+        "IN",
+        "LET",
+        "NOEXPAND",
+        "OFFEXPAND",
+        "ONEXPAND",
+        "POSITIONAL",
+        "THEN",
+        "TOKENS",
+      };
+      for (size_t i = 0; i < sizeof kws / sizeof *kws; i++)
+        stringi_set_insert (&keywords, kws[i]);
+    }
+
+  ss_ltrim (&s, ss_cstr ("!"));
+  return stringi_set_contains_len (&keywords, s.string, s.length);
+}
+
 void
 macro_tokens_copy (struct macro_tokens *dst, const struct macro_tokens *src)
 {
@@ -543,8 +579,7 @@ me_enclose (struct macro_expander *me, const struct macro_token *mt)
 static const struct macro_param *
 macro_find_parameter_by_name (const struct macro *m, struct substring name)
 {
-  if (ss_first (name) == '!')
-    ss_advance (&name, 1);
+  ss_ltrim (&name, ss_cstr ("!"));
 
   for (size_t i = 0; i < m->n_params; i++)
     {
@@ -1478,6 +1513,12 @@ macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
       return 0;
     }
   const struct substring var_name = p->token.string;
+  if (is_macro_keyword (var_name)
+      || macro_find_parameter_by_name (me->macro, var_name))
+    {
+      printf ("cannot use argument name or macro keyword as !LET variable\n");
+      return 0;
+    }
   p++;
 
   if (p >= end || p->token.type != T_EQUALS)
@@ -1538,8 +1579,15 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
       return 0;
     }
   const struct substring var_name = p->token.string;
+  if (is_macro_keyword (var_name)
+      || macro_find_parameter_by_name (me->macro, var_name))
+    {
+      printf ("cannot use argument name or macro keyword as !DO variable\n");
+      return 0;
+    }
   p++;
 
+  int miterate = settings_get_miterate ();
   if (p < end && p->token.type == T_MACRO_ID
       && ss_equals_case (p->token.string, ss_cstr ("!IN")))
     {
@@ -1568,6 +1616,11 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
       };
       for (size_t i = 0; i < items.n; i++)
         {
+          if (i >= miterate)
+            {
+              printf ("exceeded maximum number of iterations %d\n", miterate);
+              break;
+            }
           string_map_replace_nocopy (vars, ss_xstrdup (var_name),
                                      ss_xstrdup (items.mts[i].representation));
 
@@ -1625,21 +1678,31 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
       };
 
       if ((by > 0 && first <= last) || (by < 0 && first >= last))
-        for (double index = first;
-             by > 0 ? (index <= last) : (index >= last);
-             index += by)
-          {
-            char index_s[DBL_BUFSIZE_BOUND];
-            c_dtoastr (index_s, sizeof index_s, 0, 0, index);
-            string_map_replace_nocopy (vars, ss_xstrdup (var_name),
-                                       xstrdup (index_s));
-
-            bool break_ = false;
-            macro_expand (&inner, nesting_countdown, macros,
-                          me, vars, expand, &break_, exp);
-            if (break_)
-              break;
-          }
+        {
+          int i = 0;
+          for (double index = first;
+               by > 0 ? (index <= last) : (index >= last);
+               index += by)
+            {
+              if (i++ > miterate)
+                {
+                  printf ("exceeded maximum number of iterations %d\n",
+                          miterate);
+                  break;
+                }
+
+              char index_s[DBL_BUFSIZE_BOUND];
+              c_dtoastr (index_s, sizeof index_s, 0, 0, index);
+              string_map_replace_nocopy (vars, ss_xstrdup (var_name),
+                                         xstrdup (index_s));
+
+              bool break_ = false;
+              macro_expand (&inner, nesting_countdown, macros,
+                            me, vars, expand, &break_, exp);
+              if (break_)
+                break;
+            }
+        }
 
       return do_end - tokens + 1;
     }