Refactor for testing interactive selection input
[alexxy/gromacs.git] / src / gromacs / selection / scanner_internal.cpp
index d7feb7d042ee8b56cd20db6af7d68119b9567926..d66d647b58dfb524cc635ae20429cea8ae68ccdc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2009,2010,2011,2012,2014, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,2012,2014,2015, 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.
@@ -53,6 +53,8 @@
  */
 #include "gmxpre.h"
 
+#include "scanner_internal.h"
+
 #include <stdlib.h>
 #include <string.h>
 
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/messagestringcollector.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringutil.h"
 
+#include "parser.h"
 #include "parsetree.h"
+#include "scanner.h"
 #include "selectioncollection-impl.h"
 #include "selelem.h"
 #include "selmethod.h"
 #include "symrec.h"
 
-#include "parser.h"
-#include "scanner.h"
-#include "scanner_internal.h"
-
 /*! \brief
  * Step in which the allocated memory for pretty-printed input is incremented.
  */
@@ -113,24 +112,30 @@ init_param_token(YYSTYPE *yylval, gmx_ana_selparam_t *param, bool bBoolNo)
  * Processes a selection method token.
  */
 static int
-init_method_token(YYSTYPE *yylval, gmx_ana_selmethod_t *method, bool bPosMod,
-                  gmx_sel_lexer_t *state)
+init_method_token(YYSTYPE *yylval, YYLTYPE *yylloc,
+                  const gmx::SelectionParserSymbol *symbol,
+                  bool bPosMod, gmx_sel_lexer_t *state)
 {
+    gmx_ana_selmethod_t *method = symbol->methodValue();
     /* If the previous token was not KEYWORD_POS, return EMPTY_POSMOD
      * before the actual method to work around a limitation in Bison. */
     if (!bPosMod && method->type != POS_VALUE)
     {
-        state->nextmethod = method;
+        state->nextMethodSymbol = symbol;
+        _gmx_sel_lexer_add_token(yylloc, NULL, 0, state);
         return EMPTY_POSMOD;
     }
+    _gmx_sel_lexer_add_token(yylloc, symbol->name().c_str(), -1, state);
     yylval->meth = method;
     if (!(method->flags & SMETH_MODIFIER) && method->nparams == 0)
     {
         /* 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:
@@ -182,7 +187,8 @@ init_method_token(YYSTYPE *yylval, gmx_ana_selmethod_t *method, bool bPosMod,
 }
 
 int
-_gmx_sel_lexer_process_pending(YYSTYPE *yylval, gmx_sel_lexer_t *state)
+_gmx_sel_lexer_process_pending(YYSTYPE *yylval, YYLTYPE *yylloc,
+                               gmx_sel_lexer_t *state)
 {
     if (state->nextparam)
     {
@@ -192,29 +198,30 @@ _gmx_sel_lexer_process_pending(YYSTYPE *yylval, gmx_sel_lexer_t *state)
         if (state->neom > 0)
         {
             --state->neom;
+            _gmx_sel_lexer_add_token(yylloc, NULL, 0, state);
             return END_OF_METHOD;
         }
         state->nextparam = NULL;
         state->bBoolNo   = false;
-        _gmx_sel_lexer_add_token(param->name, -1, state);
+        _gmx_sel_lexer_add_token(yylloc, param->name, -1, state);
         return init_param_token(yylval, param, bBoolNo);
     }
     if (state->prev_pos_kw > 0)
     {
         --state->prev_pos_kw;
     }
-    if (state->nextmethod)
+    if (state->nextMethodSymbol)
     {
-        gmx_ana_selmethod_t *method = state->nextmethod;
-
-        state->nextmethod = NULL;
-        return init_method_token(yylval, method, true, state);
+        const gmx::SelectionParserSymbol *symbol = state->nextMethodSymbol;
+        state->nextMethodSymbol = NULL;
+        return init_method_token(yylval, yylloc, symbol, true, state);
     }
     return 0;
 }
 
 int
-_gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
+_gmx_sel_lexer_process_identifier(YYSTYPE *yylval, YYLTYPE *yylloc,
+                                  char *yytext, size_t yyleng,
                                   gmx_sel_lexer_t *state)
 {
     /* Check if the identifier matches with a parameter name */
@@ -267,23 +274,28 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
                 state->bBoolNo   = bBoolNo;
                 return END_OF_METHOD;
             }
-            _gmx_sel_lexer_add_token(param->name, -1, state);
+            _gmx_sel_lexer_add_token(yylloc, param->name, -1, state);
             return init_param_token(yylval, param, bBoolNo);
         }
     }
 
     /* Check if the identifier matches with a symbol */
     const gmx::SelectionParserSymbol *symbol
