OpenWalnut  1.4.0
WStructuredTextParser.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <algorithm>
26 #include <sstream>
27 #include <string>
28 #include <vector>
29 
30 #include "exceptions/WParseError.h"
31 #include "exceptions/WNotFound.h"
32 #include "WIOTools.h"
33 #include "WPredicateHelper.h"
34 
35 #include "WStructuredTextParser.h"
36 
38 {
39  const std::string StructuredValueTree::Separator = "/";
40 
42  m_file( file )
43  {
44  // initialize member
45  }
46 
48  {
49  // do nothing.
50  }
51 
52  StructuredValueTree::StructuredValueTree( const std::string& toParse ):
53  m_file( parseFromString( toParse ) )
54  {
55  // initialize
56  }
57 
58  StructuredValueTree::StructuredValueTree( const boost::filesystem::path& file ):
59  m_file( parseFromFile( file ) )
60  {
61  }
62 
64  {
65  // cleanup
66  }
67 
68  bool StructuredValueTree::exists( std::string key, bool valuesOnly ) const
69  {
70  return count( key, valuesOnly );
71  }
72 
73  size_t StructuredValueTree::count( std::string key, bool valuesOnly ) const
74  {
75  std::vector< ObjectType > rObj;
76  std::vector< KeyValueType > rKV;
77 
78  // traverse
79  traverse( m_file, key, rObj, rKV );
80 
81  if( valuesOnly )
82  {
83  return rKV.size();
84  }
85  else
86  {
87  return rKV.size() + rObj.size();
88  }
89  }
90 
92  {
93  std::vector< StructuredValueTree > r = getSubTrees( key );
94 
95  // return first match if any
96  if( r.size() )
97  {
98  return *r.begin();
99  }
100  else
101  {
102  return StructuredValueTree();
103  }
104  }
105 
106  std::vector< StructuredValueTree > StructuredValueTree::getSubTrees( std::string key ) const
107  {
108  std::vector< ObjectType > rObj;
109  std::vector< KeyValueType > rKV;
110  std::vector< StructuredValueTree > r;
111 
112  // traverse
113  traverse( m_file, key, rObj, rKV );
114 
115  // now we transform each found object int a MemberType (boost variant).
116  for( std::vector< ObjectType >::const_iterator objects = rObj.begin(); objects != rObj.end(); ++objects )
117  {
118  // create a new StructuredValueTree instance
119  r.push_back( StructuredValueTree( ( *objects ).m_nodes ) );
120  }
121 
122  return r;
123  }
124 
125  void StructuredValueTree::traverse( FileType current, std::string key,
126  std::vector< ObjectType >& resultObjects,
127  std::vector< KeyValueType >& resultValues ) const
128  {
129  // split up the key
130  std::vector< std::string > keySplit = string_utils::tokenize( key, Separator, false );
131  // empty key -> return empty result list
132  if( !keySplit.size() )
133  {
134  return;
135  }
136 
137  // traverse
138  for( FileType::const_iterator i = current.begin(); i != current.end(); ++i )
139  {
140  traverse( *i, keySplit.begin(), keySplit.end(), resultObjects, resultValues );
141  }
142  }
143 
144  void StructuredValueTree::traverse( MemberType current, std::vector< std::string >::const_iterator keyIter,
145  std::vector< std::string >::const_iterator keyEnd,
146  std::vector< ObjectType >& resultObjects,
147  std::vector< KeyValueType >& resultValues ) const
148  {
149  // get some properties of the current entry:
150  std::string elementName = boost::apply_visitor( NameQueryVisitor(), current );
151  bool elementIsKeyValuePair = boost::apply_visitor( IsLeafVisitor(), current );
152  bool elementIsComment = boost::apply_visitor( IsCommentVisitor(), current );
153 
154  // comments will be ignored.
155  // NOTE: we store comments in the original data structure to allow them to be written again to the file. This can be useful if OW loads a
156  // file (edited by the user) and re-writes this file. -> we are able to keep the comments
157  if( elementIsComment )
158  {
159  return;
160  }
161 
162  // does the current node match the current name?
163  if( elementName == *keyIter )
164  {
165  // only if the key path continues AND the current element is no leaf, traverse
166  if( !elementIsKeyValuePair && ( ( keyIter + 1 ) != keyEnd) )
167  {
168  ObjectType elementAsObj = boost::get< ObjectType >( current );
169  for( std::vector< MemberType >::const_iterator nodeIter = elementAsObj.m_nodes.begin();
170  nodeIter != elementAsObj.m_nodes.end();
171  ++nodeIter )
172  {
173  traverse( *nodeIter, keyIter + 1, keyEnd, resultObjects, resultValues );
174  }
175  }
176  else if( ( keyIter + 1 ) == keyEnd )
177  {
178  // we now have reached the end of the path.
179  if( elementIsKeyValuePair )
180  {
181  // the current element is a key-value pair -> add to result vector
182  resultValues.push_back( boost::get< KeyValueType >( current ) );
183  }
184  else
185  {
186  // the element is a object -> add to result vector
187  resultObjects.push_back( boost::get< ObjectType >( current ) );
188  }
189  }
190  // all the remaining cases are invalid and cause traversion to stop
191  }
192  // done
193  }
194 
195  FileType parseFromString( std::string input )
196  {
197  std::ostringstream error;
198  WStructuredTextParser::Grammar< std::string::const_iterator > parser( error );
199 
200  // parse
201  FileType ast;
202  std::string::const_iterator iter = input.begin();
203  std::string::const_iterator end = input.end();
204  bool r = phrase_parse( iter, end, parser, boost::spirit::ascii::space, ast );
205 
206  // error?
207  if( !( r && iter == end ) )
208  {
209  throw WParseError( "Parse error. Parser message: " + error.str() );
210  }
211 
212  // done. return
213  return ast;
214  }
215 
216  FileType parseFromFile( boost::filesystem::path path )
217  {
218  // NOTE: do not catch the io exception here.
219  std::string input= readFileIntoString( path );
220 
221  // instantiate parser
222  std::ostringstream error;
223  WStructuredTextParser::Grammar< std::string::const_iterator > parser( error );
224 
225  // parse
226  FileType ast;
227  std::string::const_iterator iter = input.begin();
228  std::string::const_iterator end = input.end();
229  bool r = phrase_parse( iter, end, parser, boost::spirit::ascii::space, ast );
230 
231  // error?
232  if( !( r && iter == end ) )
233  {
234  throw WParseError( "Parse error. Parser message: " + error.str() );
235  }
236 
237  // done. return
238  return ast;
239  }
240 }
241 
Indicates invalid input in a parser.
Definition: WParseError.h:35
std::vector< std::string > tokenize(const std::string &source, const std::string &delim=WHITESPACE, bool compress=true)
Splits the given string into a vector of strings (so called tokens).
size_t count(std::string key, bool valuesOnly=false) const
It is possible that there are multiple values matching a key.
StructuredValueTree getSubTree(std::string key) const
Gets a subtree.
FileType parseFromFile(boost::filesystem::path path)
Parse the given input and return the syntax tree.
bool exists(std::string key, bool valuesOnly=false) const
Checks whether the given value or object exists.
FileType m_file
The named values.
StructuredValueTree()
Creates an empty tree.
Visitor to identify whether the given variant of type WStructuredTextParser::MemberType is a object o...
This namespace contains the WStructuredTextParser data types and the parser.
void traverse(MemberType current, std::vector< std::string >::const_iterator keyIter, std::vector< std::string >::const_iterator keyEnd, std::vector< ObjectType > &resultObjects, std::vector< KeyValueType > &resultValues) const
Recursively fills a result vector using a given path iterator.
std::vector< MemberType > FileType
An object representing all objects and comments on file level.
FileType parseFromString(std::string input)
Parse the given input and return the syntax tree.
static const std::string Separator
This char is used as separator for identifying values in the tree.
Visitor to query the m_name member of WStructuredTextParser::ObjectType and WStructuredTextParser::Ke...
std::vector< StructuredValueTree > getSubTrees(std::string key) const
Gets all matching subtrees.
This simplifies working with a tree in a WStructuredTextParser::FileType instance.
virtual ~StructuredValueTree()
Cleanup.
Visitor to identify whether the given variant of type WStructuredTextParser::MemberType is a comment...