InFact
Interpreter and factory for easily creating C++ objects at run-time
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
environment.h
Go to the documentation of this file.
1 // Copyright 2014, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 // -----------------------------------------------------------------------------
30 //
31 //
38 
39 #ifndef INFACT_ENVIRONMENT_H_
40 #define INFACT_ENVIRONMENT_H_
41 
42 #define VAR_MAP_DEBUG 0
43 
44 #include <sstream>
45 #include <vector>
46 
47 #include "error.h"
48 #include "stream-init.h"
49 #include "stream-tokenizer.h"
50 
51 namespace infact {
52 
53 using std::cerr;
54 using std::endl;
55 using std::ostream;
56 using std::ostringstream;
57 using std::shared_ptr;
58 using std::unordered_map;
59 using std::unordered_set;
60 using std::vector;
61 
62 class Environment;
63 
66 class VarMapBase {
67  public:
76  VarMapBase(const string &name, Environment *env, bool is_primitive) :
77  name_(name), env_(env), is_primitive_(is_primitive) { }
78 
79  virtual ~VarMapBase() { }
80 
83  virtual bool IsPrimitive() const { return is_primitive_; }
84 
86  virtual const string &Name() const { return name_; }
87 
90  virtual bool Defined(const string &varname) const = 0;
91 
96  virtual void ReadAndSet(const string &varname, StreamTokenizer &st) = 0;
97 
101  virtual void Print(ostream &os) const = 0;
102 
104  virtual VarMapBase *Copy(Environment *env) const = 0;
105 
106  protected:
109  void SetMembers(const string &name, Environment *env, bool is_primitive) {
110  name_ = name;
111  env_ = env;
112  is_primitive_ = is_primitive;
113  }
114 
116  string name_;
122 };
123 
126 class Environment {
127  public:
128  virtual ~Environment() { }
129 
132  virtual bool Defined(const string &varname) const = 0;
133 
136  virtual void ReadAndSet(const string &varname, StreamTokenizer &st,
137  const string type = "") = 0;
138 
140  virtual const string &GetType(const string &varname) const = 0;
141 
143  virtual VarMapBase *GetVarMap(const string &varname) = 0;
144 
163  virtual VarMapBase *GetVarMapForType(const string &type) = 0;
164 
167  virtual void Print(ostream &os) const = 0;
168 
170  virtual Environment *Copy() const = 0;
171 
175  virtual void PrintFactories(ostream &os) const = 0;
176 
178  static Environment *CreateEmpty();
179 };
180 
185 template <typename T>
186 class ValueString {
187  public:
188  string ToString(const T &value) const {
189  ostringstream oss;
190  oss << value;
191  return oss.str();
192  }
193 };
194 
197 template<>
198 class ValueString<string> {
199  public:
200  string ToString(const string &value) const {
201  return "\"" + value + "\"";
202  }
203 };
204 
207 template<>
208 class ValueString<bool> {
209  public:
210  string ToString(const bool &value) const {
211  return value ? "true" : "false";
212  }
213 };
214 
218 template<typename T>
219 class ValueString<shared_ptr<T> > {
220  public:
221  string ToString(const shared_ptr<T> &value) const {
222  ostringstream oss;
223  oss << "<" << typeid(shared_ptr<T>).name() << ":" << value.get() << ">";
224  return oss.str();
225  }
226 };
227 
232 template <typename T>
233 class ValueString<vector<T> > {
234  public:
235  string ToString(const vector<T> &value) const {
236  ostringstream oss;
237  oss << "{";
238  typename vector<T>::const_iterator it = value.begin();
239  ValueString<T> value_string;
240  if (it != value.end()) {
241  oss << value_string.ToString(*it);
242  ++it;
243  }
244  for (; it != value.end(); ++it) {
245  oss << ", " << value_string.ToString(*it);
246  }
247  oss << "}";
248  return oss.str();
249  }
250 };
251 
265 template <typename T, typename Derived>
266 class VarMapImpl : public VarMapBase {
267  public:
268  VarMapImpl(const string &name, Environment *env, bool is_primitive = true) :
269  VarMapBase(name, env, is_primitive) { }
270 
271  virtual ~VarMapImpl() { }
272 
273  // Accessor methods
274 
280  bool Get(const string &varname, T *value) const {
281  typename unordered_map<string, T>::const_iterator it = vars_.find(varname);
282  if (it == vars_.end()) {
283  return false;
284  } else {
285  *value = it->second;
286  return true;
287  }
288  }
289 
291  virtual bool Defined(const string &varname) const {
292  return vars_.find(varname) != vars_.end();
293  }
294 
296  void Set(const string &varname, T value) {
297  vars_[varname] = value;
298  }
299 
301  virtual void Print(ostream &os) const {
302  ValueString<T> value_string;
303  for (typename unordered_map<string, T>::const_iterator it = vars_.begin();
304  it != vars_.end(); ++it) {
305  const T& value = it->second;
306  os << Name() << " "
307  << it->first
308  << " = "
309  << value_string.ToString(value)
310  << ";\n";
311  }
312  os.flush();
313  }
314 
316  virtual VarMapBase *Copy(Environment *env) const {
317  // Invoke Derived class' copy constructor.
318  const Derived *derived = dynamic_cast<const Derived *>(this);
319  if (derived == nullptr) {
320  Error("bad dynamic cast");
321  }
322  Derived *var_map_copy = new Derived(*derived);
323  var_map_copy->SetMembers(name_, env, is_primitive_);
324  return var_map_copy;
325  }
326  protected:
329  bool ReadAndSetFromExistingVariable(const string &varname,
330  StreamTokenizer &st) {
331  if (env()->Defined(st.Peek())) {
332  VarMapBase *var_map = env()->GetVarMap(st.Peek());
333  Derived *typed_var_map = dynamic_cast<Derived *>(var_map);
334  if (typed_var_map != nullptr) {
335  // Finally consume variable.
336  string rhs_variable = st.Next();
337  T value = T();
338  // Retrieve rhs variable's value.
339  bool success = typed_var_map->Get(rhs_variable, &value);
340  // Set varname to the same value.
341  if (VAR_MAP_DEBUG >= 1) {
342  cerr << "VarMap<" << Name() << ">::ReadAndSet: "
343  << "setting variable "
344  << varname << " to same value as rhs variable " << rhs_variable
345  << endl;
346  }
347  if (success) {
348  Set(varname, value);
349  } else {
350  // Error: we couldn't find the varname in this VarMap.
351  if (VAR_MAP_DEBUG >= 1) {
352  cerr << "VarMap<" << Name() << ">::ReadAndSet: no variable "
353  << rhs_variable << " found " << endl;
354  }
355  }
356  } else {
357  // Error: inferred or declared type of varname is different
358  // from the type of the rhs variable.
359  if (VAR_MAP_DEBUG >= 1) {
360  cerr << "VarMap<" << Name() << ">::ReadAndSet: variable "
361  << st.Peek() << " is of type " << var_map->Name()
362  << " but expecting " << typeid(T).name() << endl;
363  }
364  }
365  return true;
366  } else {
367  return false;
368  }
369  }
370 
374 
375  private:
376  unordered_map<string, T> vars_;
377 };
378 
383 template <typename T>
384 class VarMap : public VarMapImpl<T, VarMap<T> > {
385  public:
387 
395  VarMap(const string &name, Environment *env, bool is_primitive = true) :
396  Base(name, env, is_primitive) { }
397 
398  virtual ~VarMap() { }
399 
401  virtual void ReadAndSet(const string &varname, StreamTokenizer &st) {
402  if (VAR_MAP_DEBUG >= 1) {
403  cerr << "VarMap<" << Base::Name() << ">::ReadAndSet: "
404  << "about to set varname " << varname << " of type "
405  << typeid(T).name()
406  << "; prev_token=" << st.PeekPrev() << "; next_tok=" << st.Peek()
407  << endl;
408  }
409 
410  if (!Base::ReadAndSetFromExistingVariable(varname, st)) {
411  T value;
412  Initializer<T> initializer(&value);
413  initializer.Init(st, Base::env());
414  this->Set(varname, value);
415 
416  if (VAR_MAP_DEBUG >= 1) {
417  ValueString<T> value_string;
418  cerr << "VarMap<" << Base::Name() << ">::ReadAndSet: set varname "
419  << varname << " to value " << value_string.ToString(value)<< endl;
420  }
421  }
422  }
423 };
424 
439 template <typename T>
440 class VarMap<vector<T> > : public VarMapImpl<vector<T>, VarMap<vector<T> > > {
441  public:
443 
453  VarMap(const string &name, const string &element_typename, Environment *env,
454  bool is_primitive = true)
455  : Base(name, env, is_primitive), element_typename_(element_typename) { }
456 
457  virtual ~VarMap() { }
458 
459  virtual void ReadAndSet(const string &varname, StreamTokenizer &st) {
460  // First check if next token is an identifier and is a variable in
461  // the environment, set varname to its value.
462  if (!Base::ReadAndSetFromExistingVariable(varname, st)) {
463  // This entire block reads the array of values.
464 
465  // Either the next token is an open brace (if reading tokens from
466  // within a Factory-constructible object's member init list), or
467  // else we just read an open brace (if Interpreter is reading tokens).
468  if (st.Peek() == "{") {
469  // Consume open brace.
470  st.Next();
471  } else {
472  ostringstream err_ss;
473  err_ss << "VarMap<vector<T>>: "
474  << "error: expected '{' at stream position "
475  << st.PeekPrevTokenStart() << " but found \""
476  << st.PeekPrev() << "\"";
477  Error(err_ss.str());
478  }
479 
480  vector<T> value;
481  int element_idx = 0;
482  while (st.Peek() != "}") {
483  // Copy the environment, since we create fake names for each element.
484  shared_ptr<Environment> env_ptr(Base::env()->Copy());
485  ostringstream element_name_oss;
486  element_name_oss << "____" << varname << "_" << (element_idx++)
487  << "____";
488  string element_name = element_name_oss.str();
489 
490  env_ptr->ReadAndSet(element_name, st, element_typename_);
491  VarMapBase *element_var_map =
492  env_ptr->GetVarMapForType(element_typename_);
493  VarMap<T> *typed_element_var_map =
494  dynamic_cast<VarMap<T> *>(element_var_map);
495  T element;
496  if (typed_element_var_map->Get(element_name, &element)) {
497  value.push_back(element);
498  } else {
499  ostringstream err_ss;
500  err_ss << "VarMap<" << Base::Name() << ">::ReadAndSet: trouble "
501  << "initializing element " << (element_idx - 1)
502  << " of variable " << varname;
503  Error(err_ss.str());
504  }
505  // Each vector element initializer must be followed by a comma
506  // or the final closing parenthesis.
507  if (st.Peek() != "," && st.Peek() != "}") {
508  ostringstream err_ss;
509  err_ss << "Initializer<vector<T>>: "
510  << "error: expected ',' or '}' at stream position "
511  << st.PeekTokenStart() << " but found \"" << st.Peek() << "\"";
512  Error(err_ss.str());
513  }
514  // Read comma, if present.
515  if (st.Peek() == ",") {
516  st.Next();
517  }
518  }
519  // Consume close brace.
520  st.Next();
521 
522 
523  // Finally, set the newly-constructed value.
524  this->Set(varname, value);
525  }
526  }
527  private:
528  string element_typename_;
529 };
530 
531 } // namespace infact
532 
533 #endif
virtual void Print(ostream &os) const
Prints out a human-readable string to the specified output stream containing the variables, their type and, if primitive, their values.
Definition: environment.h:301
virtual VarMapBase * GetVarMapForType(const string &type)=0
Retrieves the VarMap instance for the specified type, or nullptr if there is no such VarMap...
Provides a generic dynamic object factory.
string name_
The type name of this VarMap.
Definition: environment.h:116
virtual void Init(StreamTokenizer &st, Environment *env=nullptr)
Definition: stream-init.h:88
virtual bool Defined(const string &varname) const =0
Returns whether the specified variable has a definition in this environment.
virtual void PrintFactories(ostream &os) const =0
Prints out a human-readable string with the names of all abstract base types and their concrete imple...
void Set(const string &varname, T value)
Sets the specified variable to the specified value.
Definition: environment.h:296
VarMapImpl< T, VarMap< T > > Base
Definition: environment.h:386
virtual ~VarMapImpl()
Definition: environment.h:271
VarMapBase(const string &name, Environment *env, bool is_primitive)
Constructs a base class for a concrete implementation providing a mapping from variables of a particu...
Definition: environment.h:76
virtual void ReadAndSet(const string &varname, StreamTokenizer &st)
Reads the next value (primitive or spec for constructing a Factory-constructible object) from the spe...
Definition: environment.h:401
string Next()
Returns the next token in the token stream.
virtual void ReadAndSet(const string &varname, StreamTokenizer &st)=0
Reads the next value (primitive or spec for constructing a Factory-constructible object) from the spe...
virtual void Print(ostream &os) const =0
Prints a human-readable string of all the variables in this environment, their types and...
size_t PeekPrevTokenStart() const
A template class that helps print out values with ostream& operator support and vectors of those valu...
Definition: environment.h:186
Provides an error handling function that optionally throws an exception.
string ToString(const T &value) const
Definition: environment.h:188
virtual ~VarMapBase()
Definition: environment.h:79
VarMap(const string &name, const string &element_typename, Environment *env, bool is_primitive=true)
Constructs a mapping from variables of a particular type to their values.
Definition: environment.h:453
void SetMembers(const string &name, Environment *env, bool is_primitive)
To allow proper implementation of Copy in VarMapBase implementation, since we don't get copying of ba...
Definition: environment.h:109
string ToString(const bool &value) const
Definition: environment.h:210
bool Get(const string &varname, T *value) const
Assigns the value of the specified variable to the object pointed to by the value parameter...
Definition: environment.h:280
A container to hold the mapping between named variables of a specific type and their values...
Definition: environment.h:384
VarMapImpl(const string &name, Environment *env, bool is_primitive=true)
Definition: environment.h:268
string ToString(const string &value) const
Definition: environment.h:200
string ToString(const vector< T > &value) const
Definition: environment.h:235
A partial implementation of the VarMapBase interface that is common to both VarMap<T> and the VarMap<...
Definition: environment.h:266
Environment * env_
The Environment that holds this VarMap instance.
Definition: environment.h:118
virtual Environment * Copy() const =0
Returns a copy of this environment.
virtual VarMapBase * Copy(Environment *env) const =0
Returns a newly constructed copy of this VarMap.
virtual bool IsPrimitive() const
Returns whether this instance contains primitive or primtive vector variables.
Definition: environment.h:83
virtual const string & Name() const
Returns the type name of the variables of this instance.
Definition: environment.h:86
A simple class for tokenizing a stream of tokens for the formally specified language used to construc...
static Environment * CreateEmpty()
A static factory method to create a new, empty Environment instance.
Definition: environment.cc:43
Provides the StreamTokenizer class.
virtual bool Defined(const string &varname) const
Returns whether the specified variable has a definition in this environment.
Definition: environment.h:291
A class to initialize a Factory-constructible object.
Definition: stream-init.h:84
An interface for an environment in which variables of various types are mapped to their values...
Definition: environment.h:126
bool is_primitive_
Whether this VarMap instance holds variables of primitive type or vector of primitives.
Definition: environment.h:121
VarMapImpl< vector< T >, VarMap< vector< T > > > Base
Definition: environment.h:442
size_t PeekTokenStart() const
Returns the next token’s start position, or the byte position of the underlying byte stream if there ...
virtual void Print(ostream &os) const =0
Prints out a human-readable string to the specified output stream containing the variables, their type and, if primitive, their values.
Environment * env()
A protected method to access the environment contained by this VarMapBase instance, for the two concrete VarMap implementations, below.
Definition: environment.h:373
virtual VarMapBase * Copy(Environment *env) const
Returns a newly constructed copy of this VarMap.
Definition: environment.h:316
bool ReadAndSetFromExistingVariable(const string &varname, StreamTokenizer &st)
Checks if the next token is an identifier and is a variable in the environment, and, if so, sets varname to the variable’s value.
Definition: environment.h:329
void Error(const std::string &message)
Reports an error encountered during parsing and/or construction of an object.
Definition: error.cc:47
string Peek() const
Returns the next token that would be returned by the Next method.
VarMap(const string &name, Environment *env, bool is_primitive=true)
Constructs a mapping from variables of a particular type to their values.
Definition: environment.h:395
virtual void ReadAndSet(const string &varname, StreamTokenizer &st)
Reads the next value (primitive or spec for constructing a Factory-constructible object) from the spe...
Definition: environment.h:459
virtual ~VarMap()
Definition: environment.h:398
string ToString(const shared_ptr< T > &value) const
Definition: environment.h:221
virtual VarMapBase * GetVarMap(const string &varname)=0
Retrieves the VarMap instance for the specified variable.
virtual const string & GetType(const string &varname) const =0
Retrieves the type name of the specified variable.
virtual ~Environment()
Definition: environment.h:128
virtual void ReadAndSet(const string &varname, StreamTokenizer &st, const string type="")=0
Sets the specified variable to the value obtained from the following tokens available from the specif...
A base class for a mapping from variables of a specific type to their values.
Definition: environment.h:66
#define VAR_MAP_DEBUG
Definition: environment.h:42
virtual bool Defined(const string &varname) const =0
Returns whether the specified variable has been defined in this environment.