-        = state->sc->symtab->findSymbol(std::string(yytext, yyleng), false);
+        = state->sc->symtab->findSymbol(std::string(yytext, yyleng));
     /* If there is no match, return the token as a string */
     if (!symbol)
     {
         yylval->str = gmx_strndup(yytext, yyleng);
-        _gmx_sel_lexer_add_token(yytext, yyleng, state);
+        _gmx_sel_lexer_add_token(yylloc, yytext, yyleng, state);
         return IDENTIFIER;
     }
-    _gmx_sel_lexer_add_token(symbol->name().c_str(), -1, state);
     gmx::SelectionParserSymbol::SymbolType symtype = symbol->type();
+    /* For method symbols, we need some extra processing. */
+    if (symtype == gmx::SelectionParserSymbol::MethodSymbol)
+    {
+        return init_method_token(yylval, yylloc, symbol, state->prev_pos_kw > 0, state);
+    }
+    _gmx_sel_lexer_add_token(yylloc, symbol->name().c_str(), -1, state);
     /* Reserved symbols should have been caught earlier */
     if (symtype == gmx::SelectionParserSymbol::ReservedSymbol)
     {
@@ -326,12 +338,6 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
         }
         /* This position should not be reached. */
     }
-    /* For method symbols, return the correct type */
-    if (symtype == gmx::SelectionParserSymbol::MethodSymbol)
-    {
-        gmx_ana_selmethod_t *method = symbol->methodValue();
-        return init_method_token(yylval, method, state->prev_pos_kw > 0, state);
-    }
     /* For position symbols, we need to return KEYWORD_POS, but we also need
      * some additional handling. */
     if (symtype == gmx::SelectionParserSymbol::PositionSymbol)
@@ -346,8 +352,10 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
 }
 
 void
-_gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state)
+_gmx_sel_lexer_add_token(YYLTYPE *yylloc, const char *str, int len,
+                         gmx_sel_lexer_t *state)
 {
+    yylloc->startIndex = yylloc->endIndex = state->pslen;
     /* Do nothing if the string is empty, or if it is a space and there is
      * no other text yet, or if there already is a space. */
     if (!str || len == 0 || strlen(str) == 0
@@ -371,12 +379,13 @@ _gmx_sel_lexer_add_token(const char *str, int len, gmx_sel_lexer_t *state)
     strncpy(state->pselstr + state->pslen, str, len);
     state->pslen                += len;
     state->pselstr[state->pslen] = 0;
+    yylloc->endIndex             = state->pslen;
 }
 
 void
 _gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
-                    bool bInteractive, int maxnr, bool bGroups,
-                    struct gmx_ana_indexgrps_t *grps)
+                    gmx::TextWriter *statusWriter, int maxnr,
+                    bool bGroups, struct gmx_ana_indexgrps_t *grps)
 {
     int rc = _gmx_sel_yylex_init(scannerp);
     if (rc != 0)
@@ -388,30 +397,31 @@ _gmx_sel_init_lexer(yyscan_t *scannerp, struct gmx_ana_selcollection_t *sc,
     gmx_sel_lexer_t *state = new gmx_sel_lexer_t;
 
     state->sc        = sc;
-    state->errors    = NULL;
     state->bGroups   = bGroups;
     state->grps      = grps;
     state->nexpsel   = (maxnr > 0 ? static_cast<int>(sc->sel.size()) + maxnr : -1);
 
-    state->bInteractive = bInteractive;
+    state->statusWriter = statusWriter;
 
     snew(state->pselstr, STRSTORE_ALLOCSTEP);
-    state->pselstr[0]   = 0;
-    state->pslen        = 0;
-    state->nalloc_psel  = STRSTORE_ALLOCSTEP;
+    state->pselstr[0]                 = 0;
+    state->pslen                      = 0;
+    state->nalloc_psel                = STRSTORE_ALLOCSTEP;
+    state->currentLocation.startIndex = 0;
+    state->currentLocation.endIndex   = 0;
 
     snew(state->mstack, 20);
-    state->mstack_alloc = 20;
-    state->msp          = -1;
-    state->neom         = 0;
-    state->nextparam    = NULL;
-    state->nextmethod   = NULL;
-    state->prev_pos_kw  = 0;
-    state->bBoolNo      = false;
-    state->bMatchOf     = false;
-    state->bMatchBool   = false;
-    state->bCmdStart    = true;
-    state->bBuffer      = false;
+    state->mstack_alloc     = 20;
+    state->msp              = -1;
+    state->neom             = 0;
+    state->nextparam        = NULL;
+    state->nextMethodSymbol = NULL;
+    state->prev_pos_kw      = 0;
+    state->bBoolNo          = false;
+    state->bMatchOf         = false;
+    state->bMatchBool       = false;
+    state->bCmdStart        = true;
+    state->bBuffer          = false;
 
     _gmx_sel_yyset_extra(state, *scannerp);
 }
@@ -431,14 +441,6 @@ _gmx_sel_free_lexer(yyscan_t scanner)
     _gmx_sel_yylex_destroy(scanner);
 }
 
