!BREAK works
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 18 Jun 2021 02:42:42 +0000 (19:42 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 27 Jun 2021 07:10:25 +0000 (00:10 -0700)
src/language/lexer/macro.c
tests/language/control/define.at

index 12e27620c1c23c997c285ef4f755ba00348be44a..6d7decb40faccf0e97e85a40ca04379885c068c4 100644 (file)
@@ -722,7 +722,7 @@ static void
 macro_expand (const struct macro_tokens *,
               int nesting_countdown, const struct macro_set *,
               const struct macro_expander *, struct string_map *vars,
-              bool *expand, struct macro_tokens *exp);
+              bool *expand, bool *break_, struct macro_tokens *exp);
 
 static bool
 expand_macro_function (struct parse_macro_function_ctx *ctx,
@@ -1054,7 +1054,7 @@ expand_macro_function (struct parse_macro_function_ctx *ctx,
                                 SEG_MODE_INTERACTIVE /* XXX */);
       struct macro_tokens exp = { .n = 0 };
       macro_expand (&mts, ctx->nesting_countdown - 1, ctx->macros, ctx->me,
-                    ctx->vars, ctx->expand, &exp);
+                    ctx->vars, ctx->expand, NULL, &exp);
       macro_tokens_to_representation (&exp, output);
       macro_tokens_uninit (&exp);
       macro_tokens_uninit (&mts);
@@ -1378,7 +1378,7 @@ static size_t
 macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
                  int nesting_countdown, const struct macro_set *macros,
                  const struct macro_expander *me, struct string_map *vars,
-                 bool *expand, struct macro_tokens *exp)
+                 bool *expand, bool *break_, struct macro_tokens *exp)
 {
   const struct macro_token *p = tokens;
   const struct macro_token *end = tokens + n_tokens;
@@ -1453,7 +1453,8 @@ macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
         .mts = CONST_CAST (struct macro_token *, start),
         .n = n,
       };
-      macro_expand (&mts, nesting_countdown, macros, me, vars, expand, exp);
+      macro_expand (&mts, nesting_countdown, macros, me, vars, expand,
+                    break_, exp);
     }
   return (end_if + 1) - tokens;
 }
@@ -1569,8 +1570,12 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
         {
           string_map_replace_nocopy (vars, ss_xstrdup (var_name),
                                      ss_xstrdup (items.mts[i].representation));
+
+          bool break_ = false;
           macro_expand (&inner, nesting_countdown, macros,
-                        me, vars, expand, exp);
+                        me, vars, expand, &break_, exp);
+          if (break_)
+            break;
         }
       return do_end - tokens + 1;
     }
@@ -1628,8 +1633,12 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
             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, exp);
+                          me, vars, expand, &break_, exp);
+            if (break_)
+              break;
           }
 
       return do_end - tokens + 1;
