b8cac2501a78cd667f88384bde9e277e3fe41719
[alexxy/gromacs.git] / src / gromacs / selection / params.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2009,2010,2011,2012,2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements functions in selparam.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_selection
41  */
42 #include "gmxpre.h"
43
44 #include <algorithm>
45 #include <string>
46
47 #include "gromacs/math/vec.h"
48 #include "gromacs/selection/position.h"
49 #include "gromacs/selection/selmethod.h"
50 #include "gromacs/selection/selparam.h"
51 #include "gromacs/utility/cstringutil.h"
52 #include "gromacs/utility/exceptions.h"
53 #include "gromacs/utility/gmxassert.h"
54 #include "gromacs/utility/messagestringcollector.h"
55 #include "gromacs/utility/smalloc.h"
56 #include "gromacs/utility/stringutil.h"
57
58 #include "parsetree.h"
59 #include "position.h"
60 #include "scanner.h"
61 #include "selelem.h"
62
63 using gmx::SelectionParserValue;
64 using gmx::SelectionParserValueList;
65 using gmx::SelectionParserParameter;
66 using gmx::SelectionParserParameterList;
67 using gmx::SelectionTreeElement;
68 using gmx::SelectionTreeElementPointer;
69
70 /*!
71  * \param[in] name   Name of the parameter to search.
72  * \param[in] nparam Number of parameters in the \p param array.
73  * \param[in] param  Parameter array to search.
74  * \returns   Pointer to the parameter in the \p param
75  *   or NULL if no parameter with name \p name was found.
76  *
77  * The comparison is case-sensitive.
78  */
79 gmx_ana_selparam_t *
80 gmx_ana_selparam_find(const char *name, int nparam, gmx_ana_selparam_t *param)
81 {
82     int                i;
83
84     if (nparam == 0)
85     {
86         return NULL;
87     }
88     /* Find the first non-null parameter */
89     i = 0;
90     while (i < nparam && param[i].name == NULL)
91     {
92         ++i;
93     }
94     /* Process the special case of a NULL parameter */
95     if (name == NULL)
96     {
97         return (i == 0) ? NULL : &param[i-1];
98     }
99     for (; i < nparam; ++i)
100     {
101         if (!strcmp(param[i].name, name))
102         {
103             return &param[i];
104         }
105         /* Check for 'no' prefix on boolean parameters */
106         if (param[i].val.type == NO_VALUE
107             && strlen(name) > 2 && name[0] == 'n' && name[1] == 'o'
108             && !strcmp(param[i].name, name+2))
109         {
110             return &param[i];
111         }
112     }
113     return NULL;
114 }
115
116 /*! \brief
117  * Does a type conversion on a SelectionParserValue.
118  *
119  * \param[in,out] value    Value to convert.
120  * \param[in]     type     Type to convert to.
121  * \param[in]     scanner  Scanner data structure.
122  * \returns       0 on success, a non-zero value on error.
123  */
124 static int
125 convert_value(SelectionParserValue *value, e_selvalue_t type, void *scanner)
126 {
127     if (value->type == type || type == NO_VALUE)
128     {
129         return 0;
130     }
131     if (value->hasExpressionValue())
132     {
133         /* Conversion from atom selection to position using default
134          * reference positions. */
135         if (value->type == GROUP_VALUE && type == POS_VALUE)
136         {
137             SelectionTreeElementPointer expr =
138                 _gmx_sel_init_position(value->expr, NULL, scanner);
139             // FIXME: Use exceptions
140             if (!expr)
141             {
142                 return -1;
143             }
144             *value = SelectionParserValue::createExpr(expr);
145             return 0;
146         }
147         return -1;
148     }
149     else
150     {
151         /* Integers to floating point are easy */
152         if (value->type == INT_VALUE && type == REAL_VALUE)
153         {
154             *value = SelectionParserValue::createRealRange(value->u.i.i1,
155                                                            value->u.i.i2);
156             return 0;
157         }
158         /* Reals that are integer-valued can also be converted */
159         if (value->type == REAL_VALUE && type == INT_VALUE)
160         {
161             int i1 = static_cast<int>(value->u.r.r1);
162             int i2 = static_cast<int>(value->u.r.r2);
163             if (gmx_within_tol(value->u.r.r1, i1, GMX_REAL_EPS)
164                 && gmx_within_tol(value->u.r.r2, i2, GMX_REAL_EPS))
165             {
166                 *value = SelectionParserValue::createIntegerRange(i1, i2);
167                 return 0;
168             }
169         }
170     }
171     return -1;
172 }
173
174 /*! \brief
175  * Does a type conversion on a list of values.
176  *
177  * \param[in,out] values   Values to convert.
178  * \param[in]     type     Type to convert to.
179  * \param[in]     scanner  Scanner data structure.
180  * \returns       0 on success, a non-zero value on error.
181  */
182 static int
183 convert_values(SelectionParserValueList *values, e_selvalue_t type, void *scanner)
184 {
185     int rc = 0;
186     SelectionParserValueList::iterator value;
187     for (value = values->begin(); value != values->end(); ++value)
188     {
189         int rc1 = convert_value(&*value, type, scanner);
190         if (rc1 != 0 && rc == 0)
191         {
192             rc = rc1;
193         }
194     }
195     /* FIXME: More informative error messages */
196     return rc;
197 }
198
199 /*! \brief
200  * Adds a child element for a parameter, keeping the parameter order.
201  *
202  * \param[in,out] root  Root element to which the child is added.
203  * \param[in]     child Child to add.
204  * \param[in]     param Parameter for which this child is a value.
205  *
206  * Puts \p child in the child list of \p root such that the list remains
207  * in the same order as the corresponding parameters.
208  */
209 static void
210 place_child(const SelectionTreeElementPointer &root,
211             const SelectionTreeElementPointer &child,
212             gmx_ana_selparam_t                *param)
213 {
214     gmx_ana_selparam_t *ps;
215     int                 n;
216
217     ps = root->u.expr.method->param;
218     n  = param - ps;
219     /* Put the child element in the correct place */
220     if (!root->child || n < root->child->u.param - ps)
221     {
222         child->next = root->child;
223         root->child = child;
224     }
225     else
226     {
227         SelectionTreeElementPointer prev = root->child;
228         while (prev->next && prev->next->u.param - ps >= n)
229         {
230             prev = prev->next;
231         }
232         child->next = prev->next;
233         prev->next  = child;
234     }
235 }
236
237 /*! \brief
238  * Comparison function for sorting integer ranges.
239  *
240  * \param[in] a Pointer to the first range.
241  * \param[in] b Pointer to the second range.
242  * \returns   -1, 0, or 1 depending on the relative order of \p a and \p b.
243  *
244  * The ranges are primarily sorted based on their starting point, and
245  * secondarily based on length (longer ranges come first).
246  */
247 static int
248 cmp_int_range(const void *a, const void *b)
249 {
250     if (((int *)a)[0] < ((int *)b)[0])
251     {
252         return -1;
253     }
254     if (((int *)a)[0] > ((int *)b)[0])
255     {
256         return 1;
257     }
258     if (((int *)a)[1] > ((int *)b)[1])
259     {
260         return -1;
261     }
262     return 0;
263 }
264
265 /*! \brief
266  * Comparison function for sorting real ranges.
267  *
268  * \param[in] a Pointer to the first range.
269  * \param[in] b Pointer to the second range.
270  * \returns   -1, 0, or 1 depending on the relative order of \p a and \p b.
271  *
272  * The ranges are primarily sorted based on their starting point, and
273  * secondarily based on length (longer ranges come first).
274  */
275 static int
276 cmp_real_range(const void *a, const void *b)
277 {
278     if (((real *)a)[0] < ((real *)b)[0])
279     {
280         return -1;
281     }
282     if (((real *)a)[0] > ((real *)b)[0])
283     {
284         return 1;
285     }
286     if (((real *)a)[1] > ((real *)b)[1])
287     {
288         return -1;
289     }
290     return 0;
291 }
292
293 /*! \brief
294  * Parses the values for a parameter that takes integer or real ranges.
295  *
296  * \param[in] values List of values.
297  * \param     param  Parameter to parse.
298  * \param[in] scanner Scanner data structure.
299  * \returns   true if the values were parsed successfully, false otherwise.
300  */
301 static bool
302 parse_values_range(const SelectionParserValueList &values,
303                    gmx_ana_selparam_t *param, void *scanner)
304 {
305     int                *idata;
306     real               *rdata;
307     int                 i, j, n;
308
309     param->flags &= ~SPAR_DYNAMIC;
310     GMX_RELEASE_ASSERT(param->val.type == INT_VALUE || param->val.type == REAL_VALUE,
311                        "Invalid range parameter type");
312     idata = NULL;
313     rdata = NULL;
314     if (param->val.type == INT_VALUE)
315     {
316         snew(idata, values.size()*2);
317     }
318     else
319     {
320         snew(rdata, values.size()*2);
321     }
322     i = 0;
323     SelectionParserValueList::const_iterator value;
324     for (value = values.begin(); value != values.end(); ++value)
325     {
326         if (value->hasExpressionValue())
327         {
328             _gmx_selparser_error(scanner, "expressions not supported within range parameters");
329             return false;
330         }
331         GMX_RELEASE_ASSERT(value->type == param->val.type,
332                            "Invalid range value type (should have been caught earlier)");
333         if (param->val.type == INT_VALUE)
334         {
335             int i1 = std::min(value->u.i.i1, value->u.i.i2);
336             int i2 = std::max(value->u.i.i1, value->u.i.i2);
337             /* Check if the new range overlaps or extends the previous one */
338             if (i > 0 && i1 <= idata[i-1]+1 && i2 >= idata[i-2]-1)
339             {
340                 idata[i-2] = std::min(idata[i-2], i1);
341                 idata[i-1] = std::max(idata[i-1], i2);
342             }
343             else
344             {
345                 idata[i++] = i1;
346                 idata[i++] = i2;
347             }
348         }
349         else
350         {
351             real r1 = std::min(value->u.r.r1, value->u.r.r2);
352             real r2 = std::max(value->u.r.r1, value->u.r.r2);
353             /* Check if the new range overlaps or extends the previous one */
354             if (i > 0 && r1 <= rdata[i-1] && r2 >= rdata[i-2])
355             {
356                 rdata[i-2] = std::min(rdata[i-2], r1);
357                 rdata[i-1] = std::max(rdata[i-1], r2);
358             }
359             else
360             {
361                 rdata[i++] = r1;
362                 rdata[i++] = r2;
363             }
364         }
365     }
366     n = i/2;
367     /* Sort the ranges and merge consequent ones */
368     if (param->val.type == INT_VALUE)
369     {
370         qsort(idata, n, 2*sizeof(int), &cmp_int_range);
371         for (i = j = 2; i < 2*n; i += 2)
372         {
373             if (idata[j-1]+1 >= idata[i])
374             {
375                 if (idata[i+1] > idata[j-1])
376                 {
377                     idata[j-1] = idata[i+1];
378                 }
379             }
380             else
381             {
382                 idata[j]   = idata[i];
383                 idata[j+1] = idata[i+1];
384                 j         += 2;
385             }
386         }
387     }
388     else
389     {
390         qsort(rdata, n, 2*sizeof(real), &cmp_real_range);
391         for (i = j = 2; i < 2*n; i += 2)
392         {
393             if (rdata[j-1]+1 >= rdata[i])
394             {
395                 if (rdata[i+1] > rdata[j-1])
396                 {
397                     rdata[j-1] = rdata[i+1];
398                 }
399             }
400             else
401             {
402                 rdata[j]   = rdata[i];
403                 rdata[j+1] = rdata[i+1];
404                 j         += 2;
405             }
406         }
407     }
408     n = j/2;
409     /* Store the values */
410     if (param->flags & SPAR_VARNUM)
411     {
412         param->val.nr  = n;
413         if (param->val.type == INT_VALUE)
414         {
415             srenew(idata, j);
416             _gmx_selvalue_setstore_alloc(&param->val, idata, j);
417         }
418         else
419         {
420             srenew(rdata, j);
421             _gmx_selvalue_setstore_alloc(&param->val, rdata, j);
422         }
423     }
424     else
425     {
426         if (n != param->val.nr)
427         {
428             _gmx_selparser_error(scanner, "the value should consist of exactly one range");
429             sfree(idata);
430             sfree(rdata);
431             return false;
432         }
433         if (param->val.type == INT_VALUE)
434         {
435             memcpy(param->val.u.i, idata, 2*n*sizeof(int));
436             sfree(idata);
437         }
438         else
439         {
440             memcpy(param->val.u.r, rdata, 2*n*sizeof(real));
441             sfree(rdata);
442         }
443     }
444     if (param->nvalptr)
445     {
446         *param->nvalptr = param->val.nr;
447     }
448     param->nvalptr = NULL;
449
450     return true;
451 }
452
453 /*! \brief
454  * Parses the values for a parameter that takes a variable number of values.
455  *
456  * \param[in] values List of values.
457  * \param     param  Parameter to parse.
458  * \param     root   Selection element to which child expressions are added.
459  * \param[in] scanner Scanner data structure.
460  * \returns   true if the values were parsed successfully, false otherwise.
461  *
462  * For integer ranges, the sequence of numbers from the first to second value
463  * is stored, each as a separate value.
464  */
465 static bool
466 parse_values_varnum(const SelectionParserValueList    &values,
467                     gmx_ana_selparam_t                *param,
468                     const SelectionTreeElementPointer &root,
469                     void                              *scanner)
470 {
471     int                 i, j;
472
473     param->flags &= ~SPAR_DYNAMIC;
474     /* Compute number of values, considering also integer ranges. */
475     size_t valueCount = values.size();
476     if (param->val.type == INT_VALUE)
477     {
478         SelectionParserValueList::const_iterator value;
479         for (value = values.begin(); value != values.end(); ++value)
480         {
481             if (value->type == INT_VALUE && !value->hasExpressionValue())
482             {
483                 valueCount += abs(value->u.i.i2 - value->u.i.i1);
484             }
485         }
486     }
487
488     /* Check that the value type is actually implemented */
489     if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE
490         && param->val.type != STR_VALUE && param->val.type != POS_VALUE)
491     {
492         GMX_THROW(gmx::InternalError("Variable-count value type not implemented"));
493     }
494
495     /* Reserve appropriate amount of memory */
496     if (param->val.type == POS_VALUE)
497     {
498         gmx_ana_pos_reserve(param->val.u.p, valueCount, 0);
499         gmx_ana_indexmap_init(&param->val.u.p->m, NULL, NULL, INDEX_UNKNOWN);
500         gmx_ana_pos_set_nr(param->val.u.p, valueCount);
501     }
502     else
503     {
504         _gmx_selvalue_reserve(&param->val, valueCount);
505     }
506
507     i     = 0;
508     SelectionParserValueList::const_iterator value;
509     for (value = values.begin(); value != values.end(); ++value)
510     {
511         if (value->hasExpressionValue())
512         {
513             _gmx_selparser_error(scanner, "expressions not supported within value lists");
514             return false;
515         }
516         GMX_RELEASE_ASSERT(value->type == param->val.type,
517                            "Invalid value type (should have been caught earlier)");
518         switch (param->val.type)
519         {
520             case INT_VALUE:
521                 if (value->u.i.i1 <= value->u.i.i2)
522                 {
523                     for (j = value->u.i.i1; j <= value->u.i.i2; ++j)
524                     {
525                         param->val.u.i[i++] = j;
526                     }
527                 }
528                 else
529                 {
530                     for (j = value->u.i.i1; j >= value->u.i.i2; --j)
531                     {
532                         param->val.u.i[i++] = j;
533                     }
534                 }
535                 break;
536             case REAL_VALUE:
537                 if (value->u.r.r1 != value->u.r.r2)
538                 {
539                     _gmx_selparser_error(scanner, "real ranges not supported");
540                     return false;
541                 }
542                 param->val.u.r[i++] = value->u.r.r1;
543                 break;
544             case STR_VALUE:
545                 param->val.u.s[i++] = gmx_strdup(value->stringValue().c_str());
546                 break;
547             case POS_VALUE:  copy_rvec(value->u.x, param->val.u.p->x[i++]); break;
548             default: /* Should not be reached */
549                 GMX_THROW(gmx::InternalError("Variable-count value type not implemented"));
550         }
551     }
552     param->val.nr = i;
553     if (param->nvalptr)
554     {
555         *param->nvalptr = param->val.nr;
556     }
557     param->nvalptr = NULL;
558     /* Create a dummy child element to store the string values.
559      * This element is responsible for freeing the values, but carries no
560      * other function. */
561     if (param->val.type == STR_VALUE)
562     {
563         SelectionTreeElementPointer child(new SelectionTreeElement(SEL_CONST));
564         _gmx_selelem_set_vtype(child, STR_VALUE);
565         child->setName(param->name);
566         child->flags &= ~SEL_ALLOCVAL;
567         child->flags |= SEL_FLAGSSET | SEL_VARNUMVAL | SEL_ALLOCDATA;
568         child->v.nr   = param->val.nr;
569         _gmx_selvalue_setstore(&child->v, param->val.u.s);
570         /* Because the child is not group-valued, the u union is not used
571          * for anything, so we can abuse it by storing the parameter value
572          * as place_child() expects, but this is really ugly... */
573         child->u.param = param;
574         place_child(root, child, param);
575     }
576
577     return true;
578 }
579
580 /*! \brief
581  * Adds a new subexpression reference to a selection element.
582  *
583  * \param[in,out] root  Root element to which the subexpression is added.
584  * \param[in]     param Parameter for which this expression is a value.
585  * \param[in]     expr  Expression to add.
586  * \param[in]     scanner Scanner data structure.
587  * \returns       The created child element.
588  *
589  * Creates a new \ref SEL_SUBEXPRREF element and adds it into the child
590  * list of \p root.
591  * If \p expr is already a \ref SEL_SUBEXPRREF, it is used as it is.
592  * \ref SEL_ALLOCVAL is cleared for the returned element.
593  */
594 static SelectionTreeElementPointer
595 add_child(const SelectionTreeElementPointer &root, gmx_ana_selparam_t *param,
596           const SelectionTreeElementPointer &expr, void *scanner)
597 {
598     GMX_RELEASE_ASSERT(root->type == SEL_EXPRESSION || root->type == SEL_MODIFIER,
599                        "Unsupported root element for selection parameter parser");
600     SelectionTreeElementPointer child;
601     /* Create a subexpression reference element if necessary */
602     if (expr->type == SEL_SUBEXPRREF)
603     {
604         child = expr;
605     }
606     else
607     {
608         child.reset(new SelectionTreeElement(SEL_SUBEXPRREF));
609         _gmx_selelem_set_vtype(child, expr->v.type);
610         child->child  = expr;
611     }
612     /* Setup the child element */
613     child->flags  &= ~SEL_ALLOCVAL;
614     child->u.param = param;
615     if (child->v.type != param->val.type)
616     {
617         _gmx_selparser_error(scanner, "invalid expression value");
618         // FIXME: Use exceptions.
619         return SelectionTreeElementPointer();
620     }
621     _gmx_selelem_update_flags(child);
622     if ((child->flags & SEL_DYNAMIC) && !(param->flags & SPAR_DYNAMIC))
623     {
624         _gmx_selparser_error(scanner, "dynamic values not supported");
625         // FIXME: Use exceptions.
626         return SelectionTreeElementPointer();
627     }
628     if (!(child->flags & SEL_DYNAMIC))
629     {
630         param->flags &= ~SPAR_DYNAMIC;
631     }
632     /* Put the child element in the correct place */
633     place_child(root, child, param);
634     return child;
635 }
636
637 /*! \brief
638  * Parses an expression value for a parameter that takes a variable number of values.
639  *
640  * \param[in] values List of values.
641  * \param     param  Parameter to parse.
642  * \param     root   Selection element to which child expressions are added.
643  * \param[in] scanner Scanner data structure.
644  * \returns   true if the values were parsed successfully, false otherwise.
645  */
646 static bool
647 parse_values_varnum_expr(const SelectionParserValueList    &values,
648                          gmx_ana_selparam_t                *param,
649                          const SelectionTreeElementPointer &root,
650                          void                              *scanner)
651 {
652     GMX_RELEASE_ASSERT(values.size() == 1 && values.front().hasExpressionValue(),
653                        "Called with an invalid type of value");
654
655     SelectionTreeElementPointer child
656         = add_child(root, param, values.front().expr, scanner);
657     if (!child)
658     {
659         return false;
660     }
661
662     /* Process single-valued expressions */
663     /* TODO: We should also handle SEL_SINGLEVAL expressions here */
664     if (child->v.type == POS_VALUE || child->v.type == GROUP_VALUE)
665     {
666         /* Set the value storage */
667         _gmx_selvalue_setstore(&child->v, param->val.u.ptr);
668         param->val.nr = 1;
669         if (param->nvalptr)
670         {
671             *param->nvalptr = param->val.nr;
672         }
673         param->nvalptr = NULL;
674         return true;
675     }
676
677     if (!(child->flags & SEL_VARNUMVAL))
678     {
679         _gmx_selparser_error(scanner, "invalid expression value");
680         return false;
681     }
682
683     child->flags   |= SEL_ALLOCVAL;
684     param->val.nr   = -1;
685     *param->nvalptr = param->val.nr;
686     /* Rest of the initialization is done during compilation in
687      * init_method(). */
688
689     return true;
690 }
691
692 /*! \brief
693  * Initializes the storage of an expression value.
694  *
695  * \param[in,out] sel   Selection element that evaluates the value.
696  * \param[in]     param Parameter to receive the value.
697  * \param[in]     i     The value of \p sel evaluates the value \p i for
698  *   \p param.
699  * \param[in]     scanner Scanner data structure.
700  *
701  * Initializes the data pointer of \p sel such that the result is stored
702  * as the value \p i of \p param.
703  * This function is used internally by parse_values_std().
704  */
705 static bool
706 set_expr_value_store(const SelectionTreeElementPointer &sel,
707                      gmx_ana_selparam_t *param, int i, void *scanner)
708 {
709     if (sel->v.type != GROUP_VALUE && !(sel->flags & SEL_SINGLEVAL))
710     {
711         _gmx_selparser_error(scanner, "invalid expression value");
712         return false;
713     }
714     switch (sel->v.type)
715     {
716         case INT_VALUE:   sel->v.u.i = &param->val.u.i[i]; break;
717         case REAL_VALUE:  sel->v.u.r = &param->val.u.r[i]; break;
718         case STR_VALUE:   sel->v.u.s = &param->val.u.s[i]; break;
719         case POS_VALUE:   sel->v.u.p = &param->val.u.p[i]; break;
720         case GROUP_VALUE: sel->v.u.g = &param->val.u.g[i]; break;
721         default: /* Error */
722             GMX_THROW(gmx::InternalError("Invalid value type"));
723     }
724     sel->v.nr     = 1;
725     sel->v.nalloc = -1;
726     return true;
727 }
728
729 /*! \brief
730  * Parses the values for a parameter that takes a constant number of values.
731  *
732  * \param[in] values List of values.
733  * \param     param  Parameter to parse.
734  * \param     root   Selection element to which child expressions are added.
735  * \param[in] scanner Scanner data structure.
736  * \returns   true if the values were parsed successfully, false otherwise.
737  *
738  * For integer ranges, the sequence of numbers from the first to second value
739  * is stored, each as a separate value.
740  */
741 static bool
742 parse_values_std(const SelectionParserValueList &values,
743                  gmx_ana_selparam_t *param,
744                  const SelectionTreeElementPointer &root, void *scanner)
745 {
746     int                i, j;
747     bool               bDynamic;
748
749     /* Handle atom-valued parameters */
750     if (param->flags & SPAR_ATOMVAL)
751     {
752         if (values.size() > 1)
753         {
754             _gmx_selparser_error(scanner, "more than one value not supported");
755             return false;
756         }
757         if (values.front().hasExpressionValue())
758         {
759             SelectionTreeElementPointer child
760                 = add_child(root, param, values.front().expr, scanner);
761             if (!child)
762             {
763                 return false;
764             }
765             child->flags |= SEL_ALLOCVAL;
766             if (child->v.type != GROUP_VALUE && (child->flags & SEL_ATOMVAL))
767             {
768                 /* Rest of the initialization is done during compilation in
769                  * init_method(). */
770                 /* TODO: Positions are not correctly handled */
771                 param->val.nr = -1;
772                 if (param->nvalptr)
773                 {
774                     *param->nvalptr = -1;
775                 }
776                 return true;
777             }
778             param->flags  &= ~SPAR_ATOMVAL;
779             param->val.nr  = 1;
780             if (param->nvalptr)
781             {
782                 *param->nvalptr = 1;
783             }
784             param->nvalptr = NULL;
785             if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
786                 || param->val.type == STR_VALUE)
787             {
788                 _gmx_selvalue_reserve(&param->val, 1);
789             }
790             return set_expr_value_store(child, param, 0, scanner);
791         }
792         /* If we reach here, proceed with normal parameter handling */
793         param->val.nr = 1;
794         if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
795             || param->val.type == STR_VALUE)
796         {
797             _gmx_selvalue_reserve(&param->val, 1);
798         }
799         param->flags &= ~SPAR_ATOMVAL;
800         param->flags &= ~SPAR_DYNAMIC;
801     }
802
803     i        = 0;
804     bDynamic = false;
805     SelectionParserValueList::const_iterator value;
806     for (value = values.begin(); value != values.end() && i < param->val.nr; ++value)
807     {
808         if (value->type != param->val.type)
809         {
810             _gmx_selparser_error(scanner, "incorrect value skipped");
811             continue;
812         }
813         if (value->hasExpressionValue())
814         {
815             SelectionTreeElementPointer child
816                 = add_child(root, param, value->expr, scanner);
817             /* Check that the expression is valid */
818             if (!child)
819             {
820                 return false;
821             }
822             if (!set_expr_value_store(child, param, i, scanner))
823             {
824                 return false;
825             }
826             if (child->flags & SEL_DYNAMIC)
827             {
828                 bDynamic = true;
829             }
830         }
831         else
832         {
833             /* Value is not an expression */
834             switch (value->type)
835             {
836                 case INT_VALUE:
837                     if (value->u.i.i1 <= value->u.i.i2)
838                     {
839                         for (j = value->u.i.i1; j <= value->u.i.i2 && i < param->val.nr; ++j)
840                         {
841                             param->val.u.i[i++] = j;
842                         }
843                         if (j != value->u.i.i2 + 1)
844                         {
845                             _gmx_selparser_error(scanner, "extra values skipped");
846                         }
847                     }
848                     else
849                     {
850                         for (j = value->u.i.i1; j >= value->u.i.i2 && i < param->val.nr; --j)
851                         {
852                             param->val.u.i[i++] = j;
853                         }
854                         if (j != value->u.i.i2 - 1)
855                         {
856                             _gmx_selparser_error(scanner, "extra values skipped");
857                         }
858                     }
859                     --i;
860                     break;
861                 case REAL_VALUE:
862                     if (value->u.r.r1 != value->u.r.r2)
863                     {
864                         _gmx_selparser_error(scanner, "real ranges not supported");
865                         return false;
866                     }
867                     param->val.u.r[i] = value->u.r.r1;
868                     break;
869                 case STR_VALUE:
870                     param->val.u.s[i] = gmx_strdup(value->stringValue().c_str());
871                     break;
872                 case POS_VALUE:
873                     gmx_ana_pos_init_const(&param->val.u.p[i], value->u.x);
874                     break;
875                 case NO_VALUE:
876                 case GROUP_VALUE:
877                     GMX_THROW(gmx::InternalError("Invalid non-expression value type"));
878             }
879         }
880         ++i;
881     }
882     if (value != values.end())
883     {
884         _gmx_selparser_error(scanner, "extra values");
885         return false;
886     }
887     if (i < param->val.nr)
888     {
889         _gmx_selparser_error(scanner, "not enough values");
890         return false;
891     }
892     if (!bDynamic)
893     {
894         param->flags &= ~SPAR_DYNAMIC;
895     }
896     if (param->nvalptr)
897     {
898         *param->nvalptr = param->val.nr;
899     }
900     param->nvalptr = NULL;
901
902     return true;
903 }
904
905 /*! \brief
906  * Parses the values for a boolean parameter.
907  *
908  * \param[in] name   Name by which the parameter was given.
909  * \param[in] values List of values.
910  * \param     param  Parameter to parse.
911  * \param[in] scanner Scanner data structure.
912  * \returns   true if the values were parsed successfully, false otherwise.
913  */
914 static bool
915 parse_values_bool(const std::string &name,
916                   const SelectionParserValueList &values,
917                   gmx_ana_selparam_t *param, void *scanner)
918 {
919     GMX_ASSERT(param->val.type == NO_VALUE,
920                "Boolean parser called for non-boolean parameter");
921     if (values.size() > 1 || (!values.empty() && values.front().type != INT_VALUE))
922     {
923         _gmx_selparser_error(scanner, "parameter takes only a yes/no/on/off/0/1 value");
924         return false;
925     }
926
927     bool bSetNo = false;
928     /* Check if the parameter name is given with a 'no' prefix */
929     if (name.length() > 2 && name[0] == 'n' && name[1] == 'o'
930         && name.compare(2, name.length() - 2, param->name) == 0)
931     {
932         bSetNo = true;
933     }
934     if (bSetNo && !values.empty())
935     {
936         _gmx_selparser_error(scanner, "parameter 'no%s' should not have a value",
937                              param->name);
938         return false;
939     }
940     if (!values.empty() && values.front().u.i.i1 == 0)
941     {
942         bSetNo = true;
943     }
944
945     *param->val.u.b = bSetNo ? false : true;
946     return true;
947 }
948
949 /*! \brief
950  * Parses the values for an enumeration parameter.
951  *
952  * \param[in] values List of values.
953  * \param     param  Parameter to parse.
954  * \param[in] scanner Scanner data structure.
955  * \returns   true if the values were parsed successfully, false otherwise.
956  */
957 static bool
958 parse_values_enum(const SelectionParserValueList &values,
959                   gmx_ana_selparam_t             *param,
960                   void                           *scanner)
961 {
962     GMX_ASSERT(param->val.type == STR_VALUE,
963                "Enum parser called for non-string parameter");
964     if (values.size() != 1)
965     {
966         _gmx_selparser_error(scanner, "a single value is required");
967         return false;
968     }
969     const SelectionParserValue &value = values.front();
970     GMX_RELEASE_ASSERT(value.type == param->val.type,
971                        "Invalid value type (should have been caught earlier)");
972     if (value.hasExpressionValue())
973     {
974         _gmx_selparser_error(scanner, "expression value for enumerated parameter not supported");
975         return false;
976     }
977
978     const std::string &svalue = value.stringValue();
979     int                i      = 1;
980     int                match  = 0;
981     while (param->val.u.s[i] != NULL)
982     {
983         if (gmx::startsWith(param->val.u.s[i], svalue))
984         {
985             /* Check if there is a duplicate match */
986             if (match > 0)
987             {
988                 _gmx_selparser_error(scanner, "ambiguous value");
989                 return false;
990             }
991             match = i;
992         }
993         ++i;
994     }
995     if (match == 0)
996     {
997         _gmx_selparser_error(scanner, "invalid value");
998         return false;
999     }
1000     param->val.u.s[0] = param->val.u.s[match];
1001     return true;
1002 }
1003
1004 /*! \brief
1005  * Replaces constant expressions with their values.
1006  *
1007  * \param[in,out] values First element in the value list to process.
1008  */
1009 static void
1010 convert_const_values(SelectionParserValueList *values)
1011 {
1012     SelectionParserValueList::iterator value;
1013     for (value = values->begin(); value != values->end(); ++value)
1014     {
1015         if (value->hasExpressionValue() && value->expr->v.type != GROUP_VALUE &&
1016             value->expr->type == SEL_CONST)
1017         {
1018             SelectionTreeElementPointer expr = value->expr;
1019             switch (expr->v.type)
1020             {
1021                 case INT_VALUE:
1022                     *value = SelectionParserValue::createInteger(expr->v.u.i[0]);
1023                     break;
1024                 case REAL_VALUE:
1025                     *value = SelectionParserValue::createReal(expr->v.u.r[0]);
1026                     break;
1027                 case STR_VALUE:
1028                     *value = SelectionParserValue::createString(expr->v.u.s[0]);
1029                     break;
1030                 case POS_VALUE:
1031                     *value = SelectionParserValue::createPosition(expr->v.u.p->x[0]);
1032                     break;
1033                 default:
1034                     GMX_THROW(gmx::InternalError(
1035                                       "Unsupported constant expression value type"));
1036             }
1037         }
1038     }
1039 }
1040
1041 /*!
1042  * \param     pparams List of parameters from the selection parser.
1043  * \param[in] nparam  Number of parameters in \p params.
1044  * \param     params  Array of parameters to parse.
1045  * \param     root    Selection element to which child expressions are added.
1046  * \param[in] scanner Scanner data structure.
1047  * \returns   true if the parameters were parsed successfully, false otherwise.
1048  *
1049  * Initializes the \p params array based on the parameters in \p pparams.
1050  * See the documentation of \c gmx_ana_selparam_t for different options
1051  * available for parsing.
1052  *
1053  * The list \p pparams and any associated values are freed after the parameters
1054  * have been processed, no matter is there was an error or not.
1055  */
1056 bool
1057 _gmx_sel_parse_params(const gmx::SelectionParserParameterList &pparams,
1058                       int nparam, gmx_ana_selparam_t *params,
1059                       const gmx::SelectionTreeElementPointer &root,
1060                       void *scanner)
1061 {
1062     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
1063     gmx_ana_selparam_t          *oparam;
1064     bool                         bOk, rc;
1065     int                          i;
1066
1067     /* Check that the value pointers of SPAR_VARNUM parameters are NULL and
1068      * that they are not NULL for other parameters */
1069     bOk = true;
1070     for (i = 0; i < nparam; ++i)
1071     {
1072         std::string                contextStr = gmx::formatString("In parameter '%s'", params[i].name);
1073         gmx::MessageStringContext  context(errors, contextStr);
1074         if (params[i].val.type != POS_VALUE && (params[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
1075         {
1076             if (params[i].val.u.ptr != NULL)
1077             {
1078                 _gmx_selparser_error(scanner, "value pointer is not NULL "
1079                                      "although it should be for SPAR_VARNUM "
1080                                      "and SPAR_ATOMVAL parameters");
1081             }
1082             if ((params[i].flags & SPAR_VARNUM)
1083                 && (params[i].flags & SPAR_DYNAMIC) && !params[i].nvalptr)
1084             {
1085                 _gmx_selparser_error(scanner, "nvalptr is NULL but both "
1086                                      "SPAR_VARNUM and SPAR_DYNAMIC are specified");
1087                 bOk = false;
1088             }
1089         }
1090         else
1091         {
1092             if (params[i].val.u.ptr == NULL)
1093             {
1094                 _gmx_selparser_error(scanner, "value pointer is NULL");
1095                 bOk = false;
1096             }
1097         }
1098     }
1099     if (!bOk)
1100     {
1101         return false;
1102     }
1103     /* Parse the parameters */
1104     i = 0;
1105     SelectionParserParameterList::const_iterator pparam;
1106     for (pparam = pparams.begin(); pparam != pparams.end(); ++pparam)
1107     {
1108         std::string contextStr;
1109         /* Find the parameter and make some checks */
1110         if (!pparam->name().empty())
1111         {
1112             contextStr = gmx::formatString("In parameter '%s'", pparam->name().c_str());
1113             i          = -1;
1114             oparam     = gmx_ana_selparam_find(pparam->name().c_str(), nparam, params);
1115         }
1116         else if (i >= 0)
1117         {
1118             contextStr = gmx::formatString("In value %d", i + 1);
1119             oparam     = &params[i];
1120             if (oparam->name != NULL)
1121             {
1122                 oparam = NULL;
1123                 _gmx_selparser_error(scanner, "too many NULL parameters provided");
1124                 bOk = false;
1125                 continue;
1126             }
1127             ++i;
1128         }
1129         else
1130         {
1131             _gmx_selparser_error(scanner, "all NULL parameters should appear in the beginning of the list");
1132             bOk = false;
1133             continue;
1134         }
1135         gmx::MessageStringContext  context(errors, contextStr);
1136         if (!oparam)
1137         {
1138             _gmx_selparser_error(scanner, "unknown parameter skipped");
1139             bOk = false;
1140             continue;
1141         }
1142         if (oparam->val.type != NO_VALUE && pparam->values().empty())
1143         {
1144             _gmx_selparser_error(scanner, "no value provided");
1145             bOk = false;
1146             continue;
1147         }
1148         if (oparam->flags & SPAR_SET)
1149         {
1150             _gmx_selparser_error(scanner, "parameter set multiple times, extra values skipped");
1151             bOk = false;
1152             continue;
1153         }
1154         oparam->flags |= SPAR_SET;
1155         /* Process the values for the parameter */
1156         convert_const_values(pparam->values_.get());
1157         if (convert_values(pparam->values_.get(), oparam->val.type, scanner) != 0)
1158         {
1159             _gmx_selparser_error(scanner, "invalid value");
1160             bOk = false;
1161             continue;
1162         }
1163         if (oparam->val.type == NO_VALUE)
1164         {
1165             rc = parse_values_bool(pparam->name(), pparam->values(), oparam, scanner);
1166         }
1167         else if (oparam->flags & SPAR_RANGES)
1168         {
1169             rc = parse_values_range(pparam->values(), oparam, scanner);
1170         }
1171         else if (oparam->flags & SPAR_VARNUM)
1172         {
1173             if (pparam->values().size() == 1
1174                 && pparam->values().front().hasExpressionValue())
1175             {
1176                 rc = parse_values_varnum_expr(pparam->values(), oparam, root, scanner);
1177             }
1178             else
1179             {
1180                 rc = parse_values_varnum(pparam->values(), oparam, root, scanner);
1181             }
1182         }
1183         else if (oparam->flags & SPAR_ENUMVAL)
1184         {
1185             rc = parse_values_enum(pparam->values(), oparam, scanner);
1186         }
1187         else
1188         {
1189             rc = parse_values_std(pparam->values(), oparam, root, scanner);
1190         }
1191         if (!rc)
1192         {
1193             bOk = false;
1194         }
1195     }
1196     /* Check that all required parameters are present */
1197     for (i = 0; i < nparam; ++i)
1198     {
1199         if (!(params[i].flags & SPAR_OPTIONAL) && !(params[i].flags & SPAR_SET))
1200         {
1201             _gmx_selparser_error(scanner, "required parameter '%s' not specified", params[i].name);
1202             bOk = false;
1203         }
1204     }
1205
1206     return bOk;
1207 }