Basic support for 'z of ...' selections
authorTeemu Murtola <teemu.murtola@gmail.com>
Wed, 29 Oct 2014 18:44:07 +0000 (20:44 +0200)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Sat, 29 Nov 2014 18:43:39 +0000 (19:43 +0100)
Add basic support for selections of type 'z of ...', where "z" can in
principle be any keyword and "..." any expression.  However, currently
the only syntax that is actually supported is '[xyz] of co[gm] of ...',
because
 1) this is the original case that was discussed in gmx-users some time
    ago,
 2) only the x, y, and z keywords satisfy the constraints that the
    simplest possible implementation requires,
 3) there is no context that would accept multiple values as produced by
    an expression like 'z of resnr 1 to 3', and
 4) there is no mechanism to detect that 'z of atomnr 1' actually
    evaluates to a single value.
Some of these limitations can be lifted in the future with reasonable
effort, though.

Change-Id: I6b87ce8d5c93e1ad05722dd59a66375b52b8e363

src/gromacs/selection/keywords.h
src/gromacs/selection/parser.cpp
src/gromacs/selection/parser.y
src/gromacs/selection/parsetree.cpp
src/gromacs/selection/parsetree.h
src/gromacs/selection/scanner_internal.cpp
src/gromacs/selection/selhelp.cpp
src/gromacs/selection/sm_keywords.cpp
src/gromacs/selection/sm_same.cpp
src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesKeywordOfPositions.xml [new file with mode: 0644]
src/gromacs/selection/tests/selectioncollection.cpp

index c6b3affa91ac404be4a4a387264e3dba26cec9c0..9401bd629c0fc1ee19de397b451b3ad3e743cada 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2012, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2012,2014, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -83,10 +83,23 @@ _gmx_selelem_custom_init_same(struct gmx_ana_selmethod_t                    **me
                               const gmx::SelectionParserParameterListPointer &params,
                               void                                           *scanner);
 
-/** Initializes a selection element for evaluating a keyword in a given group. */
+/*! \brief
+ * Initializes a selection element for evaluating a keyword in a given group.
+ *
+ * \param[in]   method  Keyword selection method to evaluate.
+ * \param[in]   child   The group/positions to evaluate \p method in.
+ * \param[in]   scanner Scanner data structure.
+ * \returns     Pointer to the created selection element (NULL on error).
+ *
+ * Creates a \ref SEL_EXPRESSION selection element that evaluates the keyword
+ * method given by \p method in the group/positions given by \p child.
+ *
+ * \p child should be a selection tree that evaluates to \ref GROUP_VALUE or
+ * \ref POS_VALUE.
+ */
 gmx::SelectionTreeElementPointer
 _gmx_sel_init_keyword_evaluator(struct gmx_ana_selmethod_t              *method,
-                                const gmx::SelectionParserParameterList &params,
+                                const gmx::SelectionTreeElementPointer  &child,
                                 void                                    *scanner);
 
 #endif
index 536ee2a5d7bb3db03010f61a587cc9dfbf26813a..c2a21dc220515890b9afac9ffc5b63f761c754a9 100644 (file)
@@ -494,16 +494,16 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  2
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   378
+#define YYLAST   388
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  49
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  25
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  89
+#define YYNRULES  90
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  149
+#define YYNSTATES  153
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -549,17 +549,18 @@ static const yytype_uint8 yytranslate[] =
 #if YYDEBUG
 /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
    YYRHS.  */
-static const yytype_uint8 yyprhs[] =
+static const yytype_uint16 yyprhs[] =
 {
        0,     0,     3,     4,     7,    10,    13,    14,    16,    18,
       20,    23,    27,    31,    35,    37,    39,    43,    47,    49,
       52,    54,    57,    59,    61,    63,    65,    68,    72,    76,
       80,    84,    87,    90,    92,    94,    96,    98,   100,   103,
-     107,   112,   116,   120,   122,   124,   127,   131,   135,   139,
-     143,   147,   150,   154,   158,   160,   163,   171,   175,   178,
-     182,   184,   186,   188,   190,   193,   194,   197,   200,   202,
-     206,   207,   210,   214,   216,   220,   222,   225,   229,   231,
-     233,   235,   237,   239,   241,   243,   245,   247,   251,   255
+     107,   112,   116,   120,   122,   124,   127,   132,   136,   140,
+     144,   148,   152,   155,   159,   163,   165,   168,   176,   180,
+     183,   187,   189,   191,   193,   195,   198,   199,   202,   205,
+     207,   211,   212,   215,   219,   221,   225,   227,   230,   234,
+     236,   238,   240,   242,   244,   246,   248,   250,   252,   256,
+     260
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
@@ -577,20 +578,21 @@ static const yytype_int8 yyrhs[] =
       22,    -1,    16,    -1,    42,    -1,    43,    -1,    39,    -1,
       59,    17,    -1,    59,    15,    69,    -1,    59,    15,    60,
       69,    -1,    59,    14,    69,    -1,    59,    19,    64,    -1,
-       4,    -1,     5,    -1,    59,    14,    -1,    59,    18,    64,
-      -1,    61,    32,    61,    -1,    61,    33,    61,    -1,    61,
-      34,    61,    -1,    61,    35,    61,    -1,    33,    61,    -1,
-      61,    37,    61,    -1,    40,    61,    41,    -1,    57,    -1,
-      59,    15,    -1,    44,    56,    45,    56,    45,    56,    46,
-      -1,    40,    63,    41,    -1,    20,    64,    -1,    16,    25,
-      58,    -1,    12,    -1,    11,    -1,    13,    -1,    65,    -1,
-      65,    24,    -1,    -1,    65,    66,    -1,    23,    67,    -1,
-      68,    -1,    47,    68,    48,    -1,    -1,    68,    71,    -1,
-      68,    45,    71,    -1,    70,    -1,    47,    70,    48,    -1,
-      72,    -1,    70,    72,    -1,    70,    45,    72,    -1,    58,
-      -1,    63,    -1,    61,    -1,    62,    -1,    73,    -1,    54,
-      -1,    55,    -1,    57,    -1,    73,    -1,    54,    10,    54,
-      -1,    54,    10,    55,    -1,    55,    10,    56,    -1
+       4,    -1,     5,    -1,    59,    14,    -1,    59,    14,    25,
+      63,    -1,    59,    18,    64,    -1,    61,    32,    61,    -1,
+      61,    33,    61,    -1,    61,    34,    61,    -1,    61,    35,
+      61,    -1,    33,    61,    -1,    61,    37,    61,    -1,    40,
+      61,    41,    -1,    57,    -1,    59,    15,    -1,    44,    56,
+      45,    56,    45,    56,    46,    -1,    40,    63,    41,    -1,
+      20,    64,    -1,    16,    25,    58,    -1,    12,    -1,    11,
+      -1,    13,    -1,    65,    -1,    65,    24,    -1,    -1,    65,
+      66,    -1,    23,    67,    -1,    68,    -1,    47,    68,    48,
+      -1,    -1,    68,    71,    -1,    68,    45,    71,    -1,    70,
+      -1,    47,    70,    48,    -1,    72,    -1,    70,    72,    -1,
+      70,    45,    72,    -1,    58,    -1,    63,    -1,    61,    -1,
+      62,    -1,    73,    -1,    54,    -1,    55,    -1,    57,    -1,
+      73,    -1,    54,    10,    54,    -1,    54,    10,    55,    -1,
+      55,    10,    56,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
@@ -600,11 +602,12 @@ static const yytype_uint16 yyrline[] =
      269,   276,   283,   290,   300,   301,   308,   309,   323,   324,
      328,   329,   332,   333,   336,   337,   345,   356,   367,   378,
      382,   393,   400,   409,   410,   415,   416,   417,   421,   429,
-     437,   445,   456,   471,   482,   496,   504,   515,   521,   527,
-     533,   539,   545,   551,   558,   569,   584,   593,   597,   607,
-     621,   629,   637,   650,   652,   658,   663,   674,   683,   684,
-     689,   694,   702,   713,   714,   718,   724,   732,   742,   748,
-     754,   760,   766,   770,   776,   782,   789,   793,   799,   805
+     437,   445,   456,   471,   482,   496,   504,   512,   523,   529,
+     535,   541,   547,   553,   559,   566,   577,   592,   601,   605,
+     615,   629,   637,   645,   658,   660,   666,   671,   682,   691,
+     692,   697,   702,   710,   721,   722,   726,   732,   740,   750,
+     756,   762,   768,   774,   778,   784,   790,   797,   801,   807,
+     813
 };
 #endif
 
