Macro arguments and the !length function work.
[pspp] / src / language / lexer / macro.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2021 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "language/lexer/macro.h"
20
21 #include <stdlib.h>
22
23 #include "data/settings.h"
24 #include "language/lexer/segment.h"
25 #include "language/lexer/scan.h"
26 #include "libpspp/assertion.h"
27 #include "libpspp/i18n.h"
28 #include "libpspp/message.h"
29 #include "libpspp/str.h"
30
31 #include "gettext.h"
32 #define _(msgid) gettext (msgid)
33
34 void
35 macro_destroy (struct macro *m)
36 {
37   if (!m)
38     return;
39
40   free (m->name);
41   for (size_t i = 0; i < m->n_params; i++)
42     {
43       struct macro_param *p = &m->params[i];
44       free (p->name);
45
46       tokens_uninit (&p->def);
47
48       switch (p->arg_type)
49         {
50         case ARG_N_TOKENS:
51           break;
52
53         case ARG_CHAREND:
54           token_destroy (&p->charend);
55           break;
56
57         case ARG_ENCLOSE:
58           token_destroy (&p->enclose[0]);
59           token_destroy (&p->enclose[1]);
60           break;
61
62         case ARG_CMDEND:
63           break;
64         }
65     }
66   free (m->params);
67   ss_dealloc (&m->body);
68   tokens_uninit (&m->body_tokens);
69   free (m);
70 }
71 \f
72 struct macro_set *
73 macro_set_create (void)
74 {
75   struct macro_set *set = xmalloc (sizeof *set);
76   *set = (struct macro_set) {
77     .macros = HMAP_INITIALIZER (set->macros),
78   };
79   return set;
80 }
81
82 void
83 macro_set_destroy (struct macro_set *set)
84 {
85   if (!set)
86     return;
87
88   struct macro *macro, *next;
89   HMAP_FOR_EACH_SAFE (macro, next, struct macro, hmap_node, &set->macros)
90     {
91       hmap_delete (&set->macros, &macro->hmap_node);
92       macro_destroy (macro);
93     }
94   hmap_destroy (&set->macros);
95   free (set);
96 }
97
98 static unsigned int
99 hash_macro_name (const char *name)
100 {
101   return utf8_hash_case_string (name, 0);
102 }
103
104 static struct macro *
105 macro_set_find__ (struct macro_set *set, const char *name)
106 {
107   struct macro *macro;
108   HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
109                            hash_macro_name (name), &set->macros)
110     if (!utf8_strcasecmp (macro->name, name))
111       return macro;
112
113   return NULL;
114 }
115
116 const struct macro *
117 macro_set_find (const struct macro_set *set, const char *name)
118 {
119   return macro_set_find__ (CONST_CAST (struct macro_set *, set), name);
120 }
121
122 /* Adds M to SET.  M replaces any existing macro with the same name.  Takes
123    ownership of M. */
124 void
125 macro_set_add (struct macro_set *set, struct macro *m)
126 {
127   struct macro *victim = macro_set_find__ (set, m->name);
128   if (victim)
129     {
130       hmap_delete (&set->macros, &victim->hmap_node);
131       macro_destroy (victim);
132     }
133
134   hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
135 }
136 \f
137 enum me_state
138   {
139     /* Error state. */
140     ME_ERROR,
141
142     /* Accumulating tokens in me->params toward the end of any type of
143        argument. */
144     ME_ARG,
145
146     /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
147     ME_ENCLOSE,
148
149     /* Expecting a keyword for a keyword argument. */
150     ME_KEYWORD,
151
152     /* Expecting an equal sign for a keyword argument. */
153     ME_EQUALS,
154   };
155
156
157 struct macro_expander
158   {
159     const struct macro_set *macros;
160
161     enum me_state state;
162     size_t n_tokens;
163
164     const struct macro *macro;
165     struct tokens **args;
166     const struct macro_param *param;
167   };
168
169 static int
170 me_finished (struct macro_expander *me)
171 {
172   for (size_t i = 0; i < me->macro->n_params; i++)
173     if (!me->args[i])
174       {
175         me->args[i] = xmalloc (sizeof *me->args[i]);
176         tokens_copy (me->args[i], &me->macro->params[i].def);
177       }
178   return me->n_tokens;
179 }
180
181 static int
182 me_next_arg (struct macro_expander *me)
183 {
184   if (!me->param)
185     {
186       assert (!me->macro->n_params);
187       return me_finished (me);
188     }
189   else if (me->param->positional)
190     {
191       me->param++;
192       if (me->param >= &me->macro->params[me->macro->n_params])
193         return me_finished (me);
194       else
195         {
196           me->state = me->param->positional ? ME_ARG : ME_KEYWORD;
197           return 0;
198         }
199     }
200   else
201     {
202       for (size_t i = 0; i < me->macro->n_params; i++)
203         if (!me->args[i])
204           {
205             me->state = ME_KEYWORD;
206             return 0;
207           }
208       return me_finished (me);
209     }
210 }
211
212 static int
213 me_error (struct macro_expander *me)
214 {
215   me->state = ME_ERROR;
216   return -1;
217 }
218
219 static int
220 me_add_arg (struct macro_expander *me, const struct token *token)
221 {
222   if (token->type == T_STOP)
223     {
224       msg (SE, _("Unexpected end of file reading argument %s "
225                  "to macro %s."), me->param->name, me->macro->name);
226
227       return me_error (me);
228     }
229
230   me->n_tokens++;
231
232   const struct macro_param *p = me->param;
233   struct tokens **argp = &me->args[p - me->macro->params];
234   if (!*argp)
235     *argp = xzalloc (sizeof **argp);
236   struct tokens *arg = *argp;
237   if (p->arg_type == ARG_N_TOKENS)
238     {
239       tokens_add (arg, token);
240       if (arg->n >= p->n_tokens)
241         return me_next_arg (me);
242       return 0;
243     }
244   else if (p->arg_type == ARG_CMDEND)
245     {
246       if (token->type == T_ENDCMD || token->type == T_STOP)
247         return me_next_arg (me);
248       tokens_add (arg, token);
249       return 0;
250     }
251   else
252     {
253       const struct token *end
254         = p->arg_type == ARG_CMDEND ? &p->charend : &p->enclose[1];
255       if (token_equal (token, end))
256         return me_next_arg (me);
257       tokens_add (arg, token);
258       return 0;
259     }
260 }
261
262 static int
263 me_expected (struct macro_expander *me, const struct token *token,
264              const struct token *wanted)
265 {
266   char *actual = token_to_string (token);
267   if (!actual)
268     actual = xstrdup ("<eof>");
269   char *expected = token_to_string (wanted);
270   msg (SE, _("Found `%s' while expecting `%s' reading argument %s "
271              "to macro %s."),
272        actual, expected, me->param->name, me->macro->name);
273   free (expected);
274   free (actual);
275
276   return me_error (me);
277 }
278
279 static int
280 me_enclose (struct macro_expander *me, const struct token *token)
281 {
282   me->n_tokens++;
283
284   if (token_equal (&me->param->enclose[0], token))
285     {
286       me->state = ME_ARG;
287       return 0;
288     }
289
290   return me_expected (me, token, &me->param->enclose[0]);
291 }
292
293 static const struct macro_param *
294 macro_find_parameter_by_name (const struct macro *m, struct substring name)
295 {
296   for (size_t i = 0; i < m->n_params; i++)
297     {
298       const struct macro_param *p = &m->params[i];
299       struct substring p_name = ss_cstr (p->name);
300       if (!utf8_strncasecmp (p_name.string, p_name.length,
301                              name.string, name.length))
302         return p;
303     }
304   return NULL;
305 }
306
307 static int
308 me_keyword (struct macro_expander *me, const struct token *token)
309 {
310   if (token->type != T_ID)
311     return me_finished (me);
312
313   const struct macro_param *p = macro_find_parameter_by_name (me->macro,
314                                                               token->string);
315   if (p)
316     {
317       size_t arg_index = p - me->macro->params;
318       me->param = p;
319       if (me->args[arg_index])
320         {
321           msg (SE,
322                _("Argument %s multiply specified in call to macro %s."),
323                p->name, me->macro->name);
324           return me_error (me);
325         }
326
327       me->n_tokens++;
328       me->state = ME_EQUALS;
329       return 0;
330     }
331
332   return me_finished (me);
333 }
334
335 static int
336 me_equals (struct macro_expander *me, const struct token *token)
337 {
338   me->n_tokens++;
339
340   if (token->type == T_EQUALS)
341     {
342       me->state = ME_ARG;
343       return 0;
344     }
345
346   const struct token equals = { .type = T_EQUALS };
347   return me_expected (me, token, &equals);
348 }
349
350 int
351 macro_expander_create (const struct macro_set *macros,
352                        const struct token *token,
353                        struct macro_expander **mep)
354 {
355   *mep = NULL;
356   if (macro_set_is_empty (macros))
357     return -1;
358   if (token->type != T_ID && token->type != T_MACRO_ID)
359     return -1;
360
361   const struct macro *macro = macro_set_find (macros, token->string.string);
362   if (!macro)
363     return -1;
364
365   struct macro_expander *me = xmalloc (sizeof *me);
366   *me = (struct macro_expander) {
367     .macros = macros,
368     .n_tokens = 1,
369     .macro = macro,
370   };
371   *mep = me;
372
373   if (!macro->n_params)
374     return 1;
375   else
376     {
377       me->state = macro->params[0].positional ? ME_ARG : ME_KEYWORD;
378       me->args = xcalloc (macro->n_params, sizeof *me->args);
379       me->param = macro->params;
380       return 0;
381     }
382 }
383
384 void
385 macro_expander_destroy (struct macro_expander *me)
386 {
387   if (!me)
388     return;
389
390   for (size_t i = 0; i < me->macro->n_params; i++)
391     if (me->args[i])
392       {
393         tokens_uninit (me->args[i]);
394         free (me->args[i]);
395       }
396   free (me->args);
397   free (me);
398 }
399
400 /* Adds TOKEN to the collection of tokens in ME that potentially need to be
401    macro expanded.
402
403    Returns -1 if the tokens added do not actually invoke a macro.  The caller
404    should consume the first token without expanding it.
405
406    Returns 0 if the macro expander needs more tokens, for macro arguments or to
407    decide whether this is actually a macro invocation.  The caller should call
408    macro_expander_add() again with the next token.
409
410    Returns a positive number to indicate that the returned number of tokens
411    invoke a macro.  The number returned might be less than the number of tokens
412    added because it can take a few tokens of lookahead to determine whether the
413    macro invocation is finished.  The caller should call
414    macro_expander_get_expansion() to obtain the expansion. */
415 int
416 macro_expander_add (struct macro_expander *me, const struct token *token)
417 {
418   switch (me->state)
419     {
420     case ME_ERROR:
421       return -1;
422
423     case ME_ARG:
424       return me_add_arg (me, token);
425
426     case ME_ENCLOSE:
427       return me_enclose (me, token);
428
429     case ME_KEYWORD:
430       return me_keyword (me, token);
431
432     case ME_EQUALS:
433       return me_equals (me, token);
434
435     default:
436       NOT_REACHED ();
437     }
438 }
439
440 static void
441 macro_expand (const struct tokens *tokens, int nesting_countdown,
442               const struct macro_set *macros, const struct macro_expander *me,
443               bool *expand, struct tokens *exp)
444 {
445   if (nesting_countdown <= 0)
446     {
447       printf ("maximum nesting level exceeded\n");
448       for (size_t i = 0; i < tokens->n; i++)
449         tokens_add (exp, &tokens->tokens[i]);
450       return;
451     }
452
453   for (size_t i = 0; i < tokens->n; i++)
454     {
455       const struct token *token = &tokens->tokens[i];
456       if (token->type == T_MACRO_ID && me)
457         {
458           const struct macro_param *param = macro_find_parameter_by_name (
459             me->macro, token->string);
460           if (param)
461             {
462               printf ("expand %s to:\n", param->name);
463               const struct tokens *arg = me->args[param - me->macro->params];
464               tokens_print (arg, stdout);
465               if (*expand && param->expand_arg)
466                 macro_expand (arg, nesting_countdown, macros, NULL, expand, exp);
467               else
468                 for (size_t i = 0; i < arg->n; i++)
469                   tokens_add (exp, &arg->tokens[i]);
470               continue;
471             }
472         }
473
474       if (*expand)
475         {
476           struct macro_expander *subme;
477           int retval = macro_expander_create (macros, token, &subme);
478           for (size_t j = 1; !retval; j++)
479             {
480               static const struct token stop = { .type = T_STOP };
481               retval = macro_expander_add (
482                 subme, i + j < tokens->n ? &tokens->tokens[i + j] : &stop);
483             }
484           if (retval > 0)
485             {
486               i += retval - 1;
487               macro_expand (&subme->macro->body_tokens, nesting_countdown - 1,
488                             macros, subme, expand, exp);
489               macro_expander_destroy (subme);
490               continue;
491             }
492
493           macro_expander_destroy (subme);
494         }
495
496       if (token->type != T_MACRO_ID)
497         {
498           tokens_add (exp, token);
499           continue;
500         }
501
502       if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
503         *expand = true;
504       else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
505         *expand = false;
506       else if (ss_equals_case (token->string, ss_cstr ("!length")))
507         {
508           if (i + 1 >= tokens->n || tokens->tokens[i + 1].type != T_LPAREN)
509             {
510               printf ("`(' expected following !LENGTH'\n");
511               continue;
512             }
513
514           int n_parens = 1;
515           size_t j;
516           for (j = i + 2; n_parens && j < tokens->n; j++)
517             if (tokens->tokens[j].type == T_LPAREN)
518               n_parens++;
519             else if (tokens->tokens[j].type == T_RPAREN)
520               n_parens--;
521           if (n_parens)
522             {
523               printf ("Unbalanced parentheses in !LENGTH argument.\n");
524               continue;
525             }
526
527           size_t lparen_idx = i + 1;
528           size_t rparen_idx = j - 1;
529           const struct tokens unexpanded_args = {
530             .tokens = &tokens->tokens[lparen_idx + 1],
531             .n = rparen_idx - (lparen_idx + 1),
532           };
533           struct tokens args = { .n = 0 };
534           macro_expand (&unexpanded_args, nesting_countdown, macros,
535                         me, expand, &args);
536
537           if (args.n != 1)
538             {
539               tokens_uninit (&args);
540               printf ("!LENGTH argument must be a single token (not %zu)\n", args.n);
541               continue;
542             }
543
544           char *s = token_to_string (&args.tokens[0]);
545           struct token t = { .type = T_POS_NUM, .number = strlen (s) };
546           tokens_add (exp, &t);
547           free (s);
548
549           tokens_uninit (&args);
550
551           i = rparen_idx;
552         }
553       else
554         tokens_add (exp, token);
555     }
556 }
557
558
559 void
560 macro_expander_get_expansion (struct macro_expander *me, struct tokens *exp)
561 {
562   for (size_t i = 0; i < me->macro->n_params; i++)
563     {
564       printf ("%s:\n", me->macro->params[i].name);
565       tokens_print (me->args[i], stdout);
566     }
567
568   bool expand = true;
569   macro_expand (&me->macro->body_tokens, settings_get_mnest (),
570                 me->macros, me, &expand, exp);
571
572   printf ("expansion:\n");
573   tokens_print (exp, stdout);
574 }
575