-void
-_gmx_sel_set_lexer_error_reporter(yyscan_t                     scanner,
-                                  gmx::MessageStringCollector *errors)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    state->errors = errors;
-}
-
 void
 _gmx_sel_lexer_set_exception(yyscan_t                    scanner,
                              const boost::exception_ptr &ex)
@@ -459,11 +461,11 @@ _gmx_sel_lexer_rethrow_exception_if_occurred(yyscan_t scanner)
     }
 }
 
-bool
-_gmx_sel_is_lexer_interactive(yyscan_t scanner)
+gmx::TextWriter *
+_gmx_sel_lexer_get_status_writer(yyscan_t scanner)
 {
     gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    return state->bInteractive;
+    return state->statusWriter;
 }
 
 struct gmx_ana_selcollection_t *
@@ -473,14 +475,6 @@ _gmx_sel_lexer_selcollection(yyscan_t scanner)
     return state->sc;
 }
 
-gmx::MessageStringCollector *
-_gmx_sel_lexer_error_reporter(yyscan_t scanner)
-{
-    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
-    GMX_RELEASE_ASSERT(state->errors != NULL, "Error reporter not set");
-    return state->errors;
-}
-
 bool
 _gmx_sel_lexer_has_groups_set(yyscan_t scanner)
 {
@@ -509,6 +503,42 @@ _gmx_sel_lexer_pselstr(yyscan_t scanner)
     return state->pselstr;
 }
 
+void
+_gmx_sel_lexer_set_current_location(yyscan_t                      scanner,
+                                    const gmx::SelectionLocation &location)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    state->currentLocation = location;
+}
+
+const gmx::SelectionLocation &
+_gmx_sel_lexer_get_current_location(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return state->currentLocation;
+}
+
+std::string
+_gmx_sel_lexer_get_current_text(yyscan_t scanner)
+{
+    gmx_sel_lexer_t *state = _gmx_sel_yyget_extra(scanner);
+    return _gmx_sel_lexer_get_text(scanner, state->currentLocation);
+}
+
+std::string
+_gmx_sel_lexer_get_text(yyscan_t                      scanner,
+                        const gmx::SelectionLocation &location)
+{
+    gmx_sel_lexer_t *state      = _gmx_sel_yyget_extra(scanner);
+    const int        startIndex = location.startIndex;
+    const int        endIndex   = location.endIndex;
+    if (startIndex >= endIndex)
+    {
+        return std::string();
+    }
+    return std::string(&state->pselstr[startIndex], endIndex - startIndex);
+}
+
 void
 _gmx_sel_lexer_clear_pselstr(yyscan_t scanner)
 {