@@ -651,10 +654,11 @@ static const yytype_uint8 yyr1[] =
       55,    55,    56,    56,    57,    57,    58,    58,    58,    58,
       58,    58,    58,    59,    59,    60,    60,    60,    58,    58,
       58,    58,    58,    61,    61,    61,    61,    61,    61,    61,
-      61,    61,    61,    61,    62,    62,    63,    63,    63,    63,
-      58,    61,    63,    64,    64,    65,    65,    66,    67,    67,
-      68,    68,    68,    69,    69,    70,    70,    70,    71,    71,
-      71,    71,    71,    72,    72,    72,    72,    73,    73,    73
+      61,    61,    61,    61,    61,    62,    62,    63,    63,    63,
+      63,    58,    61,    63,    64,    64,    65,    65,    66,    67,
+      67,    68,    68,    68,    69,    69,    70,    70,    70,    71,
+      71,    71,    71,    71,    72,    72,    72,    72,    73,    73,
+      73
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -664,11 +668,12 @@ static const yytype_uint8 yyr2[] =
        2,     3,     3,     3,     1,     1,     3,     3,     1,     2,
        1,     2,     1,     1,     1,     1,     2,     3,     3,     3,
        3,     2,     2,     1,     1,     1,     1,     1,     2,     3,
-       4,     3,     3,     1,     1,     2,     3,     3,     3,     3,
-       3,     2,     3,     3,     1,     2,     7,     3,     2,     3,
-       1,     1,     1,     1,     2,     0,     2,     2,     1,     3,
-       0,     2,     3,     1,     3,     1,     2,     3,     1,     1,
-       1,     1,     1,     1,     1,     1,     1,     3,     3,     3
+       4,     3,     3,     1,     1,     2,     4,     3,     3,     3,
+       3,     3,     2,     3,     3,     1,     2,     7,     3,     2,
+       3,     1,     1,     1,     1,     2,     0,     2,     2,     1,
+       3,     0,     2,     3,     1,     3,     1,     2,     3,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     3,     3,
+       3
 };
 
 /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
@@ -676,59 +681,61 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       2,     0,     1,     0,    43,    44,    24,    25,     0,    61,
-      60,    62,    34,    65,    33,     0,     0,     0,     0,     3,
+       2,     0,     1,     0,    43,    44,    24,    25,     0,    62,
+      61,    63,    34,    66,    33,     0,     0,     0,     0,     3,
        0,     9,     8,    15,     0,     0,    14,     5,     0,    32,
