From 3c71220834d52d1c4ebdddc9670e911ffdd90852 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 17 Jun 2021 19:42:42 -0700 Subject: [PATCH] !BREAK works --- src/language/lexer/macro.c | 47 ++++++++++++++++++-------- tests/language/control/define.at | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/src/language/lexer/macro.c b/src/language/lexer/macro.c index 12e27620c1..6d7decb40f 100644 --- a/src/language/lexer/macro.c +++ b/src/language/lexer/macro.c @@ -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"); diff --git a/tests/language/control/define.at b/tests/language/control/define.at index 41557ca711..fa2670f9e6 100644 --- a/tests/language/control/define.at +++ b/tests/language/control/define.at @@ -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 -- 2.30.2