3df67883dbfcd9469f305ae734dba1f8c86393ff
[alexxy/gromacs.git] / src / gromacs / selection / symrec.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 classes in symrec.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_selection
41  */
42 #include "gmxpre.h"
43
44 #include <map>
45 #include <string>
46 #include <utility>
47
48 #include "gromacs/legacyheaders/macros.h"
49
50 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/gmxassert.h"
52 #include "gromacs/utility/stringutil.h"
53 #include "gromacs/utility/uniqueptr.h"
54
55 #include "poscalc.h"
56 #include "selelem.h"
57 #include "symrec.h"
58
59 namespace gmx
60 {
61
62 /********************************************************************
63  * SelectionParserSymbol
64  */
65
66 /*! \internal \brief
67  * Private implementation class for SelectionParserSymbol.
68  *
69  * \ingroup module_selection
70  */
71 class SelectionParserSymbol::Impl
72 {
73     public:
74         /*! \brief
75          * Initializes a symbol.
76          *
77          * \param[in] type  Type for the symbol.
78          * \param[in] name  Name for the symbol.
79          *
80          * The symbol table is responsible for initializing the \a meth_ and
81          * \a var_ members as appropriate.
82          */
83         Impl(SymbolType type, const char *name)
84             : name_(name), type_(type), meth_(NULL)
85         {
86         }
87
88         //! Name of the symbol.
89         std::string                     name_;
90         //! Type of the symbol.
91         SymbolType                      type_;
92         //! Pointer to the method structure (\ref MethodSymbol).
93         gmx_ana_selmethod_t            *meth_;
94         //! Pointer to the variable value (\ref VariableSymbol).
95         SelectionTreeElementPointer     var_;
96 };
97
98 SelectionParserSymbol::SelectionParserSymbol(Impl *impl)
99     : impl_(impl)
100 {
101 }
102
103 SelectionParserSymbol::~SelectionParserSymbol()
104 {
105 }
106
107 const std::string &
108 SelectionParserSymbol::name() const
109 {
110     return impl_->name_;
111 }
112
113 SelectionParserSymbol::SymbolType
114 SelectionParserSymbol::type() const
115 {
116     return impl_->type_;
117 }
118
119 gmx_ana_selmethod_t *
120 SelectionParserSymbol::methodValue() const
121 {
122     GMX_RELEASE_ASSERT(type() == MethodSymbol,
123                        "Attempting to get method handle for a non-method symbol");
124     return impl_->meth_;
125 }
126
127 const gmx::SelectionTreeElementPointer &
128 SelectionParserSymbol::variableValue() const
129 {
130     GMX_RELEASE_ASSERT(type() == VariableSymbol,
131                        "Attempting to get variable value for a non-variable symbol");
132     return impl_->var_;
133 }
134
135 /********************************************************************
136  * SelectionParserSymbolTable::Impl
137  */
138
139 /*! \internal
140  * \brief
141  * Private implementation class for SelectionParserSymbolTable.
142  *
143  * All methods in this class may throw std::bad_alloc if out of memory.
144  *
145  * \ingroup module_selection
146  */
147 class SelectionParserSymbolTable::Impl
148 {
149     public:
150         //! Smart pointer type for managing a SelectionParserSymbol.
151         typedef gmx::gmx_unique_ptr<SelectionParserSymbol>::type
152             SymbolPointer;
153         //! Container type for the list of symbols.
154         typedef std::map<std::string, SymbolPointer> SymbolMap;
155
156         /*! \brief
157          * Adds a symbol to the symbol list.
158          *
159          * \param[in] symbol  Symbol to add.
160          */
161         void addSymbol(SymbolPointer symbol);
162         //! Adds the reserved symbols to this symbol table.
163         void addReservedSymbols();
164         //! Adds the position symbols to this symbol table.
165         void addPositionSymbols();
166
167         //! Symbols in this symbol table.
168         SymbolMap               symbols_;
169 };
170
171 void
172 SelectionParserSymbolTable::Impl::addSymbol(SymbolPointer symbol)
173 {
174     symbols_.insert(std::make_pair(symbol->name(), move(symbol)));
175 }
176
177 void
178 SelectionParserSymbolTable::Impl::addReservedSymbols()
179 {
180     const char *const sym_reserved[] = {
181         "group",
182         "to",
183         "not",
184         "and",
185         "or",
186         "xor",
187         "yes",
188         "no",
189         "on",
190         "off"
191     };
192
193     for (size_t i = 0; i < asize(sym_reserved); ++i)
194     {
195         SymbolPointer sym(new SelectionParserSymbol(
196                                   new SelectionParserSymbol::Impl(
197                                           SelectionParserSymbol::ReservedSymbol, sym_reserved[i])));
198         addSymbol(move(sym));
199     }
200 }
201
202 void
203 SelectionParserSymbolTable::Impl::addPositionSymbols()
204 {
205     const char *const *postypes
206         = gmx::PositionCalculationCollection::typeEnumValues;
207     for (int i = 0; postypes[i] != NULL; ++i)
208     {
209         SymbolPointer sym(new SelectionParserSymbol(
210                                   new SelectionParserSymbol::Impl(
211                                           SelectionParserSymbol::PositionSymbol, postypes[i])));
212         addSymbol(move(sym));
213     }
214 }
215
216 /********************************************************************
217  * SelectionParserSymbolIterator
218  */
219
220 /*! \internal \brief
221  * Private implementation class for SelectionParserSymbolIterator.
222  *
223  * \ingroup module_selection
224  */
225 class SelectionParserSymbolIterator::Impl
226 {
227     public:
228         //! Shorthand for the underlying iterator type.
229         typedef SelectionParserSymbolTable::Impl::SymbolMap::const_iterator
230             IteratorType;
231
232         /*! \brief
233          * Constructs an end iterator.
234          *
235          * \param[in] end  Iterator to the end of the iterated container.
236          */
237         explicit Impl(IteratorType end)
238             : iter_(end), end_(end)
239         {
240         }
241         /*! \brief
242          * Constructs an iterator.
243          *
244          * \param[in] iter Iterator to the current symbol.
245          * \param[in] end  Iterator to the end of the iterated container.
246          */
247         Impl(IteratorType iter, IteratorType end)
248             : iter_(iter), end_(end)
249         {
250         }
251
252         //! Underlying iterator to the symbol container.
253         IteratorType            iter_;
254         //! End of the symbol container being iterated.
255         IteratorType            end_;
256 };
257
258 SelectionParserSymbolIterator::SelectionParserSymbolIterator(Impl *impl)
259     : impl_(impl)
260 {
261 }
262
263 SelectionParserSymbolIterator::SelectionParserSymbolIterator(
264         const SelectionParserSymbolIterator &other)
265     : impl_(new Impl(*other.impl_))
266 {
267 }
268
269 SelectionParserSymbolIterator::~SelectionParserSymbolIterator()
270 {
271 }
272
273 SelectionParserSymbolIterator &SelectionParserSymbolIterator::operator=(
274         const SelectionParserSymbolIterator &other)
275 {
276     impl_.reset(new Impl(*other.impl_));
277     return *this;
278 }
279
280 bool SelectionParserSymbolIterator::operator==(
281         const SelectionParserSymbolIterator &other) const
282 {
283     return impl_->iter_ == other.impl_->iter_;
284 }
285
286 const SelectionParserSymbol &SelectionParserSymbolIterator::operator*() const
287 {
288     return *impl_->iter_->second;
289 }
290
291 SelectionParserSymbolIterator &SelectionParserSymbolIterator::operator++()
292 {
293     SelectionParserSymbol::SymbolType type = impl_->iter_->second->type();
294     do
295     {
296         ++impl_->iter_;
297     }
298     while (impl_->iter_ != impl_->end_ && impl_->iter_->second->type() != type);
299     return *this;
300 }
301
302 /********************************************************************
303  * SelectionParserSymbolTable
304  */
305
306 SelectionParserSymbolTable::SelectionParserSymbolTable()
307     : impl_(new Impl)
308 {
309     impl_->addReservedSymbols();
310     impl_->addPositionSymbols();
311 }
312
313 SelectionParserSymbolTable::~SelectionParserSymbolTable()
314 {
315 }
316
317 const SelectionParserSymbol *
318 SelectionParserSymbolTable::findSymbol(const std::string &name,
319                                        bool               bExact) const
320 {
321     Impl::SymbolMap::const_iterator sym = impl_->symbols_.lower_bound(name);
322     if (sym == impl_->symbols_.end())
323     {
324         return NULL;
325     }
326     if (sym->second->name() == name)
327     {
328         return sym->second.get();
329     }
330     if (!bExact && startsWith(sym->second->name(), name))
331     {
332         Impl::SymbolMap::const_iterator next = sym;
333         ++next;
334         if (next != impl_->symbols_.end()
335             && startsWith(next->second->name(), name))
336         {
337             GMX_THROW(InvalidInputError("'" + name + "' is ambiguous"));
338         }
339         if (sym->second->type() == SelectionParserSymbol::MethodSymbol)
340         {
341             return sym->second.get();
342         }
343     }
344     return NULL;
345 }
346
347 SelectionParserSymbolIterator
348 SelectionParserSymbolTable::beginIterator(SelectionParserSymbol::SymbolType type) const
349 {
350     Impl::SymbolMap::const_iterator sym;
351     Impl::SymbolMap::const_iterator end = impl_->symbols_.end();
352     for (sym = impl_->symbols_.begin(); sym != end; ++sym)
353     {
354         if (sym->second->type() == type)
355         {
356             return SelectionParserSymbolIterator(
357                     new SelectionParserSymbolIterator::Impl(sym, end));
358         }
359     }
360     return endIterator();
361 }
362
363 SelectionParserSymbolIterator
364 SelectionParserSymbolTable::endIterator() const
365 {
366     return SelectionParserSymbolIterator(
367             new SelectionParserSymbolIterator::Impl(impl_->symbols_.end()));
368 }
369
370 void
371 SelectionParserSymbolTable::addVariable(const char                             *name,
372                                         const gmx::SelectionTreeElementPointer &sel)
373 {
374     // In the current parser implementation, a syntax error is produced before
375     // this point is reached, but the check is here for robustness.
376     Impl::SymbolMap::const_iterator other = impl_->symbols_.find(name);
377     if (other != impl_->symbols_.end())
378     {
379         if (other->second->type() == SelectionParserSymbol::VariableSymbol)
380         {
381             GMX_THROW(InvalidInputError(
382                               formatString("Reassigning variable '%s' is not supported",
383                                            name)));
384         }
385         else
386         {
387             GMX_THROW(InvalidInputError(
388                               formatString("Variable name '%s' conflicts with a reserved keyword",
389                                            name)));
390         }
391     }
392     Impl::SymbolPointer sym(new SelectionParserSymbol(
393                                     new SelectionParserSymbol::Impl(
394                                             SelectionParserSymbol::VariableSymbol, name)));
395     sym->impl_->var_ = sel;
396     impl_->addSymbol(move(sym));
397 }
398
399 void
400 SelectionParserSymbolTable::addMethod(const char          *name,
401                                       gmx_ana_selmethod_t *method)
402 {
403     if (impl_->symbols_.find(name) != impl_->symbols_.end())
404     {
405         GMX_THROW(APIError(
406                           formatString("Method name '%s' conflicts with another symbol",
407                                        name)));
408     }
409     Impl::SymbolPointer sym(new SelectionParserSymbol(
410                                     new SelectionParserSymbol::Impl(
411                                             SelectionParserSymbol::MethodSymbol, name)));
412     sym->impl_->meth_ = method;
413     impl_->addSymbol(move(sym));
414 }
415
416 } // namespace gmx