-      25,    31,     0,    58,    63,    43,    34,     0,    26,     0,
-       0,    51,     0,    15,     0,    14,    18,    20,     0,    22,
-      23,     0,     4,    65,    10,     0,     0,    45,     0,    38,
-      65,    65,     0,     0,     0,     0,     0,     0,     0,    11,
-      12,    13,    59,    70,    64,    66,     0,     0,    45,    16,
-      29,    53,    57,    19,    21,     0,    17,    28,    27,     0,
-      83,    84,    85,    41,    73,    75,    86,    37,    35,    36,
-       0,    39,    46,    42,    30,    47,    48,    49,    50,    52,
-       0,    70,    67,    68,     0,     0,     0,     0,     0,    76,
-      40,     0,    43,    44,     0,     0,     0,     0,    54,    78,
-       0,    80,    81,    79,    71,    82,     0,    74,    87,    88,
-      89,    77,    69,    43,    44,    72,    55,     0,    56
+      25,    31,     0,    59,    64,    43,    34,     0,    26,     0,
+       0,    52,     0,    15,     0,    14,    18,    20,     0,    22,
+      23,     0,     4,    66,    10,     0,     0,    45,     0,    38,
+      66,    66,     0,     0,     0,     0,     0,     0,     0,    11,
+      12,    13,    60,    71,    65,    67,     0,     0,    45,    16,
+      29,    54,    58,    19,    21,     0,    17,    28,    27,     0,
+       0,    84,    85,    86,    41,    74,    76,    87,    37,    35,
+      36,     0,    39,    47,    42,    30,    48,    49,    50,    51,
+      53,     0,    71,    68,    69,     0,     0,     0,    46,     0,
+       0,     0,     0,    77,    40,     0,    43,    44,     0,     0,
+       0,     0,    55,    79,     0,    81,    82,    80,    72,    83,
+       0,    75,    88,    89,    90,    78,    70,    43,    44,    73,
+      56,     0,    57
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     1,    19,    20,    21,    90,    91,    51,    92,   129,
-      24,   100,    25,   132,   133,    33,    34,    75,   112,   113,
-     101,    94,   134,    95,    96
+      -1,     1,    19,    20,    21,    91,    92,    51,    93,   133,
+      24,   101,    25,   136,   137,    33,    34,    75,   113,   114,
+     102,    95,   138,    96,    97
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -84
+#define YYPACT_NINF -82
 static const yytype_int16 yypact[] =
 {
-     -84,   148,   -84,     4,     6,   -84,   -84,   -20,   189,   -84,
-     -84,   -84,     1,   -84,   -84,   322,   216,   285,     0,   -84,
-      27,    16,   285,    22,   122,   173,   -84,   -84,   308,   -84,
-     -84,   -84,   322,   -84,    71,   -84,   -84,   322,   -84,   216,
-      49,    24,   -11,   -13,   232,    23,   -84,   -84,   140,   -84,
-     -84,    21,   -84,   -84,    16,   322,   322,    40,   197,   -84,
-     -84,   -84,   216,   216,   216,   216,   216,   216,   308,    22,
-     173,   -84,    22,    30,   -84,   -84,   -13,    47,   -84,   -84,
-     -84,   -84,   -84,   -84,   -84,     0,   -84,    56,   -84,    85,
-      93,    99,   -84,   -84,   210,   -84,   -84,   -84,   -84,   -84,
-      36,   -84,   -84,   -84,   139,    94,    94,    24,    24,    24,
-      23,   -84,   -84,   241,    78,    17,     0,     0,    85,   -84,
-     -84,   178,   116,   125,   338,   271,    93,    99,   -84,    22,
-     349,   139,   -84,   -84,   -84,   -84,     0,   -84,   -84,   -84,
-     -84,   -84,   -84,   133,   136,   -84,   197,   104,   -84
+     -82,   158,   -82,    68,    86,   -82,   -82,   -33,    51,   -82,
+     -82,   -82,     5,   -82,   -82,   332,   219,   295,    17,   -82,
+      99,    27,   295,    43,   359,   183,   -82,   -82,   318,   -82,
+     -82,   -82,   332,   -82,    92,   -82,   -82,   332,   -82,   219,
+      28,    72,    -2,   -13,   242,    70,   -82,   -82,   115,   -82,
+     -82,    87,   -82,   -82,    27,   332,   332,    20,   207,   -82,
+     -82,   -82,   219,   219,   219,   219,   219,   219,   318,    43,
+     183,   -82,    43,    80,   -82,   -82,   -13,   149,   109,   -82,
+     -82,   -82,   -82,   -82,   -82,    17,   -82,   108,   -82,    82,
+      59,   107,   129,   -82,   -82,    29,   -82,   -82,   -82,   -82,
+     -82,     4,   -82,   -82,   -82,   210,    96,    96,    72,    72,
+      72,    70,   -82,   -82,   251,   100,     5,    82,   -82,     8,
+      17,    17,    59,   -82,   -82,   188,   131,   136,   348,   281,
+     107,   129,   -82,    43,   365,   210,   -82,   -82,   -82,   -82,
+      17,   -82,   -82,   -82,   -82,   -82,   -82,   139,   143,   -82,
+     207,   110,   -82
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -84,   -84,   -84,   -84,    -4,   -17,   -15,   -83,    -1,   110,
-       9,   -84,    -8,   -84,    10,    54,   -84,   -84,   -84,    51,
-     -51,    62,    33,   -79,   -28
+     -82,   -82,   -82,   -82,    74,   -17,   -15,   -81,    -1,   120,
+      22,   -82,    15,   -82,     1,    40,   -82,   -82,   -82,    42,
+     -52,    65,    31,   -75,   -54
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -737,80 +744,82 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -22
 static const yytype_int16 yytable[] =
 {
-      22,    49,   114,    50,    46,    47,    93,    31,    41,    44,
-      53,    26,    27,    42,    -7,   119,    55,    56,    54,    28,
-      70,    46,    47,     6,    30,    40,    32,    45,    80,    44,
-      79,    77,    26,    48,   140,    52,   119,    53,    71,   141,
-      46,    47,     6,    30,    46,    47,     6,    30,    40,   120,
-      48,    55,    56,   147,   104,   105,   106,   107,   108,   109,
-      44,    67,   118,    78,    82,   137,    85,    60,    49,    48,
-      50,    40,    40,    40,    40,    40,    40,   111,   110,    63,
-      64,    65,    66,    89,    67,   135,    56,    89,    81,    46,
-      47,     6,    30,   135,    73,    74,   126,   135,   127,   138,
-      49,   139,    50,   116,   126,   131,   127,    86,   126,   117,
-     127,    23,   128,   131,   102,   103,    41,   131,    48,    49,
-     128,    50,   130,   136,   128,    38,   -18,    43,    65,    66,
-     130,    67,    23,    40,   130,   -20,    57,    58,    69,    59,
-      60,    61,    72,   -19,    83,    84,   -21,    76,     2,     3,
-     148,   115,     4,     5,     6,     7,    -6,     8,   145,     9,
-      10,    11,   121,     0,    12,    87,    88,     0,    13,     0,
+      22,    49,    26,    50,   115,    94,    28,    31,    46,    47,
+       6,    30,    46,    47,     6,    30,    55,    56,    45,    53,
+     123,    46,    47,    26,    46,    47,     6,    30,    80,    71,
+      32,    41,    44,    46,    47,     6,    30,    48,    40,    79,
+     144,    48,    78,    70,   123,    89,    60,   145,    53,   124,
+      48,    90,    44,   122,    77,    29,   141,     6,    30,   151,
+     139,    40,    48,    46,    47,     6,    30,    90,    49,   111,
+      50,   139,    55,    56,   122,   139,    27,   105,   106,   107,
+     108,   109,   110,    44,    40,    40,    40,    40,    40,    40,
+     118,    42,    48,    86,    -7,    11,    54,   130,   116,   131,
+     103,   104,    13,   142,    49,   143,    50,    52,   130,    67,
+     131,    82,   130,   132,   131,    73,    74,   120,   111,    83,
+      84,    23,   117,    49,   132,    50,    18,   112,   132,   135,
+      65,    66,    85,    67,    89,    38,   134,    43,    56,   121,
+     135,   -18,    23,    41,   135,   140,   -20,   134,    69,   -19,
+      40,   134,    72,   -21,   125,   119,   152,    76,     2,     3,
+     149,     0,     4,     5,     6,     7,    -6,     8,     0,     9,
+      10,    11,     0,     0,    12,    87,    88,     0,    13,     0,
       14,    63,    64,    65,    66,     0,    67,     0,    76,    15,
-       0,    16,   122,   123,     6,    30,     0,     8,    17,     9,
-      10,    11,    18,    29,    12,     6,    30,     0,    13,    62,
+      81,    16,   126,   127,     6,    30,     0,     8,    17,     9,
+      10,    11,    18,     0,    12,     0,     0,     0,    13,    62,
       14,    46,    47,     6,    30,    63,    64,    65,    66,    15,
-      67,   124,     0,     0,    46,    47,     6,    30,    68,     0,
-      35,     5,    18,   125,     0,     0,   142,     9,     0,     0,
-      48,     0,    36,     0,     0,     0,    97,     0,    14,    98,
-      99,     0,     0,    48,    89,   122,   123,     6,    30,    16,
-       8,     0,     9,    10,    11,   118,    39,    12,    62,     0,
+      67,   128,     0,    35,     5,     0,     0,     0,    68,     0,
+       9,     0,    18,   129,     0,    36,   146,     0,     0,     0,
+      48,    14,    63,    64,    65,    66,    98,    67,     0,    99,
+     100,     0,    16,     0,    90,   126,   127,     6,    30,    39,
+       8,     0,     9,    10,    11,     0,     0,    12,    62,     0,
        0,    13,     0,    14,    63,    64,    65,    66,     0,    67,
-       0,     0,    15,    81,   124,   122,   123,     6,    30,     0,
-       8,    68,     9,    10,    11,    18,   125,    12,     0,    35,
+       0,     0,    15,    81,   128,   126,   127,     6,    30,     0,
+       8,    68,     9,    10,    11,    18,   129,    12,     0,    35,
        5,    13,     0,    14,     8,     0,     9,    10,    11,     0,
-       0,    12,    15,     0,   124,    13,     0,    14,     0,     0,
+       0,    12,    15,     0,   128,    13,     0,    14,     0,     0,
        0,    68,    35,     5,     0,    18,    15,     8,    16,     9,
       10,    11,     0,     0,    12,    17,    35,     5,    13,    18,
       14,     8,     0,     9,    10,     0,     0,     0,    36,    15,
-       0,    16,   143,   144,    14,     0,     0,     0,    68,     9,
+       0,    16,   147,   148,    14,     0,     0,     0,    68,     9,
        0,     0,    18,    15,    36,    16,     0,     0,     0,     0,
-      14,     0,    37,    57,   146,     0,    59,    60,    61,     0,
-       0,    16,     0,     0,     0,     0,     0,     0,    39
+      14,     0,    37,    57,    58,     0,    59,    60,    61,    57,
+     150,    16,    59,    60,    61,     0,     0,     0,    39
 };
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-84)))
+  (!!((Yystate) == (-82)))
 
 #define yytable_value_is_error(Yytable_value) \
   YYID (0)
 
 static const yytype_int16 yycheck[] =
 {
-       1,    18,    85,    18,     4,     5,    57,     8,    16,    17,
-      21,     1,     8,    17,     8,    94,    29,    30,    22,    39,
-      28,     4,     5,     6,     7,    16,    25,    17,    41,    37,
-      41,    39,    22,    33,   117,     8,   115,    21,    28,   118,
-       4,     5,     6,     7,     4,     5,     6,     7,    39,   100,
-      33,    29,    30,   136,    62,    63,    64,    65,    66,    67,
-      68,    37,    45,    14,    41,    48,    45,    18,    85,    33,
-      85,    62,    63,    64,    65,    66,    67,    47,    68,    32,
-      33,    34,    35,    47,    37,   113,    30,    47,    41,     4,
-       5,     6,     7,   121,    23,    24,   113,   125,   113,   116,
-     117,   116,   117,    10,   121,   113,   121,    53,   125,    10,
-     125,     1,   113,   121,    60,    61,   124,   125,    33,   136,
-     121,   136,   113,    45,   125,    15,    10,    17,    34,    35,
-     121,    37,    22,   124,   125,    10,    14,    15,    28,    17,
-      18,    19,    32,    10,     4,     5,    10,    37,     0,     1,
-      46,    89,     4,     5,     6,     7,     8,     9,   125,    11,
-      12,    13,   111,    -1,    16,    55,    56,    -1,    20,    -1,
+       1,    18,     1,    18,    85,    57,    39,     8,     4,     5,
+       6,     7,     4,     5,     6,     7,    29,    30,    17,    21,
+      95,     4,     5,    22,     4,     5,     6,     7,    41,    28,
+      25,    16,    17,     4,     5,     6,     7,    33,    16,    41,
+     121,    33,    14,    28,   119,    25,    18,   122,    21,   101,
+      33,    47,    37,    45,    39,     4,    48,     6,     7,   140,
+     114,    39,    33,     4,     5,     6,     7,    47,    85,    68,
+      85,   125,    29,    30,    45,   129,     8,    62,    63,    64,
+      65,    66,    67,    68,    62,    63,    64,    65,    66,    67,
+      89,    17,    33,    53,     8,    13,    22,   114,    16,   114,
+      60,    61,    20,   120,   121,   120,   121,     8,   125,    37,
+     125,    41,   129,   114,   129,    23,    24,    10,   117,     4,
+       5,     1,    40,   140,   125,   140,    44,    47,   129,   114,
+      34,    35,    45,    37,    25,    15,   114,    17,    30,    10,
+     125,    10,    22,   128,   129,    45,    10,   125,    28,    10,
+     128,   129,    32,    10,   112,    90,    46,    37,     0,     1,
+     129,    -1,     4,     5,     6,     7,     8,     9,    -1,    11,
+      12,    13,    -1,    -1,    16,    55,    56,    -1,    20,    -1,
       22,    32,    33,    34,    35,    -1,    37,    -1,    68,    31,
-      -1,    33,     4,     5,     6,     7,    -1,     9,    40,    11,
-      12,    13,    44,     4,    16,     6,     7,    -1,    20,    26,
+      41,    33,     4,     5,     6,     7,    -1,     9,    40,    11,
+      12,    13,    44,    -1,    16,    -1,    -1,    -1,    20,    26,
       22,     4,     5,     6,     7,    32,    33,    34,    35,    31,
-      37,    33,    -1,    -1,     4,     5,     6,     7,    40,    -1,
-       4,     5,    44,    45,    -1,    -1,    48,    11,    -1,    -1,
-      33,    -1,    16,    -1,    -1,    -1,    39,    -1,    22,    42,
-      43,    -1,    -1,    33,    47,     4,     5,     6,     7,    33,
-       9,    -1,    11,    12,    13,    45,    40,    16,    26,    -1,
+      37,    33,    -1,     4,     5,    -1,    -1,    -1,    40,    -1,
+      11,    -1,    44,    45,    -1,    16,    48,    -1,    -1,    -1,
+      33,    22,    32,    33,    34,    35,    39,    37,    -1,    42,
+      43,    -1,    33,    -1,    47,     4,     5,     6,     7,    40,
+       9,    -1,    11,    12,    13,    -1,    -1,    16,    26,    -1,
       -1,    20,    -1,    22,    32,    33,    34,    35,    -1,    37,
       -1,    -1,    31,    41,    33,     4,     5,     6,     7,    -1,
        9,    40,    11,    12,    13,    44,    45,    16,    -1,     4,
@@ -821,8 +830,8 @@ static const yytype_int16 yycheck[] =
       22,     9,    -1,    11,    12,    -1,    -1,    -1,    16,    31,
       -1,    33,     4,     5,    22,    -1,    -1,    -1,    40,    11,
       -1,    -1,    44,    31,    16,    33,    -1,    -1,    -1,    -1,
-      22,    -1,    40,    14,    15,    -1,    17,    18,    19,    -1,
-      -1,    33,    -1,    -1,    -1,    -1,    -1,    -1,    40
+      22,    -1,    40,    14,    15,    -1,    17,    18,    19,    14,
+      15,    33,    17,    18,    19,    -1,    -1,    -1,    40
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -837,13 +846,14 @@ static const yytype_uint8 yystos[] =
       55,    56,     8,    21,    53,    29,    30,    14,    15,    17,
       18,    19,    26,    32,    33,    34,    35,    37,    40,    58,
       61,    63,    58,    23,    24,    66,    58,    61,    14,    41,
-      41,    41,    41,     4,     5,    45,    64,    58,    58,    47,
-      54,    55,    57,    69,    70,    72,    73,    39,    42,    43,
-      60,    69,    64,    64,    61,    61,    61,    61,    61,    61,
-      63,    47,    67,    68,    56,    70,    10,    10,    45,    72,
-      69,    68,     4,     5,    33,    45,    54,    55,    57,    58,
-      59,    61,    62,    63,    71,    73,    45,    48,    54,    55,
-      56,    72,    48,     4,     5,    71,    15,    56,    46
+      41,    41,    41,     4,     5,    45,    64,    58,    58,    25,
+      47,    54,    55,    57,    69,    70,    72,    73,    39,    42,
+      43,    60,    69,    64,    64,    61,    61,    61,    61,    61,
+      61,    63,    47,    67,    68,    56,    16,    40,    63,    70,
+      10,    10,    45,    72,    69,    68,     4,     5,    33,    45,
+      54,    55,    57,    58,    59,    61,    62,    63,    71,    73,
+      45,    48,    54,    55,    56,    72,    48,     4,     5,    71,
+      15,    56,    46
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1364,175 +1374,175 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
 #line 176 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1368 "parser.cpp"
+#line 1378 "parser.cpp"
         break;
       case 7: /* IDENTIFIER */
 /* Line 1393 of yacc.c  */
 #line 176 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1375 "parser.cpp"
+#line 1385 "parser.cpp"
         break;
       case 16: /* KEYWORD_POS */
 /* Line 1393 of yacc.c  */
 #line 176 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1382 "parser.cpp"
+#line 1392 "parser.cpp"
         break;
       case 23: /* PARAM */
 /* Line 1393 of yacc.c  */
 #line 177 "parser.y"
         { if(((*yyvaluep).str)) free(((*yyvaluep).str)); };
 /* Line 1393 of yacc.c  */
-#line 1389 "parser.cpp"
+#line 1399 "parser.cpp"
         break;
       case 26: /* CMP_OP */
 /* Line 1393 of yacc.c  */
 #line 176 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1396 "parser.cpp"
+#line 1406 "parser.cpp"
         break;
       case 50: /* commands */
 /* Line 1393 of yacc.c  */
 #line 178 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1403 "parser.cpp"
+#line 1413 "parser.cpp"
         break;
       case 51: /* command */
 /* Line 1393 of yacc.c  */
 #line 178 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1410 "parser.cpp"
+#line 1420 "parser.cpp"
         break;
       case 52: /* cmd_plain */
 /* Line 1393 of yacc.c  */
 #line 178 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1417 "parser.cpp"
+#line 1427 "parser.cpp"
         break;
       case 53: /* selection */
 /* Line 1393 of yacc.c  */
 #line 178 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1424 "parser.cpp"
+#line 1434 "parser.cpp"
         break;
       case 57: /* string */
 /* Line 1393 of yacc.c  */
 #line 176 "parser.y"
         { free(((*yyvaluep).str));        };
 /* Line 1393 of yacc.c  */
-#line 1431 "parser.cpp"
+#line 1441 "parser.cpp"
         break;
       case 58: /* sel_expr */
 /* Line 1393 of yacc.c  */
 #line 179 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1438 "parser.cpp"
+#line 1448 "parser.cpp"
         break;
       case 59: /* pos_mod */
 /* Line 1393 of yacc.c  */
 #line 177 "parser.y"
         { if(((*yyvaluep).str)) free(((*yyvaluep).str)); };
 /* Line 1393 of yacc.c  */
-#line 1445 "parser.cpp"
+#line 1455 "parser.cpp"
         break;
       case 61: /* num_expr */
 /* Line 1393 of yacc.c  */
 #line 179 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1452 "parser.cpp"
+#line 1462 "parser.cpp"
         break;
       case 62: /* str_expr */
 /* Line 1393 of yacc.c  */
 #line 179 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1459 "parser.cpp"
+#line 1469 "parser.cpp"
         break;
       case 63: /* pos_expr */
 /* Line 1393 of yacc.c  */
 #line 179 "parser.y"
         { delete ((*yyvaluep).sel);       };
 /* Line 1393 of yacc.c  */
-#line 1466 "parser.cpp"
+#line 1476 "parser.cpp"
         break;
       case 64: /* method_params */
 /* Line 1393 of yacc.c  */
 #line 180 "parser.y"
         { delete ((*yyvaluep).plist);       };
 /* Line 1393 of yacc.c  */
-#line 1473 "parser.cpp"
+#line 1483 "parser.cpp"
         break;
       case 65: /* method_param_list */
 /* Line 1393 of yacc.c  */
 #line 180 "parser.y"
         { delete ((*yyvaluep).plist);       };
 /* Line 1393 of yacc.c  */
-#line 1480 "parser.cpp"
+#line 1490 "parser.cpp"
         break;
       case 66: /* method_param */
 /* Line 1393 of yacc.c  */
 #line 180 "parser.y"
         { delete ((*yyvaluep).param);       };
 /* Line 1393 of yacc.c  */
-#line 1487 "parser.cpp"
+#line 1497 "parser.cpp"
         break;
       case 67: /* value_list */
 /* Line 1393 of yacc.c  */
 #line 181 "parser.y"
         { delete ((*yyvaluep).vlist);       };
 /* Line 1393 of yacc.c  */
-#line 1494 "parser.cpp"
+#line 1504 "parser.cpp"
         break;
       case 68: /* value_list_contents */
 /* Line 1393 of yacc.c  */
 #line 181 "parser.y"
         { delete ((*yyvaluep).vlist);       };
 /* Line 1393 of yacc.c  */
-#line 1501 "parser.cpp"
+#line 1511 "parser.cpp"
         break;
       case 69: /* basic_value_list */
 /* Line 1393 of yacc.c  */
 #line 181 "parser.y"
         { delete ((*yyvaluep).vlist);       };
 /* Line 1393 of yacc.c  */
-#line 1508 "parser.cpp"
+#line 1518 "parser.cpp"
         break;
       case 70: /* basic_value_list_contents */
 /* Line 1393 of yacc.c  */
 #line 181 "parser.y"
         { delete ((*yyvaluep).vlist);       };
 /* Line 1393 of yacc.c  */
-#line 1515 "parser.cpp"
+#line 1525 "parser.cpp"
         break;
       case 71: /* value_item */
 /* Line 1393 of yacc.c  */
 #line 182 "parser.y"
         { delete ((*yyvaluep).val);       };
 /* Line 1393 of yacc.c  */
-#line 1522 "parser.cpp"
+#line 1532 "parser.cpp"
         break;
       case 72: /* basic_value_item */
 /* Line 1393 of yacc.c  */
 #line 182 "parser.y"
         { delete ((*yyvaluep).val);       };
 /* Line 1393 of yacc.c  */
-#line 1529 "parser.cpp"
+#line 1539 "parser.cpp"
         break;
       case 73: /* value_item_range */
 /* Line 1393 of yacc.c  */
 #line 182 "parser.y"
         { delete ((*yyvaluep).val);       };
 /* Line 1393 of yacc.c  */
-#line 1536 "parser.cpp"
+#line 1546 "parser.cpp"
         break;
 
       default:
@@ -2343,8 +2353,8 @@ yyreduce:
 #line 505 "parser.y"
     {
                  BEGIN_ACTION;
-                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
-                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), (yyvsp[(1) - (3)].str), scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (4)].str));
+                 set((yyval.sel), _gmx_sel_init_keyword_of((yyvsp[(2) - (4)].meth), get((yyvsp[(4) - (4)].sel)), (yyvsp[(1) - (4)].str), scanner));
                  CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
