1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2021 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "language/lexer/macro.h"
25 #include "data/settings.h"
26 #include "language/lexer/lexer.h"
27 #include "language/lexer/segment.h"
28 #include "language/lexer/scan.h"
29 #include "libpspp/assertion.h"
30 #include "libpspp/cast.h"
31 #include "libpspp/i18n.h"
32 #include "libpspp/message.h"
33 #include "libpspp/str.h"
34 #include "libpspp/string-array.h"
35 #include "libpspp/stringi-map.h"
36 #include "libpspp/stringi-set.h"
38 #include "gl/c-ctype.h"
39 #include "gl/ftoastr.h"
42 #define _(msgid) gettext (msgid)
44 /* An entry in the stack of macros and macro directives being expanded. The
45 stack is maintained as a linked list. Entries are not dynamically allocated
46 but on the program stack.
48 The outermost entry, where 'next' is NULL, represents the source location of
49 the call to the macro. */
50 struct macro_expansion_stack
52 const struct macro_expansion_stack *next; /* Next outer stack entry. */
53 const char *name; /* A macro name or !IF, !DO, etc. */
54 const struct msg_location *location; /* Source location if available. */
57 /* Reports an error during macro expansion. STACK is the stack for reporting
58 the location of the error, MT is the optional token at which the error was
59 detected, and FORMAT along with the varargs is the message to report. */
60 static void PRINTF_FORMAT (3, 0)
61 macro_error_valist (const struct macro_expansion_stack *stack,
62 const struct macro_token *mt, const char *format,
65 struct msg_stack **ms = NULL;
66 size_t allocated_ms = 0;
69 const struct macro_expansion_stack *p;
70 for (p = stack; p && p->next; p = p->next)
72 if (n_ms >= allocated_ms)
73 ms = x2nrealloc (ms, &allocated_ms, sizeof *ms);
75 /* TRANSLATORS: These strings are used for explaining the context of an
76 error. The "While expanding" message appears first, followed by zero
77 or more of the "inside expansion" messages. `innermost',
78 `next_inner`, etc., are names of macros, and `foobar' is a piece of
81 foo.sps:12: At `foobar' in the expansion of 'innermost',
82 foo.sps:23: inside the expansion of 'next_inner',
83 foo.sps:34: inside the expansion of 'next_inner2',
84 foo.sps:45: inside the expansion of 'outermost',
85 foo.sps:76: This is the actual error message. */
89 if (mt && mt->syntax.length)
92 str_ellipsize (mt->syntax, syntax, sizeof syntax);
93 description = xasprintf (_("At `%s' in the expansion of `%s',"),
97 description = xasprintf (_("In the expansion of `%s',"), p->name);
100 description = xasprintf (_("inside the expansion of `%s',"), p->name);
102 ms[n_ms] = xmalloc (sizeof *ms[n_ms]);
103 *ms[n_ms] = (struct msg_stack) {
104 .location = msg_location_dup (p->location),
105 .description = description,
110 struct msg *m = xmalloc (sizeof *m);
112 .category = MSG_C_SYNTAX,
113 .severity = MSG_S_ERROR,
116 .location = msg_location_dup (p ? p->location : NULL),
117 .text = xvasprintf (format, args),
122 /* Reports an error during macro expansion. STACK is the stack for reporting
123 the location of the error, MT is the optional token at which the error was
124 detected, and FORMAT along with the varargs is the message to report. */
125 static void PRINTF_FORMAT (3, 4)
126 macro_error (const struct macro_expansion_stack *stack,
127 const struct macro_token *mt, const char *format, ...)
130 va_start (args, format);
131 macro_error_valist (stack, mt, format, args);
136 macro_token_copy (struct macro_token *dst, const struct macro_token *src)
138 token_copy (&dst->token, &src->token);
139 ss_alloc_substring (&dst->syntax, src->syntax);
143 macro_token_uninit (struct macro_token *mt)
145 token_uninit (&mt->token);
146 ss_dealloc (&mt->syntax);
150 macro_token_to_syntax (struct macro_token *mt, struct string *s)
152 ds_put_substring (s, mt->syntax);
155 is_macro_keyword (struct substring s)
157 static struct stringi_set keywords = STRINGI_SET_INITIALIZER (keywords);
158 if (stringi_set_is_empty (&keywords))
160 static const char *kws[] = {
181 for (size_t i = 0; i < sizeof kws / sizeof *kws; i++)
182 stringi_set_insert (&keywords, kws[i]);
185 ss_ltrim (&s, ss_cstr ("!"));
186 return stringi_set_contains_len (&keywords, s.string, s.length);
190 macro_tokens_copy (struct macro_tokens *dst, const struct macro_tokens *src)
192 *dst = (struct macro_tokens) {
193 .mts = xmalloc (src->n * sizeof *dst->mts),
197 for (size_t i = 0; i < src->n; i++)
198 macro_token_copy (&dst->mts[i], &src->mts[i]);
202 macro_tokens_uninit (struct macro_tokens *mts)
204 for (size_t i = 0; i < mts->n; i++)
205 macro_token_uninit (&mts->mts[i]);
210 macro_tokens_add_uninit (struct macro_tokens *mts)
212 if (mts->n >= mts->allocated)
213 mts->mts = x2nrealloc (mts->mts, &mts->allocated, sizeof *mts->mts);
214 return &mts->mts[mts->n++];
218 macro_tokens_add (struct macro_tokens *mts, const struct macro_token *mt)
220 macro_token_copy (macro_tokens_add_uninit (mts), mt);
223 /* Tokenizes SRC according to MODE and appends the tokens to MTS. Uses STACK,
224 if nonull, for error reporting. */
226 macro_tokens_from_string__ (struct macro_tokens *mts, const struct substring src,
227 enum segmenter_mode mode,
228 const struct macro_expansion_stack *stack)
230 struct segmenter segmenter = segmenter_init (mode, true);
231 struct substring body = src;
233 while (body.length > 0)
235 struct macro_token mt = {
236 .token = { .type = T_STOP },
237 .syntax = { .string = body.string },
239 struct token *token = &mt.token;
241 enum segment_type type;
242 int seg_len = segmenter_push (&segmenter, body.string,
243 body.length, true, &type);
244 assert (seg_len >= 0);
246 struct substring segment = ss_head (body, seg_len);
247 enum tokenize_result result = token_from_segment (type, segment, token);
248 ss_advance (&body, seg_len);
256 mt.syntax.length = body.string - mt.syntax.string;
257 macro_tokens_add (mts, &mt);
261 mt.syntax.length = body.string - mt.syntax.string;
262 macro_error (stack, &mt, "%s", token->string.string);
266 token_uninit (token);
270 /* Tokenizes SRC according to MODE and appends the tokens to MTS. */
272 macro_tokens_from_string (struct macro_tokens *mts, const struct substring src,
273 enum segmenter_mode mode)
275 macro_tokens_from_string__ (mts, src, mode, NULL);
279 macro_tokens_print (const struct macro_tokens *mts, FILE *stream)
281 for (size_t i = 0; i < mts->n; i++)
282 token_print (&mts->mts[i].token, stream);
287 TC_ENDCMD, /* No space before or after (new-line after). */
288 TC_BINOP, /* Space on both sides. */
289 TC_COMMA, /* Space afterward. */
290 TC_ID, /* Don't need spaces except sequentially. */
291 TC_PUNCT, /* Don't need spaces except sequentially. */
295 needs_space (enum token_class prev, enum token_class next)
297 /* Don't need a space before or after the end of a command.
298 (A new-line is needed afterward as a special case.) */
299 if (prev == TC_ENDCMD || next == TC_ENDCMD)
302 /* Binary operators always have a space on both sides. */
303 if (prev == TC_BINOP || next == TC_BINOP)
306 /* A comma always has a space afterward. */
307 if (prev == TC_COMMA)
310 /* Otherwise, PREV is TC_ID or TC_PUNCT, which only need a space if there are
311 two or them in a row. */
315 static enum token_class
316 classify_token (enum token_type type)
368 /* Appends syntax for the tokens in MTS to S. If OFS and LEN are nonnull, sets
369 OFS[i] to the offset within S of the start of token 'i' in MTS and LEN[i] to
370 its length. OFS[i] + LEN[i] is not necessarily OFS[i + 1] because some
371 tokens are separated by white space. */
373 macro_tokens_to_syntax (struct macro_tokens *mts, struct string *s,
374 size_t *ofs, size_t *len)
376 assert ((ofs != NULL) == (len != NULL));
381 for (size_t i = 0; i < mts->n; i++)
385 enum token_type prev = mts->mts[i - 1].token.type;
386 enum token_type next = mts->mts[i].token.type;
388 if (prev == T_ENDCMD)
389 ds_put_byte (s, '\n');
392 enum token_class pc = classify_token (prev);
393 enum token_class nc = classify_token (next);
394 if (needs_space (pc, nc))
395 ds_put_byte (s, ' ');
400 ofs[i] = s->ss.length;
401 macro_token_to_syntax (&mts->mts[i], s);
403 len[i] = s->ss.length - ofs[i];
408 macro_destroy (struct macro *m)
414 msg_location_destroy (m->location);
415 for (size_t i = 0; i < m->n_params; i++)
417 struct macro_param *p = &m->params[i];
420 macro_tokens_uninit (&p->def);
428 token_uninit (&p->charend);
432 token_uninit (&p->enclose[0]);
433 token_uninit (&p->enclose[1]);
441 macro_tokens_uninit (&m->body);
446 macro_set_create (void)
448 struct macro_set *set = xmalloc (sizeof *set);
449 *set = (struct macro_set) {
450 .macros = HMAP_INITIALIZER (set->macros),
456 macro_set_destroy (struct macro_set *set)
461 struct macro *macro, *next;
462 HMAP_FOR_EACH_SAFE (macro, next, struct macro, hmap_node, &set->macros)
464 hmap_delete (&set->macros, ¯o->hmap_node);
465 macro_destroy (macro);
467 hmap_destroy (&set->macros);
472 hash_macro_name (const char *name)
474 return utf8_hash_case_string (name, 0);
477 static struct macro *
478 macro_set_find__ (struct macro_set *set, const char *name)
480 if (macro_set_is_empty (set))
484 HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
485 hash_macro_name (name), &set->macros)
486 if (!utf8_strcasecmp (macro->name, name))
493 macro_set_find (const struct macro_set *set, const char *name)
495 return macro_set_find__ (CONST_CAST (struct macro_set *, set), name);
498 /* Adds M to SET. M replaces any existing macro with the same name. Takes
501 macro_set_add (struct macro_set *set, struct macro *m)
503 struct macro *victim = macro_set_find__ (set, m->name);
506 hmap_delete (&set->macros, &victim->hmap_node);
507 macro_destroy (victim);
510 hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
513 /* Macro call parsing. */
520 /* Accumulating tokens in mc->params toward the end of any type of
524 /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
527 /* Expecting a keyword for a keyword argument. */
530 /* Expecting an equal sign for a keyword argument. */
533 /* Macro fully parsed and ready for expansion. */
537 /* Parsing macro calls. This is a FSM driven by macro_call_create() and
538 macro_call_add() to identify the macro being called and obtain its
539 arguments. 'state' identifies the FSM state. */
542 const struct macro_set *macros;
543 const struct macro *macro;
544 struct macro_tokens **args;
545 const struct macro_expansion_stack *stack;
546 const struct macro_expander *me;
550 const struct macro_param *param; /* Parameter currently being parsed. */
553 static bool macro_expand_arg (const struct token *,
554 const struct macro_expander *,
555 struct macro_tokens *exp);
557 /* Completes macro expansion by initializing arguments that weren't supplied to
560 mc_finished (struct macro_call *mc)
562 mc->state = MC_FINISHED;
563 for (size_t i = 0; i < mc->macro->n_params; i++)
565 mc->args[i] = &mc->macro->params[i].def;
570 mc_next_arg (struct macro_call *mc)
574 assert (!mc->macro->n_params);
575 return mc_finished (mc);
577 else if (mc->param->positional)
580 if (mc->param >= &mc->macro->params[mc->macro->n_params])
581 return mc_finished (mc);
584 mc->state = (!mc->param->positional ? MC_KEYWORD
585 : mc->param->arg_type == ARG_ENCLOSE ? MC_ENCLOSE
592 for (size_t i = 0; i < mc->macro->n_params; i++)
595 mc->state = MC_KEYWORD;
598 return mc_finished (mc);
602 static void PRINTF_FORMAT (3, 4)
603 mc_error (const struct macro_call *mc, const struct msg_location *loc,
604 const char *format, ...)
607 va_start (args, format);
610 const struct macro_expansion_stack stack = { .location = loc };
611 macro_error_valist (&stack, NULL, format, args);
614 macro_error_valist (mc->stack, NULL, format, args);
619 mc_add_arg (struct macro_call *mc, const struct macro_token *mt,
620 const struct msg_location *loc)
622 const struct macro_param *p = mc->param;
624 const struct token *token = &mt->token;
625 if ((token->type == T_ENDCMD || token->type == T_STOP)
626 && p->arg_type != ARG_CMDEND)
629 _("Unexpected end of command reading argument %s "
630 "to macro %s."), mc->param->name, mc->macro->name);
632 mc->state = MC_ERROR;
638 struct macro_tokens **argp = &mc->args[p - mc->macro->params];
640 *argp = xzalloc (sizeof **argp);
642 bool add_token; /* Should we add 'mt' to the current arg? */
643 bool next_arg; /* Should we advance to the next arg? */
644 if (p->arg_type == ARG_N_TOKENS)
646 next_arg = (*argp)->n + 1 >= p->n_tokens;
651 next_arg = (p->arg_type == ARG_CMDEND
652 ? token->type == T_ENDCMD || token->type == T_STOP
653 : token_equal (token, (p->arg_type == ARG_CHAREND
654 ? &p->charend : &p->enclose[1])));
655 add_token = !next_arg;
660 if (!macro_expand_arg (&mt->token, mc->me, *argp))
661 macro_tokens_add (*argp, mt);
663 return next_arg ? mc_next_arg (mc) : 0;
667 mc_expected (struct macro_call *mc, const struct macro_token *actual,
668 const struct msg_location *loc, const struct token *expected)
670 const struct substring actual_s = (actual->syntax.length ? actual->syntax
671 : ss_cstr (_("<end of input>")));
672 char *expected_s = token_to_string (expected);
674 _("Found `%.*s' while expecting `%s' reading argument %s "
676 (int) actual_s.length, actual_s.string, expected_s,
677 mc->param->name, mc->macro->name);
680 mc->state = MC_ERROR;
685 mc_enclose (struct macro_call *mc, const struct macro_token *mt,
686 const struct msg_location *loc)
688 const struct token *token = &mt->token;
691 if (token_equal (&mc->param->enclose[0], token))
697 return mc_expected (mc, mt, loc, &mc->param->enclose[0]);
700 static const struct macro_param *
701 macro_find_parameter_by_name (const struct macro *m, struct substring name)
706 ss_ltrim (&name, ss_cstr ("!"));
708 for (size_t i = 0; i < m->n_params; i++)
710 const struct macro_param *p = &m->params[i];
711 struct substring p_name = ss_cstr (p->name + 1);
712 if (!utf8_strncasecmp (p_name.string, p_name.length,
713 name.string, name.length))
720 mc_keyword (struct macro_call *mc, const struct macro_token *mt,
721 const struct msg_location *loc)
723 const struct token *token = &mt->token;
724 if (token->type != T_ID)
725 return mc_finished (mc);
727 const struct macro_param *p = macro_find_parameter_by_name (mc->macro,
731 size_t arg_index = p - mc->macro->params;
733 if (mc->args[arg_index])
736 _("Argument %s multiply specified in call to macro %s."),
737 p->name, mc->macro->name);
738 mc->state = MC_ERROR;
743 mc->state = MC_EQUALS;
747 return mc_finished (mc);
751 mc_equals (struct macro_call *mc, const struct macro_token *mt,
752 const struct msg_location *loc)
754 const struct token *token = &mt->token;
757 if (token->type == T_EQUALS)
759 mc->state = mc->param->arg_type == ARG_ENCLOSE ? MC_ENCLOSE : MC_ARG;
763 return mc_expected (mc, mt, loc, &(struct token) { .type = T_EQUALS });
767 macro_call_create__ (const struct macro_set *macros,
768 const struct macro_expansion_stack *stack,
769 const struct macro_expander *me,
770 const struct token *token,
771 struct macro_call **mcp)
773 const struct macro *macro = (token->type == T_ID || token->type == T_MACRO_ID
774 ? macro_set_find (macros, token->string.string)
782 struct macro_call *mc = xmalloc (sizeof *mc);
783 *mc = (struct macro_call) {
787 .state = (!macro->n_params ? MC_FINISHED
788 : !macro->params[0].positional ? MC_KEYWORD
789 : macro->params[0].arg_type == ARG_ENCLOSE ? MC_ENCLOSE
791 .args = macro->n_params ? xcalloc (macro->n_params, sizeof *mc->args) : NULL,
792 .param = macro->params,
798 return mc->state == MC_FINISHED ? 1 : 0;
801 /* If TOKEN is the first token of a call to a macro in MACROS, create a new
802 macro expander, initializes *MCP to it. Returns 0 if more tokens are needed
803 and should be added via macro_call_add() or 1 if the caller should next call
804 macro_call_get_expansion().
806 If TOKEN is not the first token of a macro call, returns -1 and sets *MCP to
809 macro_call_create (const struct macro_set *macros,
810 const struct token *token,
811 struct macro_call **mcp)
813 return macro_call_create__ (macros, NULL, NULL, token, mcp);
817 macro_call_destroy (struct macro_call *mc)
822 for (size_t i = 0; i < mc->macro->n_params; i++)
824 struct macro_tokens *a = mc->args[i];
825 if (a && a != &mc->macro->params[i].def)
827 macro_tokens_uninit (a);
835 /* Adds TOKEN to the collection of tokens in MC that potentially need to be
838 Returns -1 if the tokens added do not actually invoke a macro. The caller
839 should consume the first token without expanding it. (Later tokens might
840 invoke a macro so it's best to feed the second token into a new expander.)
842 Returns 0 if the macro expander needs more tokens, for macro arguments or to
843 decide whether this is actually a macro invocation. The caller should call
844 macro_call_add() again with the next token.
846 Returns a positive number to indicate that the returned number of tokens
847 invoke a macro. The number returned might be less than the number of tokens
848 added because it can take a few tokens of lookahead to determine whether the
849 macro invocation is finished. The caller should call
850 macro_call_get_expansion() to obtain the expansion. */
852 macro_call_add (struct macro_call *mc, const struct macro_token *mt,
853 const struct msg_location *loc)
861 return mc_add_arg (mc, mt, loc);
864 return mc_enclose (mc, mt, loc);
867 return mc_keyword (mc, mt, loc);
870 return mc_equals (mc, mt, loc);
877 /* Macro expansion. */
879 struct macro_expander
881 /* Always available. */
882 const struct macro_set *macros; /* Macros to expand recursively. */
883 enum segmenter_mode segmenter_mode; /* Mode for tokenization. */
884 int nesting_countdown; /* Remaining nesting levels. */
885 const struct macro_expansion_stack *stack; /* Stack for error reporting. */
886 bool *expand; /* May macro calls be expanded? */
887 struct stringi_map *vars; /* Variables from !do and !let. */
889 /* Only nonnull if inside a !DO loop. */
890 bool *break_; /* Set to true to break out of loop. */
892 /* Only nonnull if expanding a macro (and not, say, a macro argument). */
893 const struct macro *macro;
894 struct macro_tokens **args;
898 macro_expand (const struct macro_token *mts, size_t n_mts,
899 const struct macro_expander *, struct macro_tokens *);
902 expand_macro_function (const struct macro_expander *me,
903 const struct macro_token *input, size_t n_input,
904 struct string *output);
906 /* Parses one function argument from the N_INPUT tokens in INPUT
907 Each argument to a macro function is one of:
909 - A quoted string or other single literal token.
911 - An argument to the macro being expanded, e.g. !1 or a named argument.
915 - A function invocation.
917 Each function invocation yields a character sequence to be turned into a
918 sequence of tokens. The case where that character sequence is a single
919 quoted string is an important special case.
922 parse_function_arg (const struct macro_expander *me,
923 const struct macro_token *input, size_t n_input,
926 assert (n_input > 0);
928 const struct token *token = &input[0].token;
929 if (token->type == T_MACRO_ID && me->macro)
931 const struct macro_param *param = macro_find_parameter_by_name (
932 me->macro, token->string);
935 size_t param_idx = param - me->macro->params;
936 macro_tokens_to_syntax (me->args[param_idx], farg, NULL, NULL);
940 if (ss_equals (token->string, ss_cstr ("!*")))
942 for (size_t i = 0; i < me->macro->n_params; i++)
944 if (!me->macro->params[i].positional)
947 ds_put_byte (farg, ' ');
948 macro_tokens_to_syntax (me->args[i], farg, NULL, NULL);
953 const char *var = stringi_map_find__ (me->vars,
954 token->string.string,
955 token->string.length);
958 ds_put_cstr (farg, var);
962 size_t n_function = expand_macro_function (me, input, n_input, farg);
967 ds_put_substring (farg, input[0].syntax);
972 parse_function_args (const struct macro_expander *me,
973 const struct macro_token *mts, size_t n,
974 const char *function,
975 struct string_array *args)
977 if (n < 2 || mts[1].token.type != T_LPAREN)
979 macro_error (me->stack, n > 1 ? &mts[1] : NULL,
980 _("`(' expected following %s."), function);
984 for (size_t i = 2; i < n; )
986 if (mts[i].token.type == T_RPAREN)
989 struct string s = DS_EMPTY_INITIALIZER;
990 i += parse_function_arg (me, mts + i, n - i, &s);
991 string_array_append_nocopy (args, ds_steal_cstr (&s));
995 else if (mts[i].token.type == T_COMMA)
997 else if (mts[i].token.type != T_RPAREN)
999 macro_error (me->stack, &mts[i],
1000 _("`,' or `)' expected in call to macro function %s."),
1006 macro_error (me->stack, NULL, _("Missing `)' in call to macro function %s."),
1012 unquote_string (const char *s, enum segmenter_mode segmenter_mode,
1013 struct string *content)
1015 struct string_lexer slex;
1016 string_lexer_init (&slex, s, strlen (s), segmenter_mode, true);
1018 struct token token1;
1019 if (string_lexer_next (&slex, &token1) != SLR_TOKEN
1020 || token1.type != T_STRING)
1022 token_uninit (&token1);
1026 struct token token2;
1027 if (string_lexer_next (&slex, &token2) != SLR_END)
1029 token_uninit (&token1);
1030 token_uninit (&token2);
1034 ds_put_substring (content, token1.string);
1035 token_uninit (&token1);
1040 unquote_string_in_place (const char *s, enum segmenter_mode segmenter_mode,
1043 ds_init_empty (tmp);
1044 return unquote_string (s, segmenter_mode, tmp) ? ds_cstr (tmp) : s;
1048 parse_integer (const char *s, int *np)
1053 long int n = strtol (s, &tail, 10);
1054 *np = n < INT_MIN ? INT_MIN : n > INT_MAX ? INT_MAX : n;
1055 tail += strspn (tail, CC_SPACES);
1056 return *tail == '\0' && errno != ERANGE && n == *np;
1060 expand_macro_function (const struct macro_expander *me,
1061 const struct macro_token *input, size_t n_input,
1062 struct string *output)
1064 if (!n_input || input[0].token.type != T_MACRO_ID)
1067 struct macro_function
1073 enum macro_function_id
1088 static const struct macro_function mfs[] = {
1089 [MF_BLANKS] = { "!BLANKS", 1, 1 },
1090 [MF_CONCAT] = { "!CONCAT", 1, INT_MAX },
1091 [MF_EVAL] = { "!EVAL", 1, 1 },
1092 [MF_HEAD] = { "!HEAD", 1, 1 },
1093 [MF_INDEX] = { "!INDEX", 2, 2 },
1094 [MF_LENGTH] = { "!LENGTH", 1, 1 },
1095 [MF_NULL] = { "!NULL", 0, 0 },
1096 [MF_QUOTE] = { "!QUOTE", 1, 1 },
1097 [MF_SUBSTR] = { "!SUBSTR", 2, 3 },
1098 [MF_TAIL] = { "!TAIL", 1, 1 },
1099 [MF_UNQUOTE] = { "!UNQUOTE", 1, 1 },
1100 [MF_UPCASE] = { "!UPCASE", 1, 1 },
1103 /* Is this a macro function? */
1104 const struct macro_function *mf;
1105 for (mf = mfs; ; mf++)
1107 if (mf >= mfs + sizeof mfs / sizeof *mfs)
1109 /* Not a macro function. */
1113 if (lex_id_match_n (ss_cstr (mf->name), input[0].token.string, 4))
1117 enum macro_function_id id = mf - mfs;
1121 struct string_array args = STRING_ARRAY_INITIALIZER;
1122 size_t n_consumed = parse_function_args (me, input, n_input, mf->name, &args);
1126 if (args.n < mf->min_args || args.n > mf->max_args)
1128 if (mf->min_args == 1 && mf->max_args == 1)
1129 macro_error (me->stack, NULL,
1130 _("Macro function %s takes one argument (not %zu)."),
1132 else if (mf->min_args == 2 && mf->max_args == 2)
1133 macro_error (me->stack, NULL,
1134 _("Macro function %s takes two arguments (not %zu)."),
1136 else if (mf->min_args == 2 && mf->max_args == 3)
1137 macro_error (me->stack, NULL,
1138 _("Macro function %s takes two or three arguments "
1141 else if (mf->min_args == 1 && mf->max_args == INT_MAX)
1142 macro_error (me->stack, NULL,
1143 _("Macro function %s needs at least one argument."),
1153 ds_put_format (output, "%zu", strlen (args.strings[0]));
1159 if (!parse_integer (args.strings[0], &n))
1161 macro_error (me->stack, NULL,
1162 _("Argument to !BLANKS must be non-negative integer "
1163 "(not \"%s\")."), args.strings[0]);
1164 string_array_destroy (&args);
1168 ds_put_byte_multiple (output, ' ', n);
1173 for (size_t i = 0; i < args.n; i++)
1174 if (!unquote_string (args.strings[i], me->segmenter_mode, output))
1175 ds_put_cstr (output, args.strings[i]);
1181 const char *s = unquote_string_in_place (args.strings[0],
1182 me->segmenter_mode, &tmp);
1184 struct macro_tokens mts = { .n = 0 };
1185 macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode,
1188 ds_put_substring (output, mts.mts[0].syntax);
1189 macro_tokens_uninit (&mts);
1196 const char *haystack = args.strings[0];
1197 const char *needle = strstr (haystack, args.strings[1]);
1198 ds_put_format (output, "%zu", needle ? needle - haystack + 1 : 0);
1203 if (unquote_string (args.strings[0], me->segmenter_mode, NULL))
1204 ds_put_cstr (output, args.strings[0]);
1207 ds_extend (output, strlen (args.strings[0]) + 2);
1208 ds_put_byte (output, '\'');
1209 for (const char *p = args.strings[0]; *p; p++)
1212 ds_put_byte (output, '\'');
1213 ds_put_byte (output, *p);
1215 ds_put_byte (output, '\'');
1222 if (!parse_integer (args.strings[1], &start) || start < 1)
1224 macro_error (me->stack, NULL,
1225 _("Second argument of !SUBSTR must be "
1226 "positive integer (not \"%s\")."),
1228 string_array_destroy (&args);
1232 int count = INT_MAX;
1233 if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0))
1235 macro_error (me->stack, NULL,
1236 _("Third argument of !SUBSTR must be "
1237 "non-negative integer (not \"%s\")."),
1239 string_array_destroy (&args);
1243 struct substring s = ss_cstr (args.strings[0]);
1244 ds_put_substring (output, ss_substr (s, start - 1, count));
1251 const char *s = unquote_string_in_place (args.strings[0],
1252 me->segmenter_mode, &tmp);
1254 struct macro_tokens mts = { .n = 0 };
1255 macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode,
1259 struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 };
1260 macro_tokens_to_syntax (&tail, output, NULL, NULL);
1262 macro_tokens_uninit (&mts);
1268 if (!unquote_string (args.strings[0], me->segmenter_mode, output))
1269 ds_put_cstr (output, args.strings[0]);
1275 const char *s = unquote_string_in_place (args.strings[0],
1276 me->segmenter_mode, &tmp);
1277 char *upper = utf8_to_upper (s);
1278 ds_put_cstr (output, upper);
1286 struct macro_tokens mts = { .n = 0 };
1287 macro_tokens_from_string__ (&mts, ss_cstr (args.strings[0]),
1288 me->segmenter_mode, me->stack);
1289 struct macro_tokens exp = { .n = 0 };
1290 struct macro_expansion_stack stack = {
1294 struct macro_expander subme = *me;
1295 subme.break_ = NULL;
1296 subme.stack = &stack;
1298 macro_expand (mts.mts, mts.n, &subme, &exp);
1299 macro_tokens_to_syntax (&exp, output, NULL, NULL);
1300 macro_tokens_uninit (&exp);
1301 macro_tokens_uninit (&mts);
1309 string_array_destroy (&args);
1313 static char *macro_evaluate_or (const struct macro_expander *me,
1314 const struct macro_token **tokens,
1315 const struct macro_token *end);
1318 macro_evaluate_literal (const struct macro_expander *me,
1319 const struct macro_token **tokens,
1320 const struct macro_token *end)
1322 const struct macro_token *p = *tokens;
1325 if (p->token.type == T_LPAREN)
1328 char *value = macro_evaluate_or (me, &p, end);
1331 if (p >= end || p->token.type != T_RPAREN)
1334 macro_error (me->stack, p < end ? p : NULL,
1335 _("Expecting ')' in macro expression."));
1342 else if (p->token.type == T_RPAREN)
1344 macro_error (me->stack, p, _("Expecting literal or function invocation "
1345 "in macro expression."));
1349 struct string function_output = DS_EMPTY_INITIALIZER;
1350 size_t function_consumed = parse_function_arg (me, p, end - p,
1352 struct string unquoted = DS_EMPTY_INITIALIZER;
1353 if (unquote_string (ds_cstr (&function_output), me->segmenter_mode,
1356 ds_swap (&function_output, &unquoted);
1357 ds_destroy (&unquoted);
1359 *tokens = p + function_consumed;
1360 return ds_steal_cstr (&function_output);
1363 /* Returns true if MT is valid as a macro operator. Only operators written as
1364 symbols (e.g. <>) are usable in macro expressions, not operator written as
1365 letters (e.g. EQ). */
1367 is_macro_operator (const struct macro_token *mt)
1369 return mt->syntax.length > 0 && !c_isalpha (mt->syntax.string[0]);
1372 static enum token_type
1373 parse_relational_op (const struct macro_token *mt)
1375 switch (mt->token.type)
1385 return is_macro_operator (mt) ? mt->token.type : T_STOP;
1388 return (ss_equals_case (mt->token.string, ss_cstr ("!EQ")) ? T_EQ
1389 : ss_equals_case (mt->token.string, ss_cstr ("!NE")) ? T_NE
1390 : ss_equals_case (mt->token.string, ss_cstr ("!LT")) ? T_LT
1391 : ss_equals_case (mt->token.string, ss_cstr ("!GT")) ? T_GT
1392 : ss_equals_case (mt->token.string, ss_cstr ("!LE")) ? T_LE
1393 : ss_equals_case (mt->token.string, ss_cstr ("!GE")) ? T_GE
1402 macro_evaluate_relational (const struct macro_expander *me,
1403 const struct macro_token **tokens,
1404 const struct macro_token *end)
1406 const struct macro_token *p = *tokens;
1407 char *lhs = macro_evaluate_literal (me, &p, end);
1411 enum token_type op = p >= end ? T_STOP : parse_relational_op (p);
1419 char *rhs = macro_evaluate_literal (me, &p, end);
1426 struct string lhs_tmp, rhs_tmp;
1427 int cmp = strcmp (unquote_string_in_place (lhs, me->segmenter_mode,
1429 unquote_string_in_place (rhs, me->segmenter_mode,
1431 ds_destroy (&lhs_tmp);
1432 ds_destroy (&rhs_tmp);
1437 bool b = (op == T_EQUALS || op == T_EQ ? !cmp
1439 : op == T_LT ? cmp < 0
1440 : op == T_GT ? cmp > 0
1441 : op == T_LE ? cmp <= 0
1442 : /* T_GE */ cmp >= 0);
1445 return xstrdup (b ? "1" : "0");
1449 macro_evaluate_not (const struct macro_expander *me,
1450 const struct macro_token **tokens,
1451 const struct macro_token *end)
1453 const struct macro_token *p = *tokens;
1455 unsigned int negations = 0;
1457 && (ss_equals_case (p->syntax, ss_cstr ("!NOT"))
1458 || ss_equals (p->syntax, ss_cstr ("~"))))
1464 char *operand = macro_evaluate_relational (me, &p, end);
1465 if (!operand || !negations)
1471 bool b = strcmp (operand, "0") ^ (negations & 1);
1474 return xstrdup (b ? "1" : "0");
1478 macro_evaluate_and (const struct macro_expander *me,
1479 const struct macro_token **tokens,
1480 const struct macro_token *end)
1482 const struct macro_token *p = *tokens;
1483 char *lhs = macro_evaluate_not (me, &p, end);
1488 && (ss_equals_case (p->syntax, ss_cstr ("!AND"))
1489 || ss_equals (p->syntax, ss_cstr ("&"))))
1492 char *rhs = macro_evaluate_not (me, &p, end);
1499 bool b = strcmp (lhs, "0") && strcmp (rhs, "0");
1502 lhs = xstrdup (b ? "1" : "0");
1509 macro_evaluate_or (const struct macro_expander *me,
1510 const struct macro_token **tokens,
1511 const struct macro_token *end)
1513 const struct macro_token *p = *tokens;
1514 char *lhs = macro_evaluate_and (me, &p, end);
1519 && (ss_equals_case (p->syntax, ss_cstr ("!OR"))
1520 || ss_equals (p->syntax, ss_cstr ("|"))))
1523 char *rhs = macro_evaluate_and (me, &p, end);
1530 bool b = strcmp (lhs, "0") || strcmp (rhs, "0");
1533 lhs = xstrdup (b ? "1" : "0");
1540 macro_evaluate_expression (const struct macro_token **tokens, size_t n_tokens,
1541 const struct macro_expander *me)
1543 return macro_evaluate_or (me, tokens, *tokens + n_tokens);
1547 macro_evaluate_number (const struct macro_token **tokens, size_t n_tokens,
1548 const struct macro_expander *me,
1551 char *s = macro_evaluate_expression (tokens, n_tokens, me);
1555 struct macro_tokens mts = { .n = 0 };
1556 macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, me->stack);
1557 if (mts.n != 1 || !token_is_number (&mts.mts[0].token))
1559 macro_error (me->stack, mts.n > 0 ? &mts.mts[0] : NULL,
1560 _("Macro expression must evaluate to "
1561 "a number (not \"%s\")."), s);
1563 macro_tokens_uninit (&mts);
1567 *number = token_number (&mts.mts[0].token);
1569 macro_tokens_uninit (&mts);
1573 static const struct macro_token *
1574 find_ifend_clause (const struct macro_token *p, const struct macro_token *end)
1577 for (; p < end; p++)
1579 if (p->token.type != T_MACRO_ID)
1582 if (ss_equals_case (p->token.string, ss_cstr ("!IF")))
1584 else if (lex_id_match_n (p->token.string, ss_cstr ("!IFEND"), 4))
1590 else if (lex_id_match_n (p->token.string, ss_cstr ("!ELSE"), 4)
1598 macro_expand_if (const struct macro_token *tokens, size_t n_tokens,
1599 const struct macro_expander *me,
1600 struct macro_tokens *exp)
1602 const struct macro_token *p = tokens;
1603 const struct macro_token *end = tokens + n_tokens;
1605 if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!IF")))
1609 char *result = macro_evaluate_expression (&p, end - p, me);
1612 bool b = strcmp (result, "0");
1616 || p->token.type != T_MACRO_ID
1617 || !lex_id_match_n (p->token.string, ss_cstr ("!THEN"), 4))
1619 macro_error (me->stack, p < end ? p : NULL,
1620 _("!THEN expected in macro !IF construct."));
1624 const struct macro_token *start_then = p + 1;
1625 const struct macro_token *end_then = find_ifend_clause (start_then, end);
1628 macro_error (me->stack, NULL,
1629 _("!ELSE or !IFEND expected in macro !IF construct."));
1633 const struct macro_token *start_else, *end_if;
1634 if (lex_id_match_n (end_then->token.string, ss_cstr ("!ELSE"), 4))
1636 start_else = end_then + 1;
1637 end_if = find_ifend_clause (start_else, end);
1639 || !lex_id_match_n (end_if->token.string, ss_cstr ("!IFEND"), 4))
1641 macro_error (me->stack, end_if ? end_if : NULL,
1642 _("!IFEND expected in macro !IF construct."));
1652 const struct macro_token *start;
1657 n = end_then - start_then;
1659 else if (start_else)
1662 n = end_if - start_else;
1672 struct macro_expansion_stack stack = {
1676 struct macro_expander subme = *me;
1677 subme.stack = &stack;
1678 macro_expand (start, n, &subme, exp);
1680 return (end_if + 1) - tokens;
1684 macro_parse_let (const struct macro_token *tokens, size_t n_tokens,
1685 const struct macro_expander *me)
1687 const struct macro_token *p = tokens;
1688 const struct macro_token *end = tokens + n_tokens;
1690 if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!LET")))
1694 if (p >= end || p->token.type != T_MACRO_ID)
1696 macro_error (me->stack, p < end ? p : NULL,
1697 _("Expected macro variable name following !LET."));
1700 const struct substring var_name = p->token.string;
1701 if (is_macro_keyword (var_name)
1702 || macro_find_parameter_by_name (me->macro, var_name))
1704 macro_error (me->stack, p < end ? p : NULL,
1705 _("Cannot use argument name or macro keyword "
1706 "\"%.*s\" as !LET variable."),
1707 (int) var_name.length, var_name.string);
1712 if (p >= end || p->token.type != T_EQUALS)
1714 macro_error (me->stack, p < end ? p : NULL,
1715 _("Expected `=' following !LET."));
1720 char *value = macro_evaluate_expression (&p, end - p, me);
1724 stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name), value);
1728 static const struct macro_token *
1729 find_doend (const struct macro_expansion_stack *stack,
1730 const struct macro_token *p, const struct macro_token *end)
1733 for (; p < end; p++)
1735 if (p->token.type != T_MACRO_ID)
1738 if (ss_equals_case (p->token.string, ss_cstr ("!DO")))
1740 else if (lex_id_match_n (p->token.string, ss_cstr ("!DOEND"), 4))
1747 macro_error (stack, NULL, _("Missing !DOEND."));
1752 macro_expand_do (const struct macro_token *tokens, size_t n_tokens,
1753 const struct macro_expander *me,
1754 struct macro_tokens *exp)
1756 const struct macro_token *p = tokens;
1757 const struct macro_token *end = tokens + n_tokens;
1759 if (p >= end || !ss_equals_case (p->token.string, ss_cstr ("!DO")))
1763 if (p >= end || p->token.type != T_MACRO_ID)
1765 macro_error (me->stack, p < end ? p : NULL,
1766 _("Expected macro variable name following !DO."));
1769 const struct substring var_name = p->token.string;
1770 if (is_macro_keyword (var_name)
1771 || macro_find_parameter_by_name (me->macro, var_name))
1773 macro_error (me->stack, p, _("Cannot use argument name or macro "
1774 "keyword as !DO variable."));
1779 struct macro_expansion_stack substack = {
1783 bool break_ = false;
1784 struct macro_expander subme = *me;
1785 subme.break_ = &break_;
1786 subme.stack = &substack;
1788 int miterate = settings_get_miterate ();
1789 if (p < end && p->token.type == T_MACRO_ID
1790 && ss_equals_case (p->token.string, ss_cstr ("!IN")))
1793 char *list = macro_evaluate_expression (&p, end - p, &subme);
1797 struct macro_tokens items = { .n = 0 };
1798 macro_tokens_from_string__ (&items, ss_cstr (list), me->segmenter_mode,
1802 const struct macro_token *do_end = find_doend (subme.stack, p, end);
1805 macro_tokens_uninit (&items);
1809 for (size_t i = 0; i < items.n && !break_; i++)
1813 macro_error (&substack, NULL,
1814 _("!DO loop over list exceeded "
1815 "maximum number of iterations %d. "
1816 "(Use SET MITERATE to change the limit.)"),
1820 stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name),
1821 ss_xstrdup (items.mts[i].syntax));
1823 macro_expand (p, do_end - p, &subme, exp);
1825 return do_end - tokens + 1;
1827 else if (p < end && p->token.type == T_EQUALS)
1831 if (!macro_evaluate_number (&p, end - p, &subme, &first))
1834 if (p >= end || p->token.type != T_MACRO_ID
1835 || !ss_equals_case (p->token.string, ss_cstr ("!TO")))
1837 macro_error (subme.stack, p < end ? p : NULL,
1838 _("Expected !TO in numerical !DO loop."));
1844 if (!macro_evaluate_number (&p, end - p, &subme, &last))
1848 if (p < end && p->token.type == T_MACRO_ID
1849 && ss_equals_case (p->token.string, ss_cstr ("!BY")))
1852 if (!macro_evaluate_number (&p, end - p, &subme, &by))
1857 macro_error (subme.stack, NULL, _("!BY value cannot be zero."));
1862 const struct macro_token *do_end = find_doend (subme.stack, p, end);
1865 if ((by > 0 && first <= last) || (by < 0 && first >= last))
1868 for (double index = first;
1869 by > 0 ? (index <= last) : (index >= last) && !break_;
1874 macro_error (subme.stack, NULL,
1875 _("Numerical !DO loop exceeded "
1876 "maximum number of iterations %d. "
1877 "(Use SET MITERATE to change the limit.)"),
1882 char index_s[DBL_BUFSIZE_BOUND];
1883 c_dtoastr (index_s, sizeof index_s, 0, 0, index);
1884 stringi_map_replace_nocopy (me->vars, ss_xstrdup (var_name),
1887 macro_expand (p, do_end - p, &subme, exp);
1891 return do_end - tokens + 1;
1895 macro_error (me->stack, p < end ? p : NULL,
1896 _("Expected `=' or !IN in !DO loop."));
1902 macro_expand_arg__ (const struct macro_expander *me, size_t idx,
1903 struct macro_tokens *exp)
1905 const struct macro_param *param = &me->macro->params[idx];
1906 const struct macro_tokens *arg = me->args[idx];
1908 if (*me->expand && param->expand_arg)
1910 struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
1911 struct macro_expansion_stack stack = {
1912 .name = param->name,
1915 struct macro_expander subme = {
1916 .macros = me->macros,
1919 .segmenter_mode = me->segmenter_mode,
1920 .expand = me->expand,
1923 .nesting_countdown = me->nesting_countdown,
1926 macro_expand (arg->mts, arg->n, &subme, exp);
1927 stringi_map_destroy (&vars);
1930 for (size_t i = 0; i < arg->n; i++)
1931 macro_tokens_add (exp, &arg->mts[i]);
1935 macro_expand_arg (const struct token *token, const struct macro_expander *me,
1936 struct macro_tokens *exp)
1938 if (!me || token->type != T_MACRO_ID)
1941 /* Macro arguments. */
1944 const struct macro_param *param = macro_find_parameter_by_name (
1945 me->macro, token->string);
1948 macro_expand_arg__ (me, param - me->macro->params, exp);
1951 else if (ss_equals (token->string, ss_cstr ("!*")))
1953 for (size_t j = 0; j < me->macro->n_params; j++)
1954 macro_expand_arg__ (me, j, exp);
1959 /* Variables set by !DO or !LET. */
1960 const char *var = stringi_map_find__ (me->vars, token->string.string,
1961 token->string.length);
1964 macro_tokens_from_string__ (exp, ss_cstr (var),
1965 me->segmenter_mode, me->stack);
1973 macro_expand__ (const struct macro_token *mts, size_t n,
1974 const struct macro_expander *me,
1975 struct macro_tokens *exp)
1977 const struct token *token = &mts[0].token;
1979 /* Recursive macro calls. */
1982 struct macro_call *submc;
1983 int n_call = macro_call_create__ (me->macros, me->stack, me,
1985 for (size_t j = 1; !n_call; j++)
1987 const struct macro_token endcmd
1988 = { .token = { .type = T_ENDCMD } };
1989 n_call = macro_call_add (submc, j < n ? &mts[j] : &endcmd, NULL);
1993 struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
1994 struct macro_expansion_stack stack = {
1995 .name = submc->macro->name,
1996 .location = submc->macro->location,
1999 struct macro_expander subme = {
2000 .macros = submc->macros,
2001 .macro = submc->macro,
2002 .args = submc->args,
2003 .segmenter_mode = me->segmenter_mode,
2004 .expand = me->expand,
2007 .nesting_countdown = me->nesting_countdown - 1,
2010 const struct macro_tokens *body = &submc->macro->body;
2011 macro_expand (body->mts, body->n, &subme, exp);
2012 macro_call_destroy (submc);
2013 stringi_map_destroy (&vars);
2017 macro_call_destroy (submc);
2020 if (token->type != T_MACRO_ID)
2022 macro_tokens_add (exp, &mts[0]);
2026 /* Parameters and macro variables. */
2027 if (macro_expand_arg (token, me, exp))
2030 /* Macro functions. */
2031 struct string function_output = DS_EMPTY_INITIALIZER;
2032 size_t n_function = expand_macro_function (me, mts, n, &function_output);
2035 macro_tokens_from_string__ (exp, function_output.ss,
2036 me->segmenter_mode, me->stack);
2037 ds_destroy (&function_output);
2042 size_t n_if = macro_expand_if (mts, n, me, exp);
2046 size_t n_let = macro_parse_let (mts, n, me);
2050 size_t n_do = macro_expand_do (mts, n, me, exp);
2054 if (lex_id_match_n (token->string, ss_cstr ("!break"), 4))
2059 macro_error (me->stack, &mts[0], _("!BREAK outside !DO."));
2061 else if (lex_id_match_n (token->string, ss_cstr ("!onexpand"), 4))
2063 else if (lex_id_match_n (token->string, ss_cstr ("!offexpand"), 4))
2064 *me->expand = false;
2066 macro_tokens_add (exp, &mts[0]);
2071 macro_expand (const struct macro_token *mts, size_t n,
2072 const struct macro_expander *me,
2073 struct macro_tokens *exp)
2075 if (me->nesting_countdown <= 0)
2077 macro_error (me->stack, NULL, _("Maximum nesting level %d exceeded. "
2078 "(Use SET MNEST to change the limit.)"),
2079 settings_get_mnest ());
2080 for (size_t i = 0; i < n; i++)
2081 macro_tokens_add (exp, &mts[i]);
2085 for (size_t i = 0; i < n; )
2087 if (me->break_ && *me->break_)
2090 size_t consumed = macro_expand__ (&mts[i], n - i, me, exp);
2091 assert (consumed > 0 && i + consumed <= n);
2097 macro_call_expand (struct macro_call *mc, enum segmenter_mode segmenter_mode,
2098 const struct msg_location *call_loc,
2099 struct macro_tokens *exp)
2101 assert (mc->state == MC_FINISHED);
2104 struct stringi_map vars = STRINGI_MAP_INITIALIZER (vars);
2105 struct macro_expansion_stack stack0 = {
2106 .location = call_loc,
2108 struct macro_expansion_stack stack1 = {
2110 .name = mc->macro->name,
2111 .location = mc->macro->location,
2113 struct macro_expander me = {
2114 .macros = mc->macros,
2117 .segmenter_mode = segmenter_mode,
2121 .nesting_countdown = settings_get_mnest (),
2125 const struct macro_tokens *body = &mc->macro->body;
2126 macro_expand (body->mts, body->n, &me, exp);
2128 stringi_map_destroy (&vars);