98320ae6d97a7daa2ac28ff3b9cc93fdaf2c5b59
[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 "language/lexer/segment.h"
24 #include "language/lexer/scan.h"
25 #include "libpspp/assertion.h"
26 #include "libpspp/i18n.h"
27 #include "libpspp/message.h"
28 #include "libpspp/str.h"
29
30 #include "gettext.h"
31 #define _(msgid) gettext (msgid)
32
33 void
34 macro_destroy (struct macro *m)
35 {
36   if (!m)
37     return;
38
39   free (m->name);
40   for (size_t i = 0; i < m->n_params; i++)
41     {
42       struct macro_param *p = &m->params[i];
43       free (p->name);
44
45       tokens_uninit (&p->def);
46
47       switch (p->arg_type)
48         {
49         case ARG_N_TOKENS:
50           break;
51
52         case ARG_CHAREND:
53           token_destroy (&p->charend);
54           break;
55
56         case ARG_ENCLOSE:
57           token_destroy (&p->enclose[0]);
58           token_destroy (&p->enclose[1]);
59           break;
60
61         case ARG_CMDEND:
62           break;
63         }
64     }
65   free (m->params);
66   ss_dealloc (&m->body);
67   free (m);
68 }
69 \f
70 const struct macro *
71 macro_set_find (const struct macro_set *set, const char *name)
72 {
73   struct macro *macro;
74
75   HMAP_FOR_EACH_WITH_HASH (macro, struct macro, hmap_node,
76                            utf8_hash_case_string (name, 0), &set->macros)
77     {
78       if (!utf8_strcasecmp (macro->name, name))
79         return macro;
80     }
81
82   return NULL;
83 }
84 \f
85 enum me_state
86   {
87     ME_START,
88
89     /* Accumulating tokens in me->params toward the end of any type of
90        argument. */
91     ME_ARG,
92
93     /* Expecting the opening delimiter of an ARG_ENCLOSE argument. */
94     ME_ENCLOSE,
95
96     /* Expecting a keyword for a keyword argument. */
97     ME_KEYWORD,
98
99     /* Expecting an equal sign for a keyword argument. */
100     ME_EQUALS,
101   };
102
103
104 struct macro_expander
105   {
106     const struct macro_set *macros;
107
108     enum me_state state;
109     size_t n_tokens;
110
111     const struct macro *macro;
112     struct tokens **args;
113     size_t arg_index;
114   };
115
116 static int
117 me_finished (struct macro_expander *me)
118 {
119   for (size_t i = 0; i < me->macro->n_params; i++)
120     if (!me->args[i])
121       {
122         me->args[i] = xmalloc (sizeof *me->args[i]);
123         tokens_copy (me->args[i], &me->macro->params[i].def);
124       }
125   return me->n_tokens;
126 }
127
128 static int
129 me_next_arg (struct macro_expander *me)
130 {
131   if (me->arg_index >= me->macro->n_params)
132     {
133       assert (!me->macro->n_params);
134       return me_finished (me);
135     }
136   else if (!me->macro->params[me->arg_index].name)
137     {
138       me->arg_index++;
139       if (me->arg_index >= me->macro->n_params)
140         return me_finished (me);
141       else
142         {
143           if (!me->macro->params[me->arg_index].name)
144             me->state = ME_ARG;
145           else
146             me->state = ME_KEYWORD;
147           return 0;
148         }
149     }
150   else
151     {
152       for (size_t i = 0; i < me->macro->n_params; i++)
153         if (!me->args[i])
154           {
155             me->state = ME_KEYWORD;
156             return 0;
157           }
158       return me_finished (me);
159     }
160 }
161
162 static int
163 me_add_start (struct macro_expander *me, const struct token *token)
164 {
165   if (token->type != T_ID && token->type != T_MACRO_ID)
166     return -1;
167
168   me->macro = macro_set_find (me->macros, token->string.string);
169   if (!me->macro)
170     return -1;
171
172   me->n_tokens = 1;
173   me->args = xcalloc (me->macro->n_params, sizeof *me->args);
174   me->arg_index = 0;
175   return me_next_arg (me);
176 }
177
178 static int
179 me_error (struct macro_expander *me)
180 {
181   me->state = ME_START;
182   return -1;
183 }
184
185 static int
186 me_add_arg (struct macro_expander *me, const struct token *token)
187 {
188   const struct macro_param *p = &me->macro->params[me->arg_index];
189   if (token->type == T_STOP)
190     {
191       char *param_name = (p->name
192                           ? xstrdup (p->name)
193                           : xasprintf ("%zu", me->arg_index));
194       msg (SE, _("Unexpected end of file reading argument %s "
195                  "to macro %s."), param_name, me->macro->name);
196       free (param_name);
197
198       return me_error (me);
199     }
200
201   me->n_tokens++;
202
203   struct tokens **argp = &me->args[me->arg_index];
204   if (!*argp)
205     *argp = xzalloc (sizeof **argp);
206   struct tokens *arg = *argp;
207   if (p->arg_type == ARG_N_TOKENS)
208     {
209       tokens_add (arg, token);
210       if (arg->n >= p->n_tokens)
211         return me_next_arg (me);
212       return 0;
213     }
214   else if (p->arg_type == ARG_CMDEND)
215     {
216       if (token->type == T_ENDCMD || token->type == T_STOP)
217         return me_next_arg (me);
218       tokens_add (arg, token);
219       return 0;
220     }
221   else
222     {
223       const struct token *end
224         = p->arg_type == ARG_CMDEND ? &p->charend : &p->enclose[1];
225       if (token_equal (token, end))
226         return me_next_arg (me);
227       tokens_add (arg, token);
228       return 0;
229     }
230 }
231
232 static int
233 me_expected (struct macro_expander *me, const struct token *token,
234              const struct token *wanted)
235 {
236   const struct macro_param *p = &me->macro->params[me->arg_index];
237   char *param_name = (p->name
238                       ? xstrdup (p->name)
239                       : xasprintf ("%zu", me->arg_index));
240   char *actual = token_to_string (token);
241   if (!actual)
242     actual = xstrdup ("<eof>");
243   char *expected = token_to_string (wanted);
244   msg (SE, _("Found `%s' while expecting `%s' reading argument %s "
245              "to macro %s."),
246        actual, expected, param_name, me->macro->name);
247   free (expected);
248   free (actual);
249   free (param_name);
250
251   return me_error (me);
252 }
253
254 static int
255 me_enclose (struct macro_expander *me, const struct token *token)
256 {
257   me->n_tokens++;
258
259   const struct macro_param *p = &me->macro->params[me->arg_index];
260   if (token_equal (&p->enclose[0], token))
261     {
262       me->state = ME_ARG;
263       return 0;
264     }
265
266   return me_expected (me, token, &p->enclose[0]);
267 }
268
269 static int
270 me_keyword (struct macro_expander *me, const struct token *token)
271 {
272   if (token->type != T_ID)
273     return me_finished (me);
274
275   for (size_t i = 0; i < me->macro->n_params; i++)
276     {
277       const struct macro_param *p = &me->macro->params[i];
278       if (p->name && ss_equals_case (ss_cstr (p->name), token->string))
279         {
280           me->arg_index = i;
281           if (me->args[i])
282             {
283               msg (SE,
284                    _("Argument %s multiply specified in call to macro %s."),
285                    p->name, me->macro->name);
286               return me_error (me);
287             }
288
289           me->n_tokens++;
290           me->state = ME_EQUALS;
291           return 0;
292         }
293     }
294
295   return me_finished (me);
296 }
297
298 static int
299 me_equals (struct macro_expander *me, const struct token *token)
300 {
301   me->n_tokens++;
302
303   if (token->type == T_EQUALS)
304     {
305       me->state = ME_ARG;
306       return 0;
307     }
308
309   const struct token equals = { .type = T_EQUALS };
310   return me_expected (me, token, &equals);
311 }
312
313 /* Adds TOKEN to the collection of tokens in ME that potentially need to be
314    macro expanded.
315
316    Return values:
317
318    * -1: The tokens added do not actually invoke a macro.  The caller should
319      consume the first token without expanding it.
320
321    * 0: The macro expander needs more tokens, for macro arguments or to decide
322       whether this is actually a macro invocation.  The caller should call
323       macro_expander_add() again with the next token.
324
325     * >0: Expand the given number of tokens. */
326 int
327 macro_expander_add (struct macro_expander *me, const struct token *token)
328 {
329   switch (me->state)
330     {
331     case ME_START:
332       return me_add_start (me, token);
333
334     case ME_ARG:
335       return me_add_arg (me, token);
336
337     case ME_ENCLOSE:
338       return me_enclose (me, token);
339
340     case ME_KEYWORD:
341       return me_keyword (me, token);
342
343     case ME_EQUALS:
344       return me_equals (me, token);
345
346     default:
347       NOT_REACHED ();
348     }
349 }
350
351 void
352 macro_expander_get_expansion (struct macro_expander *me, struct tokens *exp)
353 {
354   struct state
355     {
356       struct segmenter segmenter;
357       struct substring body;
358     };
359
360   struct state state;
361   segmenter_init (&state.segmenter, SEG_MODE_INTERACTIVE /*XXX*/);
362   state.body = me->macro->body;
363
364   struct state saved = state;
365
366   struct token token = { .type = T_STOP };
367
368   while (state.body.length > 0)
369     {
370       struct scanner scanner;
371       scanner_init (&scanner, &token);
372
373       for (;;)
374         {
375           enum segment_type type;
376           int seg_len = segmenter_push (&state.segmenter, state.body.string,
377                                         state.body.length, true, &type);
378           assert (seg_len >= 0);
379
380           struct substring segment = ss_head (state.body, seg_len);
381           ss_advance (&state.body, seg_len);
382
383           enum scan_result result = scanner_push (&scanner, type, segment, &token);
384           if (result == SCAN_SAVE)
385             saved = state;
386           else if (result == SCAN_BACK)
387             {
388               state = saved;
389               break;
390             }
391           else if (result == SCAN_DONE)
392             break;
393         }
394
395       /* We have a token in 'token'. */
396       tokens_add (exp, &token);
397       token_destroy (&token);
398     }
399 }
400