@@ -2352,73 +2362,85 @@ yyreduce:
 
   case 47:
 /* Line 1787 of yacc.c  */
-#line 516 "parser.y"
+#line 513 "parser.y"
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
+                 scoped_guard_sfree posmodGuard((yyvsp[(1) - (3)].str));
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), get((yyvsp[(3) - (3)].plist)), (yyvsp[(1) - (3)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
 
   case 48:
 /* Line 1787 of yacc.c  */
-#line 522 "parser.y"
+#line 524 "parser.y"
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
                  END_ACTION;
              }
     break;
 
   case 49:
 /* Line 1787 of yacc.c  */
-#line 528 "parser.y"
+#line 530 "parser.y"
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
                  END_ACTION;
              }
     break;
 
   case 50:
 /* Line 1787 of yacc.c  */
-#line 534 "parser.y"
+#line 536 "parser.y"
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
                  END_ACTION;
              }
     break;
 
   case 51:
 /* Line 1787 of yacc.c  */
-#line 540 "parser.y"
+#line 542 "parser.y"
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
                  END_ACTION;
              }
     break;
 
   case 52:
 /* Line 1787 of yacc.c  */
-#line 546 "parser.y"
+#line 548 "parser.y"
     {
                  BEGIN_ACTION;
-                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
                  END_ACTION;
              }
     break;
 
   case 53:
 /* Line 1787 of yacc.c  */
