05e3b45b832f7117cfb50c912d42d829dd1f71ca
[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 <limits.h>
22 #include <stdlib.h>
23
24 #include "data/settings.h"
25 #include "language/lexer/segment.h"
26 #include "language/lexer/scan.h"
27 #include "libpspp/assertion.h"
28 #include "libpspp/i18n.h"
29 #include "libpspp/message.h"
30 #include "libpspp/str.h"
31
32 #include "gettext.h"
33 #define _(msgid) gettext (msgid)
34
35 void
36 macro_token_copy (struct macro_token *dst, const struct macro_token *src)
37 {
38   token_copy (&dst->token, &src->token);
39   ss_alloc_substring (&dst->representation, src->representation);
40 }
41
42 void
43 macro_token_uninit (struct macro_token *mt)
44 {
45   token_uninit (&mt->token);
46   ss_dealloc (&mt->representation);
47 }
48
49 void
50 macro_tokens_copy (struct macro_tokens *dst, const struct macro_tokens *src)
51 {
52   *dst = (struct macro_tokens) {
53     .mts = xmalloc (src->n * sizeof *dst->mts),
54     .n = src->n,
55     .allocated = src->n,
56   };
57   for (size_t i = 0; i < src->n; i++)
58     macro_token_copy (&dst->mts[i], &src->mts[i]);
59 }
60
61 void
62 macro_tokens_uninit (struct macro_tokens *mts)
63 {
64   for (size_t i = 0; i < mts->n; i++)
65     macro_token_uninit (&mts->mts[i]);
66   free (mts->mts);
67 }
68
69 struct macro_token *
70 macro_tokens_add_uninit (struct macro_tokens *mts)
71 {
72   if (mts->n >= mts->allocated)
73     mts->mts = x2nrealloc (mts->mts, &mts->allocated, sizeof *mts->mts);
74   return &mts->mts[mts->n++];
75 }
76
77 void
78 macro_tokens_add (struct macro_tokens *mts, const struct macro_token *mt)
79 {
80   macro_token_copy (macro_tokens_add_uninit (mts), mt);
81 }
82
83 void
84 macro_tokens_print (const struct macro_tokens *mts, FILE *stream)
85 {
86   for (size_t i = 0; i < mts->n; i++)
87     token_print (&mts->mts[i].token, stream);
88 }
89
90 void
91 macro_destroy (struct macro *m)
92 {
93   if (!m)
94     return;
95
96   free (m->name);
97   for (size_t i = 0; i < m->n_params; i++)
98     {
99       struct macro_param *p = &m->params[i];
100       free (p->name);
101
102       macro_tokens_uninit (&p->def);
103
104       switch (p->arg_type)
105         {
106         case ARG_N_TOKENS:
107           break;
108
109         case ARG_CHAREND:
110           token_uninit (&p->charend);
111           break;
112
113         case ARG_ENCLOSE:
114           token_uninit (&p->enclose[0]);
115           token_uninit (&p->enclose[1]);
116           break;
117
118         case ARG_CMDEND:
119           break;
120         }
121     }
122   free (m->params);
123   macro_tokens_uninit (&m->body);
124   free (m);
125 }
126 \f
127 struct macro_set *
128 macro_set_create (void)
129 {
130   struct macro_set *set = xmalloc (sizeof *set);
131   *set = (struct macro_set) {
132     .macros = HMAP_INITIALIZER (set->macros),
133   };
134   return set;
135 }
136
137 void
138 macro_set_destroy (struct macro_set *set)
139 {
140   if (!set)
141     return;
142
143   struct macro *macro, *next;
144   HMAP_FOR_EACH_SAFE (macro, next, struct macro, hmap_node, &set->macros)
145     {
146       hmap_delete (&set->macros, &macro->hmap_node);
147       macro_destroy (macro);
148     }
149   hmap_destroy (&set->macros);
150   free (set);
151 }
152
153 static unsigned int
154 hash_macro_name (const char *name)
155 {
156   return utf8_hash_case_string (name, 0);
157 }
158
159 static struct macro *
160 macro_set_find__ (struct macro_set *set, const char *name)
161 {
162   struct macro *macro;
163   HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
164                            hash_macro_name (name), &set->macros)
165     if (!utf8_strcasecmp (macro->name, name))
166       return macro;
167
168   return NULL;
169 }
170
171 const struct macro *
172 macro_set_find (const struct macro_set *set, const char *name)
173 {
174   return macro_set_find__ (CONST_CAST (struct macro_set *, set), name);
175 }
176
177 /* Adds M to SET.  M replaces any existing macro with the same name.  Takes
178    ownership of M. */
179 void
180 macro_set_add (struct macro_set *set, struct macro *m)
181 {
182   struct macro *victim = macro_set_find__ (set, m->name);
183   if (victim)
184     {
185       hmap_delete (&set->macros, &victim->hmap_node);
186       macro_destroy (victim);
187     }
188
189   hmap_insert (&set->macros, &m->hmap_node, hash_macro_name (m->name));
190 }
191 \f
192 enum me_state
193   {
194     /* Error state. */
195     ME_ERROR,
196
197     /* Accumulating tokens in me->params toward the end of any type of
198        argument. */
199     ME_ARG,
200
201     /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
202     ME_ENCLOSE,
203
204     /* Expecting a keyword for a keyword argument. */
205     ME_KEYWORD,
206
207     /* Expecting an equal sign for a keyword argument. */
208     ME_EQUALS,
209   };
210
211
212 struct macro_expander
213   {
214     const struct macro_set *macros;
215
216     enum me_state state;
217     size_t n_tokens;
218
219     const struct macro *macro;
220     struct macro_tokens **args;
221     const struct macro_param *param;
222   };
223
224 static int
225 me_finished (struct macro_expander *me)
226 {
227   for (size_t i = 0; i < me->macro->n_params; i++)
228     if (!me->args[i])
229       {
230         me->args[i] = xmalloc (sizeof *me->args[i]);
231         macro_tokens_copy (me->args[i], &me->macro->params[i].def);
232       }
233   return me->n_tokens;
234 }
235
236 static int
237 me_next_arg (struct macro_expander *me)
238 {
239   if (!me->param)
240     {
241       assert (!me->macro->n_params);
242       return me_finished (me);
243     }
244   else if (me->param->positional)
245     {
246       me->param++;
247       if (me->param >= &me->macro->params[me->macro->n_params])
248         return me_finished (me);
249       else
250         {
251           me->state = me->param->positional ? ME_ARG : ME_KEYWORD;
252           return 0;
253         }
254     }
255   else
256     {
257       for (size_t i = 0; i < me->macro->n_params; i++)
258         if (!me->args[i])
259           {
260             me->state = ME_KEYWORD;
261             return 0;
262           }
263       return me_finished (me);
264     }
265 }
266
267 static int
268 me_error (struct macro_expander *me)
269 {
270   me->state = ME_ERROR;
271   return -1;
272 }
273
274 static int
275 me_add_arg (struct macro_expander *me, const struct macro_token *mt)
276 {
277   const struct token *token = &mt->token;
278   if (token->type == T_STOP)
279     {
280       msg (SE, _("Unexpected end of file reading argument %s "
281                  "to macro %s."), me->param->name, me->macro->name);
282
283       return me_error (me);
284     }
285
286   me->n_tokens++;
287
288   const struct macro_param *p = me->param;
289   struct macro_tokens **argp = &me->args[p - me->macro->params];
290   if (!*argp)
291     *argp = xzalloc (sizeof **argp);
292   struct macro_tokens *arg = *argp;
293   if (p->arg_type == ARG_N_TOKENS)
294     {
295       macro_tokens_add (arg, mt);
296       if (arg->n >= p->n_tokens)
297         return me_next_arg (me);
298       return 0;
299     }
300   else if (p->arg_type == ARG_CMDEND)
301     {
302       if (token->type == T_ENDCMD || token->type == T_STOP)
303         return me_next_arg (me);
304       macro_tokens_add (arg, mt);
305       return 0;
306     }
307   else
308     {
309       const struct token *end
310         = p->arg_type == ARG_CMDEND ? &p->charend : &p->enclose[1];
311       if (token_equal (token, end))
312         return me_next_arg (me);
313       macro_tokens_add (arg, mt);
314       return 0;
315     }
316 }
317
318 static int
319 me_expected (struct macro_expander *me, const struct macro_token *actual,
320              const struct token *expected)
321 {
322   const struct substring actual_s
323     = (actual->representation.length ? actual->representation
324        : ss_cstr (_("<end of input>")));
325   char *expected_s = token_to_string (expected);
326   msg (SE, _("Found `%.*s' while expecting `%s' reading argument %s "
327              "to macro %s."),
328        (int) actual_s.length, actual_s.string, expected_s,
329        me->param->name, me->macro->name);
330   free (expected_s);
331
332   return me_error (me);
333 }
334
335 static int
336 me_enclose (struct macro_expander *me, const struct macro_token *mt)
337 {
338   const struct token *token = &mt->token;
339   me->n_tokens++;
340
341   if (token_equal (&me->param->enclose[0], token))
342     {
343       me->state = ME_ARG;
344       return 0;
345     }
346
347   return me_expected (me, mt, &me->param->enclose[0]);
348 }
349
350 static const struct macro_param *
351 macro_find_parameter_by_name (const struct macro *m, struct substring name)
352 {
353   for (size_t i = 0; i < m->n_params; i++)
354     {
355       const struct macro_param *p = &m->params[i];
356       struct substring p_name = ss_cstr (p->name);
357       if (!utf8_strncasecmp (p_name.string, p_name.length,
358                              name.string, name.length))
359         return p;
360     }
361   return NULL;
362 }
363
364 static int
365 me_keyword (struct macro_expander *me, const struct macro_token *mt)
366 {
367   const struct token *token = &mt->token;
368   if (token->type != T_ID)
369     return me_finished (me);
370
371   const struct macro_param *p = macro_find_parameter_by_name (me->macro,
372                                                               token->string);
373   if (p)
374     {
375       size_t arg_index = p - me->macro->params;
376       me->param = p;
377       if (me->args[arg_index])
378         {
379           msg (SE,
380                _("Argument %s multiply specified in call to macro %s."),
381                p->name, me->macro->name);
382           return me_error (me);
383         }
384
385       me->n_tokens++;
386       me->state = ME_EQUALS;
387       return 0;
388     }
389
390   return me_finished (me);
391 }
392
393 static int
394 me_equals (struct macro_expander *me, const struct macro_token *mt)
395 {
396   const struct token *token = &mt->token;
397   me->n_tokens++;
398
399   if (token->type == T_EQUALS)
400     {
401       me->state = ME_ARG;
402       return 0;
403     }
404
405   return me_expected (me, mt, &(struct token) { .type = T_EQUALS });
406 }
407
408 int
409 macro_expander_create (const struct macro_set *macros,
410                        const struct token *token,
411                        struct macro_expander **mep)
412 {
413   *mep = NULL;
414   if (macro_set_is_empty (macros))
415     return -1;
416   if (token->type != T_ID && token->type != T_MACRO_ID)
417     return -1;
418
419   const struct macro *macro = macro_set_find (macros, token->string.string);
420   if (!macro)
421     return -1;
422
423   struct macro_expander *me = xmalloc (sizeof *me);
424   *me = (struct macro_expander) {
425     .macros = macros,
426     .n_tokens = 1,
427     .macro = macro,
428   };
429   *mep = me;
430
431   if (!macro->n_params)
432     return 1;
433   else
434     {
435       me->state = macro->params[0].positional ? ME_ARG : ME_KEYWORD;
436       me->args = xcalloc (macro->n_params, sizeof *me->args);
437       me->param = macro->params;
438       return 0;
439     }
440 }
441
442 void
443 macro_expander_destroy (struct macro_expander *me)
444 {
445   if (!me)
446     return;
447
448   for (size_t i = 0; i < me->macro->n_params; i++)
449     if (me->args[i])
450       {
451         macro_tokens_uninit (me->args[i]);
452         free (me->args[i]);
453       }
454   free (me->args);
455   free (me);
456 }
457
458 /* Adds TOKEN to the collection of tokens in ME that potentially need to be
459    macro expanded.
460
461    Returns -1 if the tokens added do not actually invoke a macro.  The caller
462    should consume the first token without expanding it.
463
464    Returns 0 if the macro expander needs more tokens, for macro arguments or to
465    decide whether this is actually a macro invocation.  The caller should call
466    macro_expander_add() again with the next token.
467
468    Returns a positive number to indicate that the returned number of tokens
469    invoke a macro.  The number returned might be less than the number of tokens
470    added because it can take a few tokens of lookahead to determine whether the
471    macro invocation is finished.  The caller should call
472    macro_expander_get_expansion() to obtain the expansion. */
473 int
474 macro_expander_add (struct macro_expander *me, const struct macro_token *mt)
475 {
476   switch (me->state)
477     {
478     case ME_ERROR:
479       return -1;
480
481     case ME_ARG:
482       return me_add_arg (me, mt);
483
484     case ME_ENCLOSE:
485       return me_enclose (me, mt);
486
487     case ME_KEYWORD:
488       return me_keyword (me, mt);
489
490     case ME_EQUALS:
491       return me_equals (me, mt);
492
493     default:
494       NOT_REACHED ();
495     }
496 }
497
498 /* Each argument to a macro function is one of:
499
500        - A quoted string or other single literal token.
501
502        - An argument to the macro being expanded, e.g. !1 or a named argument.
503
504        - !*.
505
506        - A function invocation.
507
508    Each function invocation yields a character sequence to be turned into a
509    sequence of tokens.  The case where that character sequence is a single
510    quoted string is an important special case.
511 */
512 struct parse_macro_function_ctx
513   {
514     struct macro_token *input;
515     size_t n_input;
516     int nesting_countdown;
517     const struct macro_set *macros;
518     const struct macro_expander *me;
519     bool *expand;
520   };
521
522 static void
523 macro_expand (const struct macro_tokens *,
524               int nesting_countdown, const struct macro_set *,
525               const struct macro_expander *, bool *expand, struct macro_tokens *exp);
526
527 static bool
528 expand_macro_function (struct parse_macro_function_ctx *ctx,
529                        struct macro_token *output,
530                        size_t *input_consumed);
531
532 static size_t
533 parse_function_arg (struct parse_macro_function_ctx *ctx,
534                     size_t i, struct macro_token *farg)
535 {
536   struct macro_token *tokens = ctx->input;
537   const struct token *token = &tokens[i].token;
538   if (token->type == T_MACRO_ID)
539     {
540       const struct macro_param *param = macro_find_parameter_by_name (
541         ctx->me->macro, token->string);
542       if (param)
543         {
544           size_t param_idx = param - ctx->me->macro->params;
545           const struct macro_tokens *marg = ctx->me->args[param_idx];
546           if (marg->n == 1)
547             macro_token_copy (farg, &marg->mts[0]);
548           else
549             {
550               struct string s = DS_EMPTY_INITIALIZER;
551               for (size_t i = 0; i < marg->n; i++)
552                 {
553                   if (i)
554                     ds_put_byte (&s, ' ');
555                   ds_put_substring (&s, marg->mts[i].representation);
556                 }
557
558               struct substring s_copy;
559               ss_alloc_substring (&s_copy, s.ss);
560
561               *farg = (struct macro_token) {
562                 .token = { .type = T_MACRO_ID, .string = s.ss },
563                 .representation = s_copy,
564               };
565             }
566           return 1;
567         }
568
569       struct parse_macro_function_ctx subctx = {
570         .input = &ctx->input[i],
571         .n_input = ctx->n_input - i,
572         .nesting_countdown = ctx->nesting_countdown,
573         .macros = ctx->macros,
574         .me = ctx->me,
575         .expand = ctx->expand,
576       };
577       size_t subinput_consumed;
578       if (expand_macro_function (&subctx, farg, &subinput_consumed))
579         return subinput_consumed;
580     }
581
582   macro_token_copy (farg, &tokens[i]);
583   return 1;
584 }
585
586 static bool
587 parse_macro_function (struct parse_macro_function_ctx *ctx,
588                       struct macro_tokens *args,
589                       struct substring function,
590                       int min_args, int max_args,
591                       size_t *input_consumed)
592 {
593   struct macro_token *tokens = ctx->input;
594   size_t n_tokens = ctx->n_input;
595
596   if (!n_tokens
597       || tokens[0].token.type != T_MACRO_ID
598       || !ss_equals_case (tokens[0].token.string, function))
599     return false;
600
601   if (n_tokens < 2 || tokens[1].token.type != T_LPAREN)
602     {
603       printf ("`(' expected following %s'\n", function.string);
604       return false;
605     }
606
607   *args = (struct macro_tokens) { .n = 0 };
608
609   for (size_t i = 2;; )
610     {
611       if (i >= n_tokens)
612         goto unexpected_end;
613       if (tokens[i].token.type == T_RPAREN)
614         {
615           *input_consumed = i + 1;
616           if (args->n < min_args || args->n > max_args)
617             {
618               printf ("Wrong number of arguments to %s.\n", function.string);
619               goto error;
620             }
621           return true;
622         }
623
624       i += parse_function_arg (ctx, i, macro_tokens_add_uninit (args));
625       if (i >= n_tokens)
626         goto unexpected_end;
627
628       if (tokens[i].token.type == T_COMMA)
629         i++;
630       else if (tokens[i].token.type != T_RPAREN)
631         {
632           printf ("Expecting `,' or `)' in %s invocation.", function.string);
633           goto error;
634         }
635     }
636
637 unexpected_end:
638   printf ("Missing closing parenthesis in arguments to %s.\n",
639           function.string);
640   /* Fall through. */
641 error:
642   macro_tokens_uninit (args);
643   return false;
644 }
645
646 static bool
647 expand_macro_function (struct parse_macro_function_ctx *ctx,
648                        struct macro_token *output,
649                        size_t *input_consumed)
650 {
651   struct macro_tokens args;
652
653   if (parse_macro_function (ctx, &args, ss_cstr ("!length"), 1, 1,
654                             input_consumed))
655     {
656       size_t length = args.mts[0].representation.length;
657       *output = (struct macro_token) {
658         .token = { .type = T_POS_NUM, .number = length },
659         .representation = ss_cstr (xasprintf ("%zu", length)),
660       };
661     }
662   else if (parse_macro_function (ctx, &args, ss_cstr ("!blanks"), 1, 1,
663                                  input_consumed))
664     {
665       /* XXX this isn't right, it might be a character string containing a
666          positive integer, e.g. via !CONCAT. */
667       if (args.mts[0].token.type != T_POS_NUM)
668         {
669           printf ("argument to !BLANKS must be positive integer\n");
670           macro_token_uninit (output);
671           return false;
672         }
673
674       struct string s = DS_EMPTY_INITIALIZER;
675       ds_put_byte_multiple (&s, ' ', args.mts[0].token.number);
676
677       *output = (struct macro_token) {
678         .token = { .type = T_ID, .string = s.ss },
679         .representation = s.ss,
680       };
681     }
682   else if (parse_macro_function (ctx, &args, ss_cstr ("!concat"), 1, INT_MAX,
683                                  input_consumed))
684     {
685       struct string s;
686       bool all_strings = true;
687       for (size_t i = 0; i < args.n; i++)
688         {
689           if (args.mts[i].token.type == T_STRING)
690             ds_put_substring (&s, args.mts[i].token.string);
691           else
692             {
693               all_strings = false;
694               ds_put_substring (&s, args.mts[i].representation);
695             }
696         }
697
698       if (all_strings)
699         {
700           *output = (struct macro_token) {
701             .token = { .type = T_STRING, .string = s.ss },
702           };
703           output->representation = ss_cstr (token_to_string (&output->token));
704         }
705       else
706         {
707           *output = (struct macro_token) {
708             .token = { .type = T_MACRO_ID /*XXX*/, .string = s.ss },
709           };
710           ss_alloc_substring (&output->representation, s.ss);
711         }
712     }
713   else
714     return false;
715
716   macro_tokens_uninit (&args);
717   return true;
718 }
719
720 static void
721 macro_expand (const struct macro_tokens *mts,
722               int nesting_countdown, const struct macro_set *macros,
723               const struct macro_expander *me, bool *expand,
724               struct macro_tokens *exp)
725 {
726   if (nesting_countdown <= 0)
727     {
728       printf ("maximum nesting level exceeded\n");
729       for (size_t i = 0; i < mts->n; i++)
730         macro_tokens_add (exp, &mts->mts[i]);
731       return;
732     }
733
734   for (size_t i = 0; i < mts->n; i++)
735     {
736       const struct macro_token *mt = &mts->mts[i];
737       const struct token *token = &mt->token;
738       if (token->type == T_MACRO_ID && me)
739         {
740           const struct macro_param *param = macro_find_parameter_by_name (
741             me->macro, token->string);
742           if (param)
743             {
744               const struct macro_tokens *arg = me->args[param - me->macro->params];
745               //macro_tokens_print (arg, stdout);
746               if (*expand && param->expand_arg)
747                 macro_expand (arg, nesting_countdown, macros, NULL, expand, exp);
748               else
749                 for (size_t i = 0; i < arg->n; i++)
750                   macro_tokens_add (exp, &arg->mts[i]);
751               continue;
752             }
753         }
754
755       if (*expand)
756         {
757           struct macro_expander *subme;
758           int retval = macro_expander_create (macros, token, &subme);
759           for (size_t j = 1; !retval; j++)
760             {
761               const struct macro_token stop = { .token = { .type = T_STOP } };
762               retval = macro_expander_add (
763                 subme, i + j < mts->n ? &mts->mts[i + j] : &stop);
764             }
765           if (retval > 0)
766             {
767               i += retval - 1;
768               macro_expand (&subme->macro->body, nesting_countdown - 1, macros,
769                             subme, expand, exp);
770               macro_expander_destroy (subme);
771               continue;
772             }
773
774           macro_expander_destroy (subme);
775         }
776
777       if (token->type != T_MACRO_ID)
778         {
779           macro_tokens_add (exp, mt);
780           continue;
781         }
782
783       /* Maybe each arg should just be a string, either a quoted string or a
784          non-quoted string containing tokens. */
785       struct parse_macro_function_ctx ctx = {
786         .input = &mts->mts[i],
787         .n_input = mts->n - i,
788         .nesting_countdown = nesting_countdown,
789         .macros = macros,
790         .me = me,
791         .expand = expand,
792       };
793       struct macro_token function_output;
794       size_t function_consumed;
795       if (expand_macro_function (&ctx, &function_output, &function_consumed))
796         {
797           i += function_consumed - 1;
798
799           
800
801           continue;
802         }
803
804       if (ss_equals_case (token->string, ss_cstr ("!onexpand")))
805         *expand = true;
806       else if (ss_equals_case (token->string, ss_cstr ("!offexpand")))
807         *expand = false;
808       else
809         macro_tokens_add (exp, mt);
810     }
811 }
812
813 void
814 macro_expander_get_expansion (struct macro_expander *me, struct macro_tokens *exp)
815 {
816 #if 0
817   for (size_t i = 0; i < me->macro->n_params; i++)
818     {
819       printf ("%s:\n", me->macro->params[i].name);
820       macro_tokens_print (me->args[i], stdout);
821     }
822 #endif
823
824   bool expand = true;
825   macro_expand (&me->macro->body, settings_get_mnest (),
826                 me->macros, me, &expand, exp);
827
828 #if 0
829   printf ("expansion:\n");
830   macro_tokens_print (exp, stdout);
831 #endif
832 }
833