7726e4c3ecd41e86ca08cb3cbc91c16c27f1c34b
[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 struct parse_macro_function_ctx
441   {
442     const struct tokens *tokens;
443     size_t *idx;
444     struct tokens *args;
445     int nesting_countdown;
446     const struct macro_set *macros;
447     const struct macro_expander *me;
448     bool *expand;
449   };
450
451 static void
452 macro_expand (const struct tokens *tokens, int nesting_countdown,
453               const struct macro_set *macros, const struct macro_expander *me,
454               bool *expand, struct tokens *exp);
455
456 static bool
457 parse_macro_function (struct parse_macro_function_ctx *ctx,
458                       struct substring function,
459                       int min_args, int max_args)
460 {
461   const struct token *tokens = ctx->tokens->tokens;
462   size_t n_tokens = ctx->tokens->n;
463
464   if (!ss_equals_case (tokens[0].string, function))
465     return false;
466
467   size_t lparen_idx = *ctx->idx + 1;
468   if (lparen_idx >= n_tokens || tokens[lparen_idx].type != T_LPAREN)
469     {
470       printf ("`(' expected following %s'\n", function.string);
471       return false;
472     }
473
474   *ctx->args = (struct tokens) { .n = 0 };
475
476   size_t i = lparen_idx + 1;
477   for (size_t j = i; ; j++)
478     {
479       if (j >= n_tokens)
480         {
481           printf ("Missing closing parenthesis in arguments to %s.\n",
482                   function.string);
483           goto error;
484         }
485
486       int type = tokens[j].type;
487       if (type == T_LPAREN)
488         {
489           int paren_nesting_level = 1;
490           do
491             {
492               j++;
493               if (j >= n_tokens)
494                 {
495                   printf ("Missing closing parenthesis in argument %zu to %s.\n",
496                           ctx->args->n + 1, function.string);
497                   goto error;
498                 }
499               if (tokens[j].type == T_LPAREN)
500                 paren_nesting_level++;
501               else if (tokens[j].type == T_RPAREN)
502                 paren_nesting_level--;
503             }
504           while (paren_nesting_level != 0);
505         }
506       else if (type == T_RPAREN || type == T_COMMA)
507         {
508           const struct tokens unexpanded_arg = {
509             .tokens = CONST_CAST (struct token *, &tokens[i]),
510             .n = j - i,
511           };
512           struct tokens expanded_arg = { .n = 0 };
513           macro_expand (&unexpanded_arg, ctx->nesting_countdown, ctx->macros,
514                         ctx->me, ctx->expand, &expanded_arg);
515
516           if (expanded_arg.n != 1)
517             {
518               printf ("argument %zu to %s must be a single token "
519                       "(not %zu tokens)\n", ctx->args->n + 1, function.string,
520                       expanded_arg.n);
521               tokens_uninit (&expanded_arg);
522               goto error;
523             }
524
525           tokens_add (ctx->args, &expanded_arg.tokens[0]);
526           tokens_uninit (&expanded_arg);
527
528           i = j + 1;
529           if (type == T_RPAREN)
530             break;
531         }
532     }
533
534   if (ctx->args->n < min_args || ctx->args->n > max_args)
535     {
536       printf ("Wrong number of argument to %s.\n", function.string);
537       goto error;
538     }
539   *ctx->idx = i;
540   return true;
541
542 error:
543   tokens_uninit (ctx->args);
544   return false;
545 }
546
547 static void
548 macro_expand (const struct tokens *tokens, int nesting_countdown,
549               const struct macro_set *macros, const struct macro_expander *me,
550               bool *expand, struct tokens *exp)
551 {
552   if (nesting_countdown <= 0)
553     {
554       printf ("maximum nesting level exceeded\n");
555       for (size_t i = 0; i < tokens->n; i++)
556         tokens_add (exp, &tokens->tokens[i]);
557       return;
558     }
559
560   for (size_t i = 0; i < tokens->n; i++)
561     {
562       const struct token *token = &tokens->tokens[i];
563       if (token->type == T_MACRO_ID && me)
564         {
565           const struct macro_param *param = macro_find_parameter_by_name (
566             me->macro, token->string);
567           if (param)
568             {
569               printf ("expand %s to:\n", param->name);
570               const struct tokens *arg = me->args[param - me->macro->params];
571               tokens_print (arg, stdout);
572               if (*expand && param->expand_arg)
573                 macro_expand (arg, nesting_countdown, macros, NULL, expand, exp);
574               else
575                 for (size_t i = 0; i < arg->n; i++)
576                   tokens_add (exp, &arg->tokens[i]);
577               continue;
578             }
579         }
580
581       if (*expand)
582         {
583           struct macro_expander *subme;
584           int retval = macro_expander_create (macros, token, &subme);
585           for (size_t j = 1; !retval; j++)
586             {
587               static const struct token stop = { .type = T_STOP };
588               retval = macro_expander_add (
589                 subme, i + j < tokens->n ? &tokens->tokens[i + j] : &stop);
590             }
591           if (retval > 0)
592             {
593               i += retval - 1;
594               macro_expand (&subme->macro->body_tokens, nesting_countdown - 1,
595                             macros, subme, expand, exp);
596               macro_expander_destroy (subme);
597               continue;
598             }
599
600           macro_expander_destroy (subme);
601         }
602
603       if (token->type != T_MACRO_ID)
604         {
605           tokens_add (exp, token);
606           continue;
607         }
608
609 #if 0
610       struct macro_function
611         {
612           const char *name;
613           int min_args;
614           int max_args;
615         };
616       static const struct macro_function functions[] = {
617         { "!length", 1, 1 },
618         { "!concat", 1, INT_MAX },
619         { "!substr", 2, 3 },
620         { "!index", 2, 2 },
621         { "!head", 1, 1 },
622         { "!tail", 1, 1 },
623         { "!quote", 1, 1 },
624         { "!unquote", 1, 1 },
625         { "!upcase", 1, 1 },
626         { "!blanks", 1, 1 },
627         { "!eval", 1, 1 },
628       };
629 #endif
630       struct tokens args;
631       struct parse_macro_function_ctx ctx = {
632         .tokens = tokens,
633         .idx = &i,
634         .args = &args,
635         .nesting_countdown = nesting_countdown,
636         .macros = macros,
637         .me = me,
638         .expand = expand,
639       };
640       if (parse_macro_function (&ctx, ss_cstr ("!length"), 1, 1))
641         {
642           char *s = token_to_string (&args.tokens[0]);
643           struct token t = { .type = T_POS_NUM, .number = strlen (s) };
644           tokens_add (exp, &t);
645           free (s);
646
647           tokens_uninit (&args);
648         }
649       else if (parse_macro_function (&ctx, ss_cstr ("!blanks"), 1, 1))
650         {
651           if (args.tokens[0].type != T_POS_NUM)
652             printf ("argument to !BLANKS must be positive integer\n");
653           else
654             {
655               struct string s = DS_EMPTY_INITIALIZER;
656               ds_put_byte_multiple (&s, ' ', args.tokens[0].number);
657               struct token t = { .type = T_ID, .string = s.ss };
658               tokens_add (exp, &t);
659               ds_destroy (&s);
660             }
661           tokens_uninit (&args);
662         }
663       else if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
664         *expand = true;
665       else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
666         *expand = false;
667       else
668         tokens_add (exp, token);
669     }
670 }
671
672
673 void
674 macro_expander_get_expansion (struct macro_expander *me, struct tokens *exp)
675 {
676   for (size_t i = 0; i < me->macro->n_params; i++)
677     {
678       printf ("%s:\n", me->macro->params[i].name);
679       tokens_print (me->args[i], stdout);
680     }
681
682   bool expand = true;
683   macro_expand (&me->macro->body_tokens, settings_get_mnest (),
684                 me->macros, me, &expand, exp);
685
686   printf ("expansion:\n");
687   tokens_print (exp, stdout);
688 }
689