-#line 551 "parser.y"
-    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+#line 554 "parser.y"
+    {
+                 BEGIN_ACTION;
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
+                 END_ACTION;
+             }
     break;
 
   case 54:
 /* Line 1787 of yacc.c  */
 #line 559 "parser.y"
+    { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
+    break;
+
+  case 55:
+/* Line 1787 of yacc.c  */
+#line 567 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionTreeElementPointer sel(
@@ -2431,9 +2453,9 @@ yyreduce:
              }
     break;
 
-  case 55:
+  case 56:
 /* Line 1787 of yacc.c  */
-#line 570 "parser.y"
+#line 578 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree posmodGuard((yyvsp[(1) - (2)].str));
@@ -2443,9 +2465,9 @@ yyreduce:
              }
     break;
 
-  case 56:
+  case 57:
 /* Line 1787 of yacc.c  */
-#line 585 "parser.y"
+#line 593 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r)));
@@ -2453,15 +2475,15 @@ yyreduce:
              }
     break;
 
-  case 57:
+  case 58:
 /* Line 1787 of yacc.c  */
-#line 593 "parser.y"
+#line 601 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
-  case 58:
+  case 59:
 /* Line 1787 of yacc.c  */
-#line 598 "parser.y"
+#line 606 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_method((yyvsp[(1) - (2)].meth), get((yyvsp[(2) - (2)].plist)), NULL, scanner));
@@ -2470,9 +2492,9 @@ yyreduce:
              }
     break;
 
-  case 59:
+  case 60:
 /* Line 1787 of yacc.c  */
-#line 608 "parser.y"
+#line 616 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree keywordGuard((yyvsp[(1) - (3)].str));
@@ -2482,9 +2504,9 @@ yyreduce:
              }
     break;
 
-  case 60:
+  case 61:
 /* Line 1787 of yacc.c  */
-#line 622 "parser.y"
+#line 630 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2492,9 +2514,9 @@ yyreduce:
              }
     break;
 
-  case 61:
+  case 62:
 /* Line 1787 of yacc.c  */
-#line 630 "parser.y"
+#line 638 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2502,9 +2524,9 @@ yyreduce:
              }
     break;
 
-  case 62:
+  case 63:
 /* Line 1787 of yacc.c  */
-#line 638 "parser.y"
+#line 646 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
@@ -2512,21 +2534,21 @@ yyreduce:
              }
     break;
 
-  case 63:
+  case 64:
 /* Line 1787 of yacc.c  */
-#line 651 "parser.y"
+#line 659 "parser.y"
     { (yyval.plist) = (yyvsp[(1) - (1)].plist); }
     break;
 
-  case 64:
+  case 65:
 /* Line 1787 of yacc.c  */
-#line 653 "parser.y"
+#line 661 "parser.y"
     { (yyval.plist) = (yyvsp[(1) - (2)].plist); }
     break;
 
-  case 65:
+  case 66:
 /* Line 1787 of yacc.c  */
-#line 658 "parser.y"
+#line 666 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.plist), SelectionParserParameter::createList());
@@ -2534,9 +2556,9 @@ yyreduce:
              }
     break;
 
-  case 66:
+  case 67:
 /* Line 1787 of yacc.c  */
-#line 664 "parser.y"
+#line 672 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserParameterListPointer list(get((yyvsp[(1) - (2)].plist)));
@@ -2546,9 +2568,9 @@ yyreduce:
              }
     break;
 
-  case 67:
+  case 68:
 /* Line 1787 of yacc.c  */
-#line 675 "parser.y"
+#line 683 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree nameGuard((yyvsp[(1) - (2)].str));
@@ -2557,21 +2579,21 @@ yyreduce:
              }
     break;
 
-  case 68:
+  case 69:
 /* Line 1787 of yacc.c  */
-#line 683 "parser.y"
+#line 691 "parser.y"
     { (yyval.vlist) = (yyvsp[(1) - (1)].vlist);   }
     break;
 
-  case 69:
+  case 70:
 /* Line 1787 of yacc.c  */
-#line 684 "parser.y"
+#line 692 "parser.y"
     { (yyval.vlist) = (yyvsp[(2) - (3)].vlist);   }
     break;
 
-  case 70:
+  case 71:
 /* Line 1787 of yacc.c  */
-#line 689 "parser.y"
+#line 697 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList());
@@ -2579,9 +2601,9 @@ yyreduce:
              }
     break;
 
-  case 71:
+  case 72:
 /* Line 1787 of yacc.c  */
-#line 695 "parser.y"
+#line 703 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2591,9 +2613,9 @@ yyreduce:
              }
     break;
 
-  case 72:
+  case 73:
 /* Line 1787 of yacc.c  */
-#line 703 "parser.y"
+#line 711 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
@@ -2603,21 +2625,21 @@ yyreduce:
              }
     break;
 