@@ -1645,7 +1654,7 @@ static void
 macro_expand (const struct macro_tokens *mts,
               int nesting_countdown, const struct macro_set *macros,
               const struct macro_expander *me, struct string_map *vars,
-              bool *expand, struct macro_tokens *exp)
+              bool *expand, bool *break_, struct macro_tokens *exp)
 {
   if (nesting_countdown <= 0)
     {
@@ -1658,7 +1667,8 @@ macro_expand (const struct macro_tokens *mts,
   struct string_map own_vars = STRING_MAP_INITIALIZER (own_vars);
   if (!vars)
     vars = &own_vars;
-  for (size_t i = 0; i < mts->n; i++)
+
+  for (size_t i = 0; i < mts->n && (!break_ || !*break_); i++)
     {
       const struct macro_token *mt = &mts->mts[i];
       const struct token *token = &mt->token;
@@ -1672,7 +1682,7 @@ macro_expand (const struct macro_tokens *mts,
               //macro_tokens_print (arg, stdout);
               if (*expand && param->expand_arg)
                 macro_expand (arg, nesting_countdown, macros, NULL, NULL,
-                              expand, exp);
+                              expand, break_, exp);
               else
                 for (size_t i = 0; i < arg->n; i++)
                   macro_tokens_add (exp, &arg->mts[i]);
@@ -1690,7 +1700,7 @@ macro_expand (const struct macro_tokens *mts,
                   const struct macro_tokens *arg = me->args[j];
                   if (*expand && param->expand_arg)
                     macro_expand (arg, nesting_countdown, macros, NULL, NULL,
-                                  expand, exp);
+                                  expand, break_, exp);
                   else
                     for (size_t k = 0; k < arg->n; k++)
                       macro_tokens_add (exp, &arg->mts[k]);
@@ -1701,7 +1711,7 @@ macro_expand (const struct macro_tokens *mts,
 
           size_t n = macro_expand_if (&mts->mts[i], mts->n - i,
                                       nesting_countdown, macros, me, vars,
-                                      expand, exp);
+                                      expand, break_, exp);
           if (n > 0)
             {
               i += n - 1;
@@ -1735,7 +1745,7 @@ macro_expand (const struct macro_tokens *mts,
             {
               i += retval - 1;
               macro_expand (&subme->macro->body, nesting_countdown - 1, macros,
-                            subme, NULL, expand, exp);
+                            subme, NULL, expand, break_, exp);
               macro_expander_destroy (subme);
               continue;
             }
@@ -1749,6 +1759,17 @@ macro_expand (const struct macro_tokens *mts,
           continue;
         }
 
+      if (ss_equals_case (token->string, ss_cstr ("!break")))
+        {
+          if (!break_)
+            printf ("!BREAK outside !DO\n");
+          else
+            {
+              *break_ = true;
+              break;
+            }
+        }
+
       struct parse_macro_function_ctx ctx = {
         .input = &mts->mts[i],
         .n_input = mts->n - i,
@@ -1813,7 +1834,7 @@ macro_expander_get_expansion (struct macro_expander *me, struct macro_tokens *ex
 
   bool expand = true;
   macro_expand (&me->macro->body, settings_get_mnest (),
-                me->macros, me, NULL, &expand, exp);
+                me->macros, me, NULL, &expand, NULL, exp);
 
 #if 0
   printf ("expansion:\n");
index 41557ca711e98e50e3989f5a3567812e57ba5537..fa2670f9e6c367e67dace6389514e1c5ba709077 100644 (file)
@@ -819,6 +819,33 @@ AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
 ])
 AT_CLEANUP
 
+AT_SETUP([!BREAK with macro indexed !DO])
+AT_KEYWORDS([index do break])
+AT_DATA([define.sps], [dnl
+DEFINE !title(!POS !TOKENS(1)) !1. !ENDDEFINE.
+
+DEFINE !for(!POS !TOKENS(1) / !POS !TOKENS(1) / !POS !TOKENS(1))
+!DO !var = !1 !TO !2
+  !var
+  !IF 1 !THEN
+    !IF !var = !3 !THEN
+      x
+      !BREAK
+      y
+    !IFEND
+    ,
+  !IFEND
+!DOEND.
+!ENDDEFINE.
+
+DEBUG EXPAND.
+!for 1 5 4.
+])
+AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
+1, 2, 3, 4 x.
+])
+AT_CLEANUP
+
 AT_SETUP([macro list !DO])
 AT_KEYWORDS([index do])
 AT_DATA([define.sps], [dnl
@@ -840,3 +867,33 @@ AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
 ])
 AT_CLEANUP
 
+AT_SETUP([!BREAK with macro list !DO])
+AT_KEYWORDS([index break do])
+AT_DATA([define.sps], [dnl
+DEFINE !for(!POS !TOKENS(1) / !POS !CMDEND)
+(!DO !i !IN (!2)
+  (!i)
+  !IF 1 !THEN
+    !IF !i = !1 !THEN
+      x
+      !BREAK
+      y
+    !IFEND
+    ,
+  !IFEND
+!DOEND).
+!ENDDEFINE.
+
+DEBUG EXPAND.
+!for d a b c.
+!for baz 'foo bar baz quux'.
+!for e.
+])
+AT_CHECK([pspp --testing-mode define.sps], [0], [dnl
+( (a), (b), (c), ).
+
+( (foo), (bar), (baz)x).
+
+( ).
+])
+AT_CLEANUP