InFact
Interpreter and factory for easily creating C++ objects at run-time
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
environment-impl.cc
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 //
35 
36 #include "environment-impl.h"
37 #include "factory.h"
38 
39 namespace infact {
40 
42  debug_ = debug;
43 
44  // Set up VarMap instances for each of the primitive types and their vectors.
45  var_map_["bool"] = new VarMap<bool>("bool", this);
46  var_map_["int"] = new VarMap<int>("int", this);
47  var_map_["double"] = new VarMap<double>("double", this);
48  var_map_["string"] = new VarMap<string>("string", this);
49  var_map_["bool[]"] = new VarMap<vector<bool> >("bool[]", "bool", this);
50  var_map_["int[]"] = new VarMap<vector<int> >("int[]", "int", this);
51  var_map_["double[]"] =
52  new VarMap<vector<double> >("double[]", "double", this);
53  var_map_["string[]"] =
54  new VarMap<vector<string> >("string[]", "string", this);
55 
56  // Set up VarMap instances for each of the Factory-constructible types
57  // and their vectors.
59  factory_it != FactoryContainer::end(); ++factory_it) {
60  unordered_set<string> registered;
61  (*factory_it)->CollectRegistered(registered);
62  string base_name = (*factory_it)->BaseName();
63 
64  // Create type-specific VarMap from the Factory and add to var_map_.
65  VarMapBase *obj_var_map = (*factory_it)->CreateVarMap(this);
66  var_map_[obj_var_map->Name()] = obj_var_map;
67 
68  if (debug_ >= 3) {
69  cerr << "Environment: created VarMap for " << obj_var_map->Name()
70  << endl;
71  }
72 
73  // Create VarMap for vectors of shared_object of T and add to var_map_.
74  VarMapBase *obj_vector_var_map = (*factory_it)->CreateVectorVarMap(this);
75  var_map_[obj_vector_var_map->Name()] = obj_vector_var_map;
76 
77  if (debug_ >= 3) {
78  cerr << "Environment: created VarMap for " << obj_vector_var_map->Name()
79  << endl;
80  }
81 
82  for (unordered_set<string>::const_iterator it = registered.begin();
83  it != registered.end(); ++it) {
84  const string &concrete_type_name = *it;
85 
86  unordered_map<string, string>::const_iterator concrete_to_factory_it =
87  concrete_to_factory_type_.find(concrete_type_name);
88  if (concrete_to_factory_it != concrete_to_factory_type_.end()) {
89  // Warn user that there are two entries for the same concrete type
90  // (presumably due to different abstract factory types).
91  cerr << "Environment: WARNING: trying to override existing "
92  << "concrete-to-factory type mapping ["
93  << concrete_type_name << " --> " << concrete_to_factory_it->second
94  << "] with [" << concrete_type_name << " --> " << base_name
95  << endl;
96  }
97  concrete_to_factory_type_[concrete_type_name] = base_name;
98 
99  if (debug_ >= 3) {
100  cerr << "Environment: associating concrete typename "
101  << concrete_type_name
102  << " with factory for " << base_name << endl;
103  }
104  }
105  }
106 }
107 
108 void
109 EnvironmentImpl::ReadAndSet(const string &varname, StreamTokenizer &st,
110  const string type) {
111  bool is_vector =
113  st.Peek() == "{";
114 
115  if (is_vector) {
116  // Consume open brace.
117  st.Next();
118  } else if (st.PeekTokenType() == StreamTokenizer::RESERVED_CHAR ||
120  st.Peek() != "true" && st.Peek() != "false" &&
121  st.Peek() != "nullptr" && st.Peek() != "NULL")) {
122  ostringstream err_ss;
123  err_ss << "Environment: error: expected literal or Factory-constructible "
124  << "type but found token \"" << st.Peek() << "\" of type "
126  Error(err_ss.str());
127  }
128 
129  string next_tok = st.Peek();
130  bool is_object_type = false;
131 
132  string inferred_type = InferType(varname, st, is_vector, &is_object_type);
133 
134  if (is_vector) {
135  st.Putback();
136  next_tok = st.Peek();
137  }
138 
139  if (debug_ >= 2) {
140  cerr << "Environment::ReadAndSet: next_tok=\"" << next_tok
141  << "\"; explicit type=\"" << type << "\"; "
142  << "inferred_type=\"" << inferred_type << "\"" << endl;
143  }
144 
145  if (type == "" && inferred_type == "") {
146  ostringstream err_ss;
147  err_ss << "Environment: error: no explicit type specifier and could not "
148  << "infer type for variable " << varname;
149  Error(err_ss.str());
150  }
151  if (type != "" && inferred_type != "" && type != inferred_type) {
152  ostringstream err_ss;
153  err_ss << "Environment: error: explicit type " << type
154  << " and inferred type " << inferred_type
155  << " disagree for variable " << varname;
156  Error(err_ss.str());
157  }
158 
159  // If no explicit type specifier, then the inferred_type is the type.
160  string varmap_type = type == "" ? inferred_type : type;
161 
162  // Check that varmap_type is a key in var_map_.
163  var_map_[varmap_type]->ReadAndSet(varname, st);
164  types_[varname] = varmap_type;
165 }
166 
167 string
168 EnvironmentImpl::InferType(const string &varname,
169  const StreamTokenizer &st, bool is_vector,
170  bool *is_object_type) {
171  *is_object_type = false;
172  string next_tok = st.Peek();
173  switch (st.PeekTokenType()) {
175  if (next_tok == "true" || next_tok == "false") {
176  return is_vector ? "bool[]" : "bool";
177  } else {
178  return "";
179  }
180  break;
182  return is_vector ? "string[]" : "string";
183  break;
185  {
186  // If a token is a NUMBER, it is a double iff it contains a
187  // decimal point.
188  size_t dot_pos = next_tok.find('.');
189  if (dot_pos != string::npos) {
190  return is_vector ? "double[]" : "double";
191  } else {
192  return is_vector ? "int[]" : "int";
193  }
194  }
195  break;
197  {
198  string type = "";
199 
200  // Find out if next_tok is a concrete typename or a variable.
201  unordered_map<string, string>::const_iterator factory_type_it =
202  concrete_to_factory_type_.find(next_tok);
203  unordered_map<string, string>::const_iterator var_type_it =
204  types_.find(next_tok);
205  if (factory_type_it != concrete_to_factory_type_.end()) {
206  // Set type to be abstract factory type.
207  if (debug_ >= 2) {
208  cerr << "Environment::InferType: concrete type is " << next_tok
209  << "; mapping to abstract Factory type "
210  << factory_type_it->second << endl;
211  }
212  type = factory_type_it->second;
213  *is_object_type = true;
214  type = is_vector ? type + "[]" : type;
215 
216  if (debug_ >= 2) {
217  cerr << "Environment::InferType: type "
218  << (is_vector ? "is" : "isn't")
219  << " a vector, so final inferred type is " << type << endl;
220  }
221  } else if (var_type_it != types_.end()) {
222  // Could be a variable, in which case we need not only to return
223  // the variable's type, but also set is_object_type and is_vector
224  // based on the variable's type string.
225  string append = is_vector ? "[]" : "";
226  type = var_type_it->second + append;
227  if (debug_ >= 2) {
228  cerr << "Environment::InferType: found variable "
229  << var_type_it->first << " of type " << var_type_it->second
230  << "; type is " << type << endl;
231  }
232  } else {
233  ostringstream err_ss;
234  err_ss << "Environment: error: token " << next_tok
235  << " is neither a variable nor a concrete object typename";
236  Error(err_ss.str());
237  }
238  return type;
239  }
240  break;
241  default:
242  return "";
243  }
244  return "";
245 }
246 
247 void
250 }
251 
252 } // namespace infact
vector< FactoryBase * >::iterator iterator
Definition: factory.h:455
static void Print(ostream &os)
Prints the base typenames for all factories along with a list of all concrete subtypes those factorie...
Definition: factory.h:500
string Next()
Returns the next token in the token stream.
virtual void ReadAndSet(const string &varname, StreamTokenizer &st, const string type)
Sets the specified variable to the value obtained from the following tokens available from the specif...
EnvironmentImpl(int debug=0)
Constructs a new, empty environment.
A container to hold the mapping between named variables of a specific type and their values...
Definition: environment.h:384
TokenType PeekTokenType() const
Returns the type of the next token, or EOF_TYPE if there is no next token.
void Putback()
A synonym for Rewind(1).
virtual const string & Name() const
Returns the type name of the variables of this instance.
Definition: environment.h:86
Provides a generic dynamic object factory.
A simple class for tokenizing a stream of tokens for the formally specified language used to construc...
static iterator begin()
Definition: factory.h:482
static const char * TypeName(TokenType token_type)
Returns a string type name for the specified TokenType constant.
virtual void PrintFactories(ostream &os) const
Prints out a human-readable string with the names of all abstract base types and their concrete imple...
static iterator end()
Definition: factory.h:489
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.
Provides an environment for variables and their values, either primitive or Factory-constructible obj...
A base class for a mapping from variables of a specific type to their values.
Definition: environment.h:66