-  case 73:
+  case 74:
 /* Line 1787 of yacc.c  */
-#line 713 "parser.y"
+#line 721 "parser.y"
     { (yyval.vlist) = (yyvsp[(1) - (1)].vlist); }
     break;
 
-  case 74:
+  case 75:
 /* Line 1787 of yacc.c  */
-#line 714 "parser.y"
+#line 722 "parser.y"
     { (yyval.vlist) = (yyvsp[(2) - (3)].vlist); }
     break;
 
-  case 75:
+  case 76:
 /* Line 1787 of yacc.c  */
-#line 719 "parser.y"
+#line 727 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.vlist), SelectionParserValue::createList(get((yyvsp[(1) - (1)].val))));
@@ -2625,9 +2647,9 @@ yyreduce:
              }
     break;
 
-  case 76:
+  case 77:
 /* Line 1787 of yacc.c  */
-#line 725 "parser.y"
+#line 733 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (2)].vlist)));
@@ -2637,9 +2659,9 @@ yyreduce:
              }
     break;
 
-  case 77:
+  case 78:
 /* Line 1787 of yacc.c  */
-#line 733 "parser.y"
+#line 741 "parser.y"
     {
                  BEGIN_ACTION;
                  SelectionParserValueListPointer list(get((yyvsp[(1) - (3)].vlist)));
@@ -2649,9 +2671,9 @@ yyreduce:
              }
     break;
 
-  case 78:
+  case 79:
 /* Line 1787 of yacc.c  */
-#line 743 "parser.y"
+#line 751 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2659,9 +2681,9 @@ yyreduce:
              }
     break;
 
-  case 79:
+  case 80:
 /* Line 1787 of yacc.c  */
-#line 749 "parser.y"
+#line 757 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2669,9 +2691,9 @@ yyreduce:
              }
     break;
 
-  case 80:
+  case 81:
 /* Line 1787 of yacc.c  */
-#line 755 "parser.y"
+#line 763 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2679,9 +2701,9 @@ yyreduce:
              }
     break;
 
-  case 81:
+  case 82:
 /* Line 1787 of yacc.c  */
-#line 761 "parser.y"
+#line 769 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createExpr(get((yyvsp[(1) - (1)].sel))));
@@ -2689,15 +2711,15 @@ yyreduce:
              }
     break;
 
-  case 82:
+  case 83:
 /* Line 1787 of yacc.c  */
-#line 766 "parser.y"
+#line 774 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
-  case 83:
+  case 84:
 /* Line 1787 of yacc.c  */
-#line 771 "parser.y"
+#line 779 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createInteger((yyvsp[(1) - (1)].i)));
@@ -2705,9 +2727,9 @@ yyreduce:
              }
     break;
 
-  case 84:
+  case 85:
 /* Line 1787 of yacc.c  */
-#line 777 "parser.y"
+#line 785 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createReal((yyvsp[(1) - (1)].r)));
@@ -2715,9 +2737,9 @@ yyreduce:
              }
     break;
 
-  case 85:
+  case 86:
 /* Line 1787 of yacc.c  */
-#line 783 "parser.y"
+#line 791 "parser.y"
     {
                  BEGIN_ACTION;
                  scoped_guard_sfree stringGuard((yyvsp[(1) - (1)].str));
@@ -2726,15 +2748,15 @@ yyreduce:
              }
     break;
 
-  case 86:
+  case 87:
 /* Line 1787 of yacc.c  */
-#line 789 "parser.y"
+#line 797 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
-  case 87:
+  case 88:
 /* Line 1787 of yacc.c  */
-#line 794 "parser.y"
+#line 802 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createIntegerRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].i)));
@@ -2742,9 +2764,9 @@ yyreduce:
              }
     break;
 
-  case 88:
+  case 89:
 /* Line 1787 of yacc.c  */
-#line 800 "parser.y"
+#line 808 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].i), (yyvsp[(3) - (3)].r)));
@@ -2752,9 +2774,9 @@ yyreduce:
              }
     break;
 
-  case 89:
+  case 90:
 /* Line 1787 of yacc.c  */
-#line 806 "parser.y"
+#line 814 "parser.y"
     {
                  BEGIN_ACTION;
                  set((yyval.val), SelectionParserValue::createRealRange((yyvsp[(1) - (3)].r), (yyvsp[(3) - (3)].r)));
@@ -2764,7 +2786,7 @@ yyreduce:
 
 
 /* Line 1787 of yacc.c  */
-#line 2768 "parser.cpp"
+#line 2790 "parser.cpp"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
index bbd080f8fabf919ca7cba36c93a6c1d913cffa34..384c6fdaa2eec21e17440cceca599c6e69aaf753 100644 (file)
@@ -501,6 +501,14 @@ num_expr:    pos_mod KEYWORD_NUMERIC    %prec NUM_REDUCT
                  CHECK_SEL($$);
                  END_ACTION;
              }
