SAVE TRANSLATE: Allow variable names with space, etc. in output.
[pspp] / src / language / lexer / variable-parser.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012 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/variable-parser.h"
20
21 #include <ctype.h>
22 #include <limits.h>
23 #include <stdbool.h>
24 #include <stdlib.h>
25
26 #include "data/dataset.h"
27 #include "data/dictionary.h"
28 #include "data/variable.h"
29 #include "language/lexer/lexer.h"
30 #include "libpspp/assertion.h"
31 #include "libpspp/cast.h"
32 #include "libpspp/hash-functions.h"
33 #include "libpspp/i18n.h"
34 #include "libpspp/hmapx.h"
35 #include "libpspp/message.h"
36 #include "libpspp/misc.h"
37 #include "libpspp/pool.h"
38 #include "libpspp/str.h"
39 #include "libpspp/stringi-set.h"
40
41 #include "math/interaction.h"
42
43 #include "gl/c-ctype.h"
44 #include "gl/xalloc.h"
45
46 #include "gettext.h"
47 #define _(msgid) gettext (msgid)
48
49 static struct variable *var_set_get_var (const struct var_set *, size_t);
50 static struct variable *var_set_lookup_var (const struct var_set *,
51                                             const char *);
52 static bool var_set_lookup_var_idx (const struct var_set *, const char *,
53                                     size_t *);
54 static bool var_set_get_names_must_be_ids (const struct var_set *);
55
56 static bool
57 is_name_token (const struct lexer *lexer, bool names_must_be_ids)
58 {
59   return (lex_token (lexer) == T_ID
60           || (!names_must_be_ids && lex_token (lexer) == T_STRING));
61 }
62
63 static bool
64 is_vs_name_token (const struct lexer *lexer, const struct var_set *vs)
65 {
66   return is_name_token (lexer, var_set_get_names_must_be_ids (vs));
67 }
68
69 static bool
70 is_dict_name_token (const struct lexer *lexer, const struct dictionary *d)
71 {
72   return is_name_token (lexer, dict_get_names_must_be_ids (d));
73 }
74
75 /* Parses a name as a variable within VS.  Sets *IDX to the
76    variable's index and returns true if successful.  On failure
77    emits an error message and returns false. */
78 static bool
79 parse_vs_variable_idx (struct lexer *lexer, const struct var_set *vs,
80                        size_t *idx)
81 {
82   assert (idx != NULL);
83
84   if (!is_vs_name_token (lexer, vs))
85     {
86       lex_error (lexer, _("expecting variable name"));
87       return false;
88     }
89   else if (var_set_lookup_var_idx (vs, lex_tokcstr (lexer), idx))
90     {
91       lex_get (lexer);
92       return true;
93     }
94   else
95     {
96       msg (SE, _("%s is not a variable name."), lex_tokcstr (lexer));
97       return false;
98     }
99 }
100
101 /* Parses a name as a variable within VS and returns the variable
102    if successful.  On failure emits an error message and returns
103    a null pointer. */
104 static struct variable *
105 parse_vs_variable (struct lexer *lexer, const struct var_set *vs)
106 {
107   size_t idx;
108   return parse_vs_variable_idx (lexer, vs, &idx) ? var_set_get_var (vs, idx) : NULL;
109 }
110
111 /* Parses a variable name in dictionary D and returns the
112    variable if successful.  On failure emits an error message and
113    returns a null pointer. */
114 struct variable *
115 parse_variable (struct lexer *lexer, const struct dictionary *d)
116 {
117   struct var_set *vs = var_set_create_from_dict (d);
118   struct variable *var = parse_vs_variable (lexer, vs);
119   var_set_destroy (vs);
120   return var;
121 }
122
123 /* Parses a set of variables from dictionary D given options
124    OPTS.  Resulting list of variables stored in *VAR and the
125    number of variables into *CNT.  Returns true only if
126    successful. */
127 bool
128 parse_variables (struct lexer *lexer, const struct dictionary *d,
129                         struct variable ***var,
130                         size_t *cnt, int opts)
131 {
132   struct var_set *vs;
133   int success;
134
135   assert (d != NULL);
136   assert (var != NULL);
137   assert (cnt != NULL);
138
139   vs = var_set_create_from_dict (d);
140   success = parse_var_set_vars (lexer, vs, var, cnt, opts);
141   var_set_destroy (vs);
142   return success;
143 }
144
145 /* Parses a set of variables from dictionary D given options
146    OPTS.  Resulting list of variables stored in *VARS and the
147    number of variables into *VAR_CNT.  Returns true only if
148    successful.  Same behavior as parse_variables, except that all
149    allocations are taken from the given POOL. */
150 bool
151 parse_variables_pool (struct lexer *lexer, struct pool *pool,
152                 const struct dictionary *dict,
153                 struct variable ***vars, size_t *var_cnt, int opts)
154 {
155   int retval;
156
157   /* PV_APPEND is unsafe because parse_variables would free the
158      existing names on failure, but those names are presumably
159      already in the pool, which would attempt to re-free it
160      later. */
161   assert (!(opts & PV_APPEND));
162
163   retval = parse_variables (lexer, dict, vars, var_cnt, opts);
164   if (retval)
165     pool_register (pool, free, *vars);
166   return retval;
167 }
168
169 /* Parses a variable name from VS.  If successful, sets *IDX to
170    the variable's index in VS, *CLASS to the variable's
171    dictionary class, and returns true.  Returns false on
172    failure. */
173 static bool
174 parse_var_idx_class (struct lexer *lexer, const struct var_set *vs,
175                         size_t *idx,
176                         enum dict_class *class)
177 {
178   if (!parse_vs_variable_idx (lexer, vs, idx))
179     return false;
180
181   *class = dict_class_from_id (var_get_name (var_set_get_var (vs, *idx)));
182   return true;
183 }
184
185 /* Add the variable from VS with index IDX to the list of
186    variables V that has *NV elements and room for *MV.
187    Uses and updates INCLUDED to avoid duplicates if indicated by
188    PV_OPTS, which also affects what variables are allowed in
189    appropriate ways. */
190 static void
191 add_variable (struct variable ***v, size_t *nv, size_t *mv,
192               char *included, int pv_opts,
193               const struct var_set *vs, size_t idx)
194 {
195   struct variable *add = var_set_get_var (vs, idx);
196   const char *add_name = var_get_name (add);
197
198   if ((pv_opts & PV_NUMERIC) && !var_is_numeric (add))
199     msg (SW, _("%s is not a numeric variable.  It will not be "
200                "included in the variable list."), add_name);
201   else if ((pv_opts & PV_STRING) && !var_is_alpha (add))
202     msg (SE, _("%s is not a string variable.  It will not be "
203                "included in the variable list."), add_name);
204   else if ((pv_opts & PV_NO_SCRATCH)
205            && dict_class_from_id (add_name) == DC_SCRATCH)
206     msg (SE, _("Scratch variables (such as %s) are not allowed "
207                "here."), add_name);
208   else if ((pv_opts & (PV_SAME_TYPE | PV_SAME_WIDTH)) && *nv
209            && var_get_type (add) != var_get_type ((*v)[0]))
210     msg (SE, _("%s and %s are not the same type.  All variables in "
211                "this variable list must be of the same type.  %s "
212                "will be omitted from the list."),
213          var_get_name ((*v)[0]), add_name, add_name);
214   else if ((pv_opts & PV_SAME_WIDTH) && *nv
215            && var_get_width (add) != var_get_width ((*v)[0]))
216     msg (SE, _("%s and %s are string variables with different widths.  "
217                "All variables in this variable list must have the "
218                "same width.  %s will be omitted from the list."),
219          var_get_name ((*v)[0]), add_name, add_name);
220   else if ((pv_opts & PV_NO_DUPLICATE) && included && included[idx])
221     msg (SE, _("Variable %s appears twice in variable list."), add_name);
222   else if ((pv_opts & PV_DUPLICATE) || !included || !included[idx])
223     {
224       if (*nv >= *mv)
225         {
226           *mv = 2 * (*nv + 1);
227           *v = xnrealloc (*v, *mv, sizeof **v);
228         }
229       (*v)[(*nv)++] = add;
230       if (included != NULL)
231         included[idx] = 1;
232     }
233 }
234
235 /* Adds the variables in VS with indexes FIRST_IDX through
236    LAST_IDX, inclusive, to the list of variables V that has *NV
237    elements and room for *MV.  Uses and updates INCLUDED to avoid
238    duplicates if indicated by PV_OPTS, which also affects what
239    variables are allowed in appropriate ways. */
240 static void
241 add_variables (struct variable ***v, size_t *nv, size_t *mv, char *included,
242                int pv_opts,
243                const struct var_set *vs, int first_idx, int last_idx,
244                enum dict_class class)
245 {
246   size_t i;
247
248   for (i = first_idx; i <= last_idx; i++)
249     if (dict_class_from_id (var_get_name (var_set_get_var (vs, i))) == class)
250       add_variable (v, nv, mv, included, pv_opts, vs, i);
251 }
252
253 /* Note that if parse_variables() returns false, *v is free()'d.
254    Conversely, if parse_variables() returns true, then *nv is
255    nonzero and *v is non-NULL. */
256 bool
257 parse_var_set_vars (struct lexer *lexer, const struct var_set *vs,
258                     struct variable ***v, size_t *nv,
259                     int pv_opts)
260 {
261   size_t mv;
262   char *included;
263
264   assert (vs != NULL);
265   assert (v != NULL);
266   assert (nv != NULL);
267
268   /* At most one of PV_NUMERIC, PV_STRING, PV_SAME_TYPE,
269      PV_SAME_WIDTH may be specified. */
270   assert (((pv_opts & PV_NUMERIC) != 0)
271           + ((pv_opts & PV_STRING) != 0)
272           + ((pv_opts & PV_SAME_TYPE) != 0)
273           + ((pv_opts & PV_SAME_WIDTH) != 0) <= 1);
274
275   /* PV_DUPLICATE and PV_NO_DUPLICATE are incompatible. */
276   assert (!(pv_opts & PV_DUPLICATE) || !(pv_opts & PV_NO_DUPLICATE));
277
278   if (!(pv_opts & PV_APPEND))
279     {
280       *v = NULL;
281       *nv = 0;
282       mv = 0;
283     }
284   else
285     mv = *nv;
286
287   if (!(pv_opts & PV_DUPLICATE))
288     {
289       size_t i;
290
291       included = xcalloc (var_set_get_cnt (vs), sizeof *included);
292       for (i = 0; i < *nv; i++)
293         {
294           size_t index;
295           if (!var_set_lookup_var_idx (vs, var_get_name ((*v)[i]), &index))
296             NOT_REACHED ();
297           included[index] = 1;
298         }
299     }
300   else
301     included = NULL;
302
303   do
304     {
305       if (lex_match (lexer, T_ALL))
306         add_variables (v, nv, &mv, included, pv_opts,
307                        vs, 0, var_set_get_cnt (vs) - 1, DC_ORDINARY);
308       else
309         {
310           enum dict_class class;
311           size_t first_idx;
312
313           if (!parse_var_idx_class (lexer, vs, &first_idx, &class))
314             goto fail;
315
316           if (!lex_match (lexer, T_TO))
317             add_variable (v, nv, &mv, included, pv_opts, vs, first_idx);
318           else
319             {
320               size_t last_idx;
321               enum dict_class last_class;
322               struct variable *first_var, *last_var;
323
324               if (!parse_var_idx_class (lexer, vs, &last_idx, &last_class))
325                 goto fail;
326
327               first_var = var_set_get_var (vs, first_idx);
328               last_var = var_set_get_var (vs, last_idx);
329
330               if (last_idx < first_idx)
331                 {
332                   const char *first_name = var_get_name (first_var);
333                   const char *last_name = var_get_name (last_var);
334                   msg (SE, _("%s TO %s is not valid syntax since %s "
335                              "precedes %s in the dictionary."),
336                        first_name, last_name, first_name, last_name);
337                   goto fail;
338                 }
339
340               if (class != last_class)
341                 {
342                   msg (SE, _("When using the TO keyword to specify several "
343                              "variables, both variables must be from "
344                              "the same variable dictionaries, of either "
345                              "ordinary, scratch, or system variables.  "
346                              "%s is a %s variable, whereas %s is %s."),
347                        var_get_name (first_var), dict_class_to_name (class),
348                        var_get_name (last_var),
349                        dict_class_to_name (last_class));
350                   goto fail;
351                 }
352
353               add_variables (v, nv, &mv, included, pv_opts,
354                              vs, first_idx, last_idx, class);
355             }
356         }
357
358       if (pv_opts & PV_SINGLE)
359         break;
360       lex_match (lexer, T_COMMA);
361     }
362   while (lex_token (lexer) == T_ALL
363          || (is_vs_name_token (lexer, vs)
364              && var_set_lookup_var (vs, lex_tokcstr (lexer)) != NULL));
365
366   if (*nv == 0)
367     goto fail;
368
369   free (included);
370   return 1;
371
372 fail:
373   free (included);
374   free (*v);
375   *v = NULL;
376   *nv = 0;
377   return 0;
378 }
379
380 char *
381 parse_DATA_LIST_var (struct lexer *lexer, const struct dictionary *d)
382 {
383   if (!is_dict_name_token (lexer, d))
384     {
385       lex_error (lexer, "expecting variable name");
386       return NULL;
387     }
388   if (!dict_id_is_valid (d, lex_tokcstr (lexer), true))
389     return NULL;
390
391   char *name = xstrdup (lex_tokcstr (lexer));
392   lex_get (lexer);
393   return name;
394 }
395
396 /* Attempts to break UTF-8 encoded NAME into a root (whose contents are
397    arbitrary except that it does not end in a digit) followed by an integer
398    numeric suffix.  On success, stores the value of the suffix into *NUMBERP,
399    the number of digits in the suffix into *N_DIGITSP, and returns the number
400    of bytes in the root.  On failure, returns 0. */
401 static int
402 extract_numeric_suffix (const char *name,
403                         unsigned long int *numberp, int *n_digitsp)
404 {
405   size_t root_len, n_digits;
406   size_t i;
407
408   /* Count length of root. */
409   root_len = 1;                 /* Valid identifier never starts with digit. */
410   for (i = 1; name[i] != '\0'; i++)
411     if (!c_isdigit (name[i]))
412       root_len = i + 1;
413   n_digits = i - root_len;
414
415   if (n_digits == 0)
416     {
417       msg (SE, _("`%s' cannot be used with TO because it does not end in "
418                  "a digit."), name);
419       return 0;
420     }
421
422   *numberp = strtoull (name + root_len, NULL, 10);
423   if (*numberp == ULONG_MAX)
424     {
425       msg (SE, _("Numeric suffix on `%s' is larger than supported with TO."),
426            name);
427       return 0;
428     }
429   *n_digitsp = n_digits;
430   return root_len;
431 }
432
433 static bool
434 add_var_name (char *name,
435               char ***names, size_t *n_vars, size_t *allocated_vars,
436               struct stringi_set *set, int pv_opts)
437 {
438   if (pv_opts & PV_NO_DUPLICATE && !stringi_set_insert (set, name))
439     {
440       msg (SE, _("Variable %s appears twice in variable list."),
441            name);
442       return false;
443     }
444
445   if (*n_vars >= *allocated_vars)
446     *names = x2nrealloc (*names, allocated_vars, sizeof **names);
447   (*names)[(*n_vars)++] = name;
448   return true;
449 }
450
451 /* Parses a list of variable names according to the DATA LIST version
452    of the TO convention.  */
453 bool
454 parse_DATA_LIST_vars (struct lexer *lexer, const struct dictionary *dict,
455                       char ***namesp, size_t *n_varsp, int pv_opts)
456 {
457   char **names;
458   size_t n_vars;
459   size_t allocated_vars;
460
461   struct stringi_set set;
462
463   char *name1 = NULL;
464
465   bool ok = false;
466
467   assert ((pv_opts & ~(PV_APPEND | PV_SINGLE
468                        | PV_NO_SCRATCH | PV_NO_DUPLICATE)) == 0);
469   stringi_set_init (&set);
470
471   if (pv_opts & PV_APPEND)
472     {
473       n_vars = allocated_vars = *n_varsp;
474       names = *namesp;
475
476       if (pv_opts & PV_NO_DUPLICATE)
477         {
478           size_t i;
479
480           for (i = 0; i < n_vars; i++)
481             stringi_set_insert (&set, names[i]);
482         }
483     }
484   else
485     {
486       n_vars = allocated_vars = 0;
487       names = NULL;
488     }
489
490   do
491     {
492       name1 = parse_DATA_LIST_var (lexer, dict);
493       if (!name1)
494         goto exit;
495       if (dict_class_from_id (name1) == DC_SCRATCH && pv_opts & PV_NO_SCRATCH)
496         {
497           msg (SE, _("Scratch variables not allowed here."));
498           goto exit;
499         }
500       if (lex_match (lexer, T_TO))
501         {
502           unsigned long int num1, num2;
503           int n_digits1, n_digits2;
504           int root_len1, root_len2;
505           unsigned long int number;
506
507           char *name2 = parse_DATA_LIST_var (lexer, dict);
508
509           root_len1 = extract_numeric_suffix (name1, &num1, &n_digits1);
510           if (root_len1 == 0)
511             goto exit;
512
513           root_len2 = extract_numeric_suffix (name2, &num2, &n_digits2);
514           if (root_len2 == 0)
515             goto exit;
516
517           if (root_len1 != root_len2 || memcasecmp (name1, name2, root_len1))
518             {
519               msg (SE, _("Prefixes don't match in use of TO convention."));
520               goto exit;
521             }
522           if (num1 > num2)
523             {
524               msg (SE, _("Bad bounds in use of TO convention."));
525               goto exit;
526             }
527
528           for (number = num1; number <= num2; number++)
529             {
530               char *name = xasprintf ("%.*s%0*lu",
531                                       root_len1, name1,
532                                       n_digits1, number);
533               if (!add_var_name (name, &names, &n_vars, &allocated_vars,
534                                  &set, pv_opts))
535                 {
536                   free (name);
537                   goto exit;
538                 }
539             }
540
541           free (name1);
542           name1 = NULL;
543           free (name2);
544         }
545       else
546         {
547           if (!add_var_name (name1, &names, &n_vars, &allocated_vars,
548                              &set, pv_opts))
549             goto exit;
550           name1 = NULL;
551         }
552
553       lex_match (lexer, T_COMMA);
554
555       if (pv_opts & PV_SINGLE)
556         break;
557     }
558   while (lex_token (lexer) == T_ID);
559   ok = true;
560
561 exit:
562   stringi_set_destroy (&set);
563   if (ok)
564     {
565       *namesp = names;
566       *n_varsp = n_vars;
567     }
568   else
569     {
570       int i;
571       for (i = 0; i < n_vars; i++)
572         free (names[i]);
573       free (names);
574       *namesp = NULL;
575       *n_varsp = 0;
576
577       free (name1);
578     }
579   return ok;
580 }
581
582 /* Registers each of the NAMES[0...NNAMES - 1] in POOL, as well
583    as NAMES itself. */
584 static void
585 register_vars_pool (struct pool *pool, char **names, size_t nnames)
586 {
587   size_t i;
588
589   for (i = 0; i < nnames; i++)
590     pool_register (pool, free, names[i]);
591   pool_register (pool, free, names);
592 }
593
594 /* Parses a list of variable names according to the DATA LIST
595    version of the TO convention.  Same args as
596    parse_DATA_LIST_vars(), except that all allocations are taken
597    from the given POOL. */
598 bool
599 parse_DATA_LIST_vars_pool (struct lexer *lexer, const struct dictionary *dict,
600                            struct pool *pool,
601                            char ***names, size_t *nnames, int pv_opts)
602 {
603   int retval;
604
605   /* PV_APPEND is unsafe because parse_DATA_LIST_vars would free
606      the existing names on failure, but those names are
607      presumably already in the pool, which would attempt to
608      re-free it later. */
609   assert (!(pv_opts & PV_APPEND));
610
611   retval = parse_DATA_LIST_vars (lexer, dict, names, nnames, pv_opts);
612   if (retval)
613     register_vars_pool (pool, *names, *nnames);
614   return retval;
615 }
616
617 /* Parses a list of variables where some of the variables may be
618    existing and the rest are to be created.  Same args as
619    parse_DATA_LIST_vars(). */
620 bool
621 parse_mixed_vars (struct lexer *lexer, const struct dictionary *dict,
622                   char ***names, size_t *nnames, int pv_opts)
623 {
624   size_t i;
625
626   assert (names != NULL);
627   assert (nnames != NULL);
628
629   if (!(pv_opts & PV_APPEND))
630     {
631       *names = NULL;
632       *nnames = 0;
633     }
634   while (is_dict_name_token (lexer, dict) || lex_token (lexer) == T_ALL)
635     {
636       if (lex_token (lexer) == T_ALL || dict_lookup_var (dict, lex_tokcstr (lexer)) != NULL)
637         {
638           struct variable **v;
639           size_t nv;
640
641           if (!parse_variables (lexer, dict, &v, &nv, pv_opts))
642             goto fail;
643           *names = xnrealloc (*names, *nnames + nv, sizeof **names);
644           for (i = 0; i < nv; i++)
645             (*names)[*nnames + i] = xstrdup (var_get_name (v[i]));
646           free (v);
647           *nnames += nv;
648         }
649       else if (!parse_DATA_LIST_vars (lexer, dict, names, nnames, PV_APPEND | pv_opts))
650         goto fail;
651     }
652   if (*nnames == 0)
653     goto fail;
654
655   return true;
656
657 fail:
658   for (i = 0; i < *nnames; i++)
659     free ((*names)[i]);
660   free (*names);
661   *names = NULL;
662   *nnames = 0;
663   return false;
664 }
665
666 /* Parses a list of variables where some of the variables may be
667    existing and the rest are to be created.  Same args as
668    parse_mixed_vars(), except that all allocations are taken
669    from the given POOL. */
670 bool
671 parse_mixed_vars_pool (struct lexer *lexer, const struct dictionary *dict, struct pool *pool,
672                        char ***names, size_t *nnames, int pv_opts)
673 {
674   int retval;
675
676   /* PV_APPEND is unsafe because parse_mixed_vars_pool would free
677      the existing names on failure, but those names are
678      presumably already in the pool, which would attempt to
679      re-free it later. */
680   assert (!(pv_opts & PV_APPEND));
681
682   retval = parse_mixed_vars (lexer, dict, names, nnames, pv_opts);
683   if (retval)
684     register_vars_pool (pool, *names, *nnames);
685   return retval;
686 }
687 \f
688 /* A set of variables. */
689 struct var_set
690   {
691     bool names_must_be_ids;
692     size_t (*get_cnt) (const struct var_set *);
693     struct variable *(*get_var) (const struct var_set *, size_t idx);
694     bool (*lookup_var_idx) (const struct var_set *, const char *, size_t *);
695     void (*destroy) (struct var_set *);
696     void *aux;
697   };
698
699 /* Returns the number of variables in VS. */
700 size_t
701 var_set_get_cnt (const struct var_set *vs)
702 {
703   assert (vs != NULL);
704
705   return vs->get_cnt (vs);
706 }
707
708 /* Return variable with index IDX in VS.
709    IDX must be less than the number of variables in VS. */
710 static struct variable *
711 var_set_get_var (const struct var_set *vs, size_t idx)
712 {
713   assert (vs != NULL);
714   assert (idx < var_set_get_cnt (vs));
715
716   return vs->get_var (vs, idx);
717 }
718
719 /* Returns the variable in VS named NAME, or a null pointer if VS
720    contains no variable with that name. */
721 struct variable *
722 var_set_lookup_var (const struct var_set *vs, const char *name)
723 {
724   size_t idx;
725   return (var_set_lookup_var_idx (vs, name, &idx)
726           ? var_set_get_var (vs, idx)
727           : NULL);
728 }
729
730 /* If VS contains a variable named NAME, sets *IDX to its index
731    and returns true.  Otherwise, returns false. */
732 bool
733 var_set_lookup_var_idx (const struct var_set *vs, const char *name,
734                         size_t *idx)
735 {
736   assert (vs != NULL);
737   assert (name != NULL);
738
739   return vs->lookup_var_idx (vs, name, idx);
740 }
741
742 /* Destroys VS. */
743 void
744 var_set_destroy (struct var_set *vs)
745 {
746   if (vs != NULL)
747     vs->destroy (vs);
748 }
749
750 static bool
751 var_set_get_names_must_be_ids (const struct var_set *vs)
752 {
753   return vs->names_must_be_ids;
754 }
755 \f
756 /* Returns the number of variables in VS. */
757 static size_t
758 dict_var_set_get_cnt (const struct var_set *vs)
759 {
760   struct dictionary *d = vs->aux;
761
762   return dict_get_var_cnt (d);
763 }
764
765 /* Return variable with index IDX in VS.
766    IDX must be less than the number of variables in VS. */
767 static struct variable *
768 dict_var_set_get_var (const struct var_set *vs, size_t idx)
769 {
770   struct dictionary *d = vs->aux;
771
772   return dict_get_var (d, idx);
773 }
774
775 /* If VS contains a variable named NAME, sets *IDX to its index
776    and returns true.  Otherwise, returns false. */
777 static bool
778 dict_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
779                              size_t *idx)
780 {
781   struct dictionary *d = vs->aux;
782   struct variable *v = dict_lookup_var (d, name);
783   if (v != NULL)
784     {
785       *idx = var_get_dict_index (v);
786       return true;
787     }
788   else
789     return false;
790 }
791
792 /* Destroys VS. */
793 static void
794 dict_var_set_destroy (struct var_set *vs)
795 {
796   free (vs);
797 }
798
799 /* Returns a variable set based on D. */
800 struct var_set *
801 var_set_create_from_dict (const struct dictionary *d)
802 {
803   struct var_set *vs = xmalloc (sizeof *vs);
804   vs->names_must_be_ids = dict_get_names_must_be_ids (d);
805   vs->get_cnt = dict_var_set_get_cnt;
806   vs->get_var = dict_var_set_get_var;
807   vs->lookup_var_idx = dict_var_set_lookup_var_idx;
808   vs->destroy = dict_var_set_destroy;
809   vs->aux = (void *) d;
810   return vs;
811 }
812 \f
813 /* A variable set based on an array. */
814 struct array_var_set
815   {
816     struct variable *const *var;/* Array of variables. */
817     size_t var_cnt;             /* Number of elements in var. */
818     struct hmapx vars_by_name;  /* Variables hashed by name. */
819   };
820
821 /* Returns the number of variables in VS. */
822 static size_t
823 array_var_set_get_cnt (const struct var_set *vs)
824 {
825   struct array_var_set *avs = vs->aux;
826
827   return avs->var_cnt;
828 }
829
830 /* Return variable with index IDX in VS.
831    IDX must be less than the number of variables in VS. */
832 static struct variable *
833 array_var_set_get_var (const struct var_set *vs, size_t idx)
834 {
835   struct array_var_set *avs = vs->aux;
836
837   return CONST_CAST (struct variable *, avs->var[idx]);
838 }
839
840 /* If VS contains a variable named NAME, sets *IDX to its index
841    and returns true.  Otherwise, returns false. */
842 static bool
843 array_var_set_lookup_var_idx (const struct var_set *vs, const char *name,
844                               size_t *idx)
845 {
846   struct array_var_set *avs = vs->aux;
847   struct hmapx_node *node;
848   struct variable **varp;
849
850   HMAPX_FOR_EACH_WITH_HASH (varp, node, utf8_hash_case_string (name, 0),
851                             &avs->vars_by_name)
852     if (!utf8_strcasecmp (name, var_get_name (*varp)))
853       {
854         *idx = varp - avs->var;
855         return true;
856       }
857
858   return false;
859 }
860
861 /* Destroys VS. */
862 static void
863 array_var_set_destroy (struct var_set *vs)
864 {
865   struct array_var_set *avs = vs->aux;
866
867   hmapx_destroy (&avs->vars_by_name);
868   free (avs);
869   free (vs);
870 }
871
872 /* Returns a variable set based on the VAR_CNT variables in VAR. */
873 struct var_set *
874 var_set_create_from_array (struct variable *const *var, size_t var_cnt)
875 {
876   struct var_set *vs;
877   struct array_var_set *avs;
878   size_t i;
879
880   vs = xmalloc (sizeof *vs);
881   vs->names_must_be_ids = true;
882   vs->get_cnt = array_var_set_get_cnt;
883   vs->get_var = array_var_set_get_var;
884   vs->lookup_var_idx = array_var_set_lookup_var_idx;
885   vs->destroy = array_var_set_destroy;
886   vs->aux = avs = xmalloc (sizeof *avs);
887   avs->var = var;
888   avs->var_cnt = var_cnt;
889   hmapx_init (&avs->vars_by_name);
890   for (i = 0; i < var_cnt; i++)
891     {
892       const char *name = var_get_name (var[i]);
893       size_t idx;
894
895       if (array_var_set_lookup_var_idx (vs, name, &idx))
896         {
897           var_set_destroy (vs);
898           return NULL;
899         }
900       hmapx_insert (&avs->vars_by_name, CONST_CAST (void *, &avs->var[i]),
901                     utf8_hash_case_string (name, 0));
902     }
903
904   return vs;
905 }
906
907
908 /* Match a variable.
909    If the match succeeds, the variable will be placed in VAR.
910    Returns true if successful */
911 bool
912 lex_match_variable (struct lexer *lexer, const struct dictionary *dict, const struct variable **var)
913 {
914   if (lex_token (lexer) !=  T_ID)
915     return false;
916
917   *var = parse_variable_const  (lexer, dict);
918
919   if ( *var == NULL)
920     return false;
921   return true;
922 }
923
924 /* An interaction is a variable followed by {*, BY} followed by an interaction */
925 static bool
926 parse_internal_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact, struct interaction **it)
927 {
928   const struct variable *v = NULL;
929   assert (iact);
930
931   switch  (lex_next_token (lexer, 1))
932     {
933     case T_ENDCMD:
934     case T_SLASH:
935     case T_COMMA:
936     case T_ID:
937     case T_BY:
938     case T_ASTERISK:
939       break;
940     default:
941       return false;
942       break;
943     }
944
945   if (! lex_match_variable (lexer, dict, &v))
946     {
947       if (it)
948         interaction_destroy (*it);
949       *iact = NULL;
950       return false;
951     }
952
953   assert (v);
954
955   if ( *iact == NULL)
956     *iact = interaction_create (v);
957   else
958     interaction_add_variable (*iact, v);
959
960   if ( lex_match (lexer, T_ASTERISK) || lex_match (lexer, T_BY))
961     {
962       return parse_internal_interaction (lexer, dict, iact, iact);
963     }
964
965   return true;
966 }
967
968 bool
969 parse_design_interaction (struct lexer *lexer, const struct dictionary *dict, struct interaction **iact)
970 {
971   return parse_internal_interaction (lexer, dict, iact, NULL);
972 }
973