+           | pos_mod KEYWORD_NUMERIC OF pos_expr
+             {
+                 BEGIN_ACTION;
+                 scoped_guard_sfree posmodGuard($1);
+                 set($$, _gmx_sel_init_keyword_of($2, get($4), $1, scanner));
+                 CHECK_SEL($$);
+                 END_ACTION;
+             }
            | pos_mod METHOD_NUMERIC method_params
              {
                  BEGIN_ACTION;
index 14d5d27dbdaddb8dc4d518fd3bbd6f7130c6ad4a..6bb7bd4a9b6fb87429f0b29c59af809e44723b15 100644 (file)
@@ -746,6 +746,30 @@ _gmx_sel_init_keyword_strmatch(gmx_ana_selmethod_t *method,
     return init_keyword_internal(method, matchType, move(args), rpost, scanner);
 }
 
+/*!
+ * \param[in]  method Method to use for initialization.
+ * \param[in]  group  Selection in which the keyword should be evaluated.
+ * \param[in]  rpost  Reference position type to use (NULL = default).
+ * \param[in]  scanner Scanner data structure.
+ * \returns    The created selection element.
+ *
+ * This function handles the creation of a gmx::SelectionTreeElement object for
+ * expressions like "z of ...".
+ */
+SelectionTreeElementPointer
+_gmx_sel_init_keyword_of(gmx_ana_selmethod_t                    *method,
+                         const gmx::SelectionTreeElementPointer &group,
+                         const char *rpost, yyscan_t scanner)
+{
+    gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[128];
+    sprintf(buf, "In '%s of'", method->name);
+    gmx::MessageStringContext    context(errors, buf);
+
+    GMX_UNUSED_VALUE(rpost);
+    return _gmx_sel_init_keyword_evaluator(method, group, scanner);
+}
+
 /*!
  * \param[in]  method Method to use for initialization.
  * \param[in]  params Pointer to the first parameter.
index db88f45e92da056f0a5d6c8d9c6e87360141e2bb..d84d68cea82053aef70b3a4b9a15a98c1db166ff 100644 (file)
@@ -431,6 +431,11 @@ _gmx_sel_init_keyword_strmatch(struct gmx_ana_selmethod_t *method,
                                gmx::SelectionStringMatchType matchType,
                                gmx::SelectionParserValueListPointer args,
                                const char *rpost, void *scanner);
+/** Creates a gmx::SelectionTreeElement for "keyword of" expression. */
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_keyword_of(struct gmx_ana_selmethod_t *method,
+                         const gmx::SelectionTreeElementPointer &group,
+                         const char *rpost, void *scanner);
 /** Creates a gmx::SelectionTreeElement for a method expression from the parsed data. */
 gmx::SelectionTreeElementPointer
 _gmx_sel_init_method(struct gmx_ana_selmethod_t *method,
index f13031fd1a4e3abe373d96630217292775a97794..446bc99e4bd70578cfeea16898d0d0eaecf4e74a 100644 (file)
@@ -129,8 +129,10 @@ init_method_token(YYSTYPE *yylval, gmx_ana_selmethod_t *method, bool bPosMod,
         /* Keyword */
         switch (method->type)
         {
-            case INT_VALUE:   return KEYWORD_NUMERIC;
-            case REAL_VALUE:  return KEYWORD_NUMERIC;
+            case INT_VALUE:
+            case REAL_VALUE:
+                state->bMatchOf = true;
+                return KEYWORD_NUMERIC;
             case STR_VALUE:   return KEYWORD_STR;
             case GROUP_VALUE: return KEYWORD_GROUP;
             default:
index 4a52815f378e9bc15b1bf8cc47196309d4dc19ff..1e79117b77f4827ac990f46d9f266522d00d8b97 100644 (file)
@@ -398,7 +398,10 @@ const char *const SyntaxHelpText::text[] = {
     "evaluation order.[BR]",
     "3. [TT]ATOM_EXPR[tt] expressions can be converted into [TT]POS_EXPR[tt]",
     "expressions in various ways, see the \"positions\" subtopic for more",
-    "details.[PAR]",
+    "details.[BR]",
+    "4. [TT]POS_EXPR[tt] can be converted into [TT]NUM_EXPR[tt] using syntax",
+    "like \"x of POS_EXPR\". Currently, this is only supported for single",
+    "positions like in expression \"x of cog of ATOM_EXPR\".[PAR]",
 
     "Some keywords select atoms based on string values such as the atom name.",
     "For these keywords, it is possible to use wildcards ([TT]name \"C*\"[tt])",
index 32d478ed00bfd63ae5f1de79aba80027d0721198..0081200389bfff4841bdcf0ec905d7e6317be3b4 100644 (file)
 #include <boost/shared_ptr.hpp>
 
 #include "gromacs/legacyheaders/macros.h"
+#include "gromacs/selection/position.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxregex.h"
 #include "gromacs/utility/messagestringcollector.h"
 #include "gromacs/utility/smalloc.h"
@@ -363,27 +365,67 @@ free_data_kweval(void *data);
 /** Initializes frame evaluation for keyword evaluation in an arbitrary group. */
 static void
 init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
-/** Evaluates keywords in an arbitrary group. */
+/*! \brief
+ * Evaluates keywords in an arbitrary group.
+ *
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_kweval.
+ *
+ * Calls the evaluation function of the wrapped keyword with the given
+ * parameters, with the exception of using \c t_methoddata_kweval::g for the
+ * evaluation group.
+ */
 static void
-evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data);
+evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t *g,
+                gmx_ana_selvalue_t *out, void *data);
+/*! \brief
+ * Evaluates keywords in an arbitrary set of positions.
+ *
+ * See sel_updatefunc() for description of the parameters.
+ * \p data should point to a \c t_methoddata_kweval.
+ *
+ * Calls the evaluation function of the wrapped keyword with the given
+ * parameters, with the exception of using \c t_methoddata_kweval::p for the
+ * evaluation positions.
+ */
+static void
+evaluate_kweval_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t *g,
+                    gmx_ana_selvalue_t *out, void *data);
 
 /*! \internal \brief
  * Data structure for keyword evaluation in arbitrary groups.
  */
-typedef struct
+struct t_methoddata_kweval
 {
-    /** Wrapped keyword method for evaluating the values. */
+    //! Initialize new keyword evaluator for the given keyword.
+    t_methoddata_kweval(gmx_ana_selmethod_t *method, void *data)
+        : kwmethod(method), kwmdata(data)
+    {
+        gmx_ana_index_clear(&g);
+    }
+    ~t_methoddata_kweval()
+    {
+        _gmx_selelem_free_method(kwmethod, kwmdata);
+    }
+
+    //! Wrapped keyword method for evaluating the values.
     gmx_ana_selmethod_t  *kwmethod;
-    /** Method data for \p kwmethod. */
+    //! Method data for \p kwmethod.
     void                 *kwmdata;
-    /** Group in which \p kwmethod should be evaluated. */
+    //! Group in which \p kwmethod should be evaluated.
     gmx_ana_index_t       g;
-} t_methoddata_kweval;
+    //! Positions for which \p kwmethod should be evaluated.
+    gmx_ana_pos_t         p;
+};
 
 /** Parameters for keyword evaluation in an arbitrary group. */
-static gmx_ana_selparam_t smparams_kweval[] = {
+static gmx_ana_selparam_t smparams_kweval_group[] = {
     {NULL,   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
 };
+/** Parameters for keyword evaluation from positions. */
+static gmx_ana_selparam_t smparams_kweval_pos[] = {
+    {NULL,   {POS_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
+};
 
 
 /********************************************************************
@@ -635,7 +677,7 @@ evaluate_keyword_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* p
 static void
 init_kweval(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
 {
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+    t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
     d->kwmethod->init(top, 0, NULL, d->kwmdata);
 }
@@ -643,7 +685,7 @@ init_kweval(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, v
 static void
 init_output_kweval(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
 {
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+    t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
     out->nr = d->g.isize;
     _gmx_selvalue_reserve(out, out->nr);
@@ -657,10 +699,9 @@ init_output_kweval(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
 static void
 free_data_kweval(void *data)
 {
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+    t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
-    _gmx_selelem_free_method(d->kwmethod, d->kwmdata);
-    sfree(d);
+    delete d;
 }
 
 /*!
@@ -676,69 +717,65 @@ free_data_kweval(void *data)
 static void
 init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
 {
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+    t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
     d->kwmethod->init_frame(top, fr, pbc, d->kwmdata);
 }
 
-/*!
- * See sel_updatefunc() for description of the parameters.
- * \p data should point to a \c t_methoddata_kweval.
- *
- * Calls the evaluation function of the wrapped keyword with the given
- * parameters, with the exception of using \c t_methoddata_kweval::g for the
- * evaluation group.
- */
 static void
 evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
                 gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
 {
-    t_methoddata_kweval *d = (t_methoddata_kweval *)data;
+    t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
 
     d->kwmethod->update(top, fr, pbc, &d->g, out, d->kwmdata);
 }
 
-/*!
+static void
+evaluate_kweval_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+                    gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
+{
+    t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
+
+    d->kwmethod->pupdate(top, fr, pbc, &d->p, out, d->kwmdata);
+}
+
+/*! \brief
+ * Initializes a selection element for evaluating a keyword in a given group.
+ *
  * \param[in]   method  Keyword selection method to evaluate.
- * \param[in]   params  Parameter that gives the group to evaluate \p method in.
+ * \param[in]   params  Parameters to pass to initialization (the child group).
  * \param[in]   scanner Scanner data structure.
  * \returns     Pointer to the created selection element (NULL on error).
  *
- * Creates a \ref SEL_EXPRESSION selection element that evaluates the keyword
- * method given by \p method in the group given by \p param.
- *
- * The name of \p param should be empty.
+ * Implements _gmx_sel_init_keyword_evaluator() for \ref GROUP_VALUE input
+ * selections.
  */
-gmx::SelectionTreeElementPointer
-_gmx_sel_init_keyword_evaluator(gmx_ana_selmethod_t                     *method,
-                                const gmx::SelectionParserParameterList &params,
-                                void                                    *scanner)
+static gmx::SelectionTreeElementPointer
+init_evaluator_group(gmx_ana_selmethod_t                     *method,
+                     const gmx::SelectionParserParameterList &params,
+                     void                                    *scanner)
 {
-    gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
-    char  buf[1024];
-    sprintf(buf, "In evaluation of '%s'", method->name);
-    gmx::MessageStringContext   context(errors, buf);
-
     if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
         || method->outinit || method->pupdate)
     {
-        GMX_THROW(gmx::InternalError(
-                          "Unsupported keyword method for arbitrary group evaluation"));
+        std::string message = gmx::formatString(
+                    "Keyword '%s' cannot be evaluated in this context",
+                    method->name);
+        GMX_THROW(gmx::InvalidInputError(message));
     }
 
     gmx::SelectionTreeElementPointer sel(
             new gmx::SelectionTreeElement(SEL_EXPRESSION));
     _gmx_selelem_set_method(sel, method, scanner);
 
-    t_methoddata_kweval  *data;
-    snew(data, 1);
-    data->kwmethod = sel->u.expr.method;
-    data->kwmdata  = sel->u.expr.mdata;
-    gmx_ana_index_clear(&data->g);
+    t_methoddata_kweval *data
+        = new t_methoddata_kweval(sel->u.expr.method, sel->u.expr.mdata);
 
     snew(sel->u.expr.method, 1);
-    memcpy(sel->u.expr.method, data->kwmethod, sizeof(gmx_ana_selmethod_t));
-    sel->u.expr.method->flags       |= SMETH_VARNUMVAL;
+    sel->u.expr.method->name         = data->kwmethod->name;
+    sel->u.expr.method->type         = data->kwmethod->type;
+    sel->u.expr.method->flags        = data->kwmethod->flags | SMETH_VARNUMVAL;
     sel->u.expr.method->init_data    = NULL;
     sel->u.expr.method->set_poscoll  = NULL;
     sel->u.expr.method->init         = method->init ? &init_kweval : NULL;
@@ -747,8 +784,8 @@ _gmx_sel_init_keyword_evaluator(gmx_ana_selmethod_t                     *method,
     sel->u.expr.method->init_frame   = method->init_frame ? &init_frame_kweval : NULL;
     sel->u.expr.method->update       = &evaluate_kweval;
     sel->u.expr.method->pupdate      = NULL;
-    sel->u.expr.method->nparams      = asize(smparams_kweval);
-    sel->u.expr.method->param        = smparams_kweval;
+    sel->u.expr.method->nparams      = asize(smparams_kweval_group);
+    sel->u.expr.method->param        = smparams_kweval_group;
     _gmx_selelem_init_method_params(sel, scanner);
     sel->u.expr.mdata = data;
 
@@ -761,3 +798,89 @@ _gmx_sel_init_keyword_evaluator(gmx_ana_selmethod_t                     *method,
     }
     return sel;
 }
+
+/*! \brief
+ * Initializes a selection element for evaluating a keyword in given positions.
+ *
+ * \param[in]   method  Keyword selection method to evaluate.
+ * \param[in]   params  Parameters to pass to initialization (the child positions).
+ * \param[in]   scanner Scanner data structure.
+ * \returns     Pointer to the created selection element (NULL on error).
+ *
+ * Implements _gmx_sel_init_keyword_evaluator() for \ref POS_VALUE input
+ * selections.
+ */
+static gmx::SelectionTreeElementPointer
+init_evaluator_pos(gmx_ana_selmethod_t                     *method,
+                   const gmx::SelectionParserParameterList &params,
+                   void                                    *scanner)
+{
+    if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
+        || method->outinit || method->pupdate == NULL)
+    {
+        std::string message = gmx::formatString(
+                    "Keyword '%s' cannot be evaluated in this context",
+                    method->name);
+        GMX_THROW(gmx::InvalidInputError(message));
+    }
+
+    gmx::SelectionTreeElementPointer sel(
+            new gmx::SelectionTreeElement(SEL_EXPRESSION));
+    _gmx_selelem_set_method(sel, method, scanner);
+
+    t_methoddata_kweval *data
+        = new t_methoddata_kweval(sel->u.expr.method, sel->u.expr.mdata);
+
+    snew(sel->u.expr.method, 1);
+    sel->u.expr.method->name         = data->kwmethod->name;
+    sel->u.expr.method->type         = data->kwmethod->type;
+    sel->u.expr.method->flags        = data->kwmethod->flags | SMETH_SINGLEVAL;
+    sel->u.expr.method->init_data    = NULL;
+    sel->u.expr.method->set_poscoll  = NULL;
+    sel->u.expr.method->init         = method->init ? &init_kweval : NULL;
+    sel->u.expr.method->outinit      = NULL;
+    sel->u.expr.method->free         = &free_data_kweval;
+    sel->u.expr.method->init_frame   = method->init_frame ? &init_frame_kweval : NULL;
+    sel->u.expr.method->update       = &evaluate_kweval_pos;
+    sel->u.expr.method->pupdate      = NULL;
+    sel->u.expr.method->nparams      = asize(smparams_kweval_pos);
+    sel->u.expr.method->param        = smparams_kweval_pos;
+    _gmx_selelem_init_method_params(sel, scanner);
+    sel->u.expr.mdata = data;
+
+    sel->u.expr.method->param[0].val.u.p = &data->p;
+
+    if (!_gmx_sel_parse_params(params, sel->u.expr.method->nparams,
+                               sel->u.expr.method->param, sel, scanner))
+    {
+        return gmx::SelectionTreeElementPointer();
+    }
+    return sel;
+}
+
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_keyword_evaluator(gmx_ana_selmethod_t                    *method,
+                                const gmx::SelectionTreeElementPointer &child,
+                                void                                   *scanner)
+{
+    gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
+    char  buf[1024];
+    sprintf(buf, "In evaluation of '%s'", method->name);
+    gmx::MessageStringContext            context(errors, buf);
+
+    gmx::SelectionParserParameterList    params;
+    params.push_back(
+            gmx::SelectionParserParameter::createFromExpression(NULL, child));
+    if (child->v.type == GROUP_VALUE)
+    {
+        return init_evaluator_group(method, params, scanner);
+    }
+    else if (child->v.type == POS_VALUE)
+    {
+        return init_evaluator_pos(method, params, scanner);
+    }
+    else
+    {
+        GMX_THROW(gmx::InvalidInputError("Invalid expression for keyword evaluation group"));
+    }
+}
index cb8126171bb215283086f6f3dc560c3458187d5d..6362cc5b8ec6a235e54deea16ecffa22286a9e23 100644 (file)
@@ -265,17 +265,18 @@ _gmx_selelem_custom_init_same(gmx_ana_selmethod_t                           **me
     gmx::SelectionParserParameterList::iterator asparam = ++params->begin();
     if (asparam != params->end() && asparam->name() == sm_same.param[1].name)
     {
-        gmx::SelectionParserParameterList    kwparams;
-        gmx::SelectionParserValueListPointer values(
-                new gmx::SelectionParserValueList(asparam->values()));
-        kwparams.push_back(
-                gmx::SelectionParserParameter::create(NULL, move(values)));
-
+        const gmx::SelectionParserValueList &asvalues = asparam->values();
+        if (asvalues.size() != 1 || !asvalues.front().hasExpressionValue())
+        {
+            _gmx_selparser_error(scanner, "'same ... as' should be followed by a single expression");
+            return -1;
+        }
+        const gmx::SelectionTreeElementPointer &child = asvalues.front().expr;
         /* Create a second keyword evaluation element for the keyword given as
          * the first parameter, evaluating the keyword in the group given by the
          * second parameter. */
         gmx::SelectionTreeElementPointer kwelem
-            = _gmx_sel_init_keyword_evaluator(kwmethod, kwparams, scanner);
+            = _gmx_sel_init_keyword_evaluator(kwmethod, child, scanner);
         // FIXME: Use exceptions.
         if (!kwelem)
         {
diff --git a/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesKeywordOfPositions.xml b/src/gromacs/selection/tests/refdata/SelectionCollectionDataTest_HandlesKeywordOfPositions.xml
new file mode 100644 (file)
index 0000000..e728c55
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+  <ParsedSelections Name="Parsed">
+    <ParsedSelection Name="Selection1">
+      <String Name="Input">x &lt; y of cog of resnr 2</String>
+      <String Name="Text">x &lt; y of cog of resnr 2</String>
+      <Bool Name="Dynamic">true</Bool>
+    </ParsedSelection>
+  </ParsedSelections>
+  <CompiledSelections Name="Compiled">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">15</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+        <Int>8</Int>
+        <Int>9</Int>
+        <Int>10</Int>
+        <Int>11</Int>
+        <Int>12</Int>
+        <Int>13</Int>
+        <Int>14</Int>
+      </Sequence>
+    </Selection>
+  </CompiledSelections>
+  <EvaluatedSelections Name="Frame1">
+    <Selection Name="Selection1">
+      <Sequence Name="Atoms">
+        <Int Name="Length">8</Int>
+        <Int>0</Int>
+        <Int>1</Int>
+        <Int>2</Int>
+        <Int>3</Int>
+        <Int>4</Int>
+        <Int>5</Int>
+        <Int>6</Int>
+        <Int>7</Int>
+      </Sequence>
+    </Selection>
+  </EvaluatedSelections>
+</ReferenceData>
index aa4bd522357cdcc0251201830982a01aeff9aae4..0776b003e330bd7acde67e325c8d4cdb6a02d9bc 100644 (file)
@@ -1137,6 +1137,16 @@ TEST_F(SelectionCollectionDataTest, HandlesPositionModifiersForMethods)
 }
 
 
+TEST_F(SelectionCollectionDataTest, HandlesKeywordOfPositions)
+{
+    static const char * const selections[] = {
+        "x < y of cog of resnr 2"
+    };
+    setFlags(TestFlags() | efTestEvaluation);
+    runTest("simple.gro", selections);
+}
+
+
 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
 {
     static const char * const selections[] = {