Schnek
expression.hpp
1 /*
2  * expression.hpp
3  *
4  * Created on: 26 Jan 2011
5  * Author: Holger Schmitz
6  * Email: holger@notjustphysics.com
7  *
8  * Copyright 2012 Holger Schmitz
9  *
10  * This file is part of Schnek.
11  *
12  * Schnek is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation, either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * Schnek is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with Schnek. If not, see <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #ifndef SCHNEK_EXPRESSION_HPP_
28 #define SCHNEK_EXPRESSION_HPP_
29 
30 #include "variables.hpp"
31 #include "../util/logger.hpp"
32 
33 #include <boost/shared_ptr.hpp>
34 #include <boost/lexical_cast.hpp>
35 
36 #include <boost/function.hpp>
37 
38 #include <boost/fusion/include/push_back.hpp>
39 #include <boost/fusion/include/invoke.hpp>
40 #include <boost/fusion/include/cons.hpp>
41 
42 #include <boost/mpl/begin.hpp>
43 #include <boost/mpl/end.hpp>
44 #include <boost/mpl/next.hpp>
45 #include <boost/mpl/deref.hpp>
46 
47 #include <boost/foreach.hpp>
48 
49 #include <string>
50 #include <iostream>
51 #include <set>
52 
53 #undef LOGLEVEL
54 #define LOGLEVEL 0
55 
56 namespace fusion = boost::fusion;
57 namespace mpl = boost::mpl;
58 namespace bft = boost::function_types;
59 
60 namespace schnek {
61 
63 {
64  public:
65  WrongNumberOfArgsException() : EvaluationException("Wrong number of arguments!") {}
66 };
67 
69 {
70  public:
71  FunctionNotFoundException(std::string functionName) : EvaluationException("Function '"+functionName+"' was not defined!") {}
72 };
73 
75 {
76  public:
77  TypeCastException() : EvaluationException("Could not convert types") {}
78 };
79 
80 typedef std::set<long> DependencyList;
81 
90 template<typename vtype>
92 {
93  public:
94  virtual ~Expression() {}
95 
97  virtual vtype eval() = 0;
98 
100  virtual bool isConstant() = 0;
101 
103  vtype operator()() { return eval(); }
104 
105  virtual DependencyList getDependencies() { return DependencyList(); }
106 
108  typedef boost::shared_ptr<Expression> pExpression;
109  typedef vtype ValueType;
110 };
111 
112 template<class ResultVariant>
113 struct ExpressionEvaluator : public boost::static_visitor<ResultVariant>
114 {
115  template<class ExpressionPointer>
116  ResultVariant operator()(ExpressionPointer e) { return e->eval(); }
117 };
118 
121 template<typename vtype>
122 class Value : public Expression<vtype>
123 {
124  private:
126  vtype val;
127  public:
128  typedef vtype ValueType;
130  Value(vtype val_) : val(val_) {}
132  vtype eval()
133  {
134  SCHNEK_TRACE_LOG(5, "Value<vtype>::eval(" << val << ")")
135  return val;
136  }
138  bool isConstant() { return true; }
140  vtype &getReference() { return val; }
141 };
142 
147 template<typename vtype>
148 class ReferencedValue : public Expression<vtype>
149 {
150  private:
152  pVariable var;
153  public:
155  ReferencedValue(const pVariable &var_) : var(var_) {}
157  vtype eval() {
158 // if (var->isConstant())
159 // {
160 // //std::cerr << "Attempting to assign variable\n";
161 // return boost::get<vtype>(var->getValue());
162 // }
163 // else
164 // return boost::get<vtype>(var->evaluateExpression());
165  // it is assumed that the referenced variable has been evaluated
166  SCHNEK_TRACE_LOG(5, "ReferencedValue<vtype>::eval(" << var->getValue() << ")")
167  return boost::get<vtype>(var->getValue());
168  }
170  bool isConstant() { return var->isConstant(); }
171 
173  DependencyList getDependencies()
174  {
175  DependencyList dep;
176  dep.insert(var->getId());
177  return dep;
178  }
179 };
180 
183 template<typename vtype>
184 class ExternalValue : public Expression<vtype>
185 {
186  private:
188  vtype *var;
189  public:
191  ExternalValue(vtype *var_) : var(var_) {}
192 
194  vtype eval() {
195 // std::cout << "Returning value " << *var << "\n";
196  SCHNEK_TRACE_LOG(5, "ExternalValue<vtype>::eval(" << *var << ")")
197  return *var;
198  }
199 
201  bool isConstant() { return false; }
202 };
203 
209 template<class oper, class vtype>
210 class UnaryOp : public Expression<vtype>
211 {
212  private:
213  typedef typename Expression<vtype>::pExpression pExpression;
215  pExpression expr;
216  public:
217  UnaryOp(pExpression expr_) : expr(expr_) {}
218 
220  vtype eval() { return oper::eval(expr->eval()); }
221 
223  bool isConstant() { return expr->isConstant(); }
224 
226  DependencyList getDependencies()
227  {
228  return expr->getDependencies();
229  }
230 };
231 
232 template<class vtype>
234  bool positive;
235  typename Expression<vtype>::pExpression expression;
236  ExpressionInfo(bool positive_, typename Expression<vtype>::pExpression expression_)
237  : positive(positive_), expression(expression_) {}
238 };
239 
245 template<class oper, class vtype>
246 class BinaryOp : public Expression<vtype>
247 {
248  private:
251 
253  typedef boost::shared_ptr<InvType> pInvType;
254  friend class BinaryOp<typename oper::Inverted, vtype>;
255 
257  std::list<ExpressionInfo<vtype> > expressions;
258  public:
259  BinaryOp(pExpression expr1_, pExpression expr2_)
260  {
261  typedef boost::shared_ptr<BinaryOp<oper, vtype> > pBinaryOp;
262 
263  pBinaryOp binaryExpr1 = boost::dynamic_pointer_cast<SelfType>(expr1_);
264  pInvType invExpr1 = boost::dynamic_pointer_cast<InvType>(expr1_);
265 
266  pBinaryOp binaryExpr2 = boost::dynamic_pointer_cast<SelfType>(expr2_);
267  pInvType invExpr2 = boost::dynamic_pointer_cast<InvType>(expr2_);
268 
269  if (binaryExpr1)
270  {
271  expressions.insert(expressions.end(), binaryExpr1->expressions.begin(), binaryExpr1->expressions.end());
272  }
273  else if (invExpr1)
274  {
275  expressions.insert(expressions.end(), invExpr1->expressions.begin(), invExpr1->expressions.end());
276  }
277  else
278  {
279  expressions.push_back(ExpressionInfo<vtype>(true, expr1_));
280  }
281 
282  if (binaryExpr2)
283  {
284  typename std::list<ExpressionInfo<vtype> >::iterator it = binaryExpr2->expressions.begin();
285  if (!oper::isPositive)
286  {
287  expressions.push_back(ExpressionInfo<vtype>(!it->positive, it->expression));
288  ++it;
289  }
290  expressions.insert(expressions.end(), it, binaryExpr2->expressions.end());
291  }
292  else if (invExpr2)
293  {
294  typename std::list<ExpressionInfo<vtype> >::iterator it = invExpr2->expressions.begin();
295  if (!oper::isPositive)
296  {
297  expressions.push_back(ExpressionInfo<vtype>(!it->positive, it->expression));
298  ++it;
299  }
300  expressions.insert(expressions.end(), it, invExpr2->expressions.end());
301  }
302  else
303  {
304  expressions.push_back(ExpressionInfo<vtype>(oper::isPositive, expr2_));
305  }
306  }
307 
309  vtype eval() {
310  typedef typename oper::Positive opPositive;
311  typedef typename oper::Negative opNegative;
312  typename std::list<ExpressionInfo<vtype> >::iterator it = expressions.begin();
313 // std::cout << std::endl << "EVAL: " << expressions.size() << std::endl;
314  vtype val = it->expression->eval();
315 
316  while (++it != expressions.end())
317  {
318 // std::cout << " : " << val << " " << it->positive << " " << it->expression->eval() << " ";
319  val = it->positive ? opPositive::eval(val, it->expression->eval()) : opNegative::eval(val, it->expression->eval());
320 // std::cout << val << std::endl;
321  }
322  return val;
323  }
324 
326  bool isConstant() {
327  BOOST_FOREACH(ExpressionInfo<vtype> exp, expressions)
328  {
329  if (!exp.expression->isConstant()) return false;
330  }
331  return true;
332  }
333 
335  DependencyList getDependencies()
336  {
337  DependencyList dependencies;
338 
339  BOOST_FOREACH(ExpressionInfo<vtype> exp, expressions)
340  {
341  DependencyList dep = exp.expression->getDependencies();
342  dependencies.insert(dep.begin(), dep.end());
343  }
344  return dependencies;
345  }
346 };
347 
348 template<class vtype>
349 struct FastCast
350 {
351  vtype operator()(int a);
352  vtype operator()(double a);
353  vtype operator()(std::string a);
354 };
355 
356 template<>
357 struct FastCast<int>
358 {
359  int operator()(int a) { return a; }
360  int operator()(double a) { return static_cast<int>(a); }
361  int operator()(std::string a) { return boost::lexical_cast<int>(a); }
362 };
363 
364 template<>
365 struct FastCast<double>
366 {
367  double operator()(int a) { return static_cast<double>(a); }
368  double operator()(double a) { return a; }
369  double operator()(std::string a) { return boost::lexical_cast<double>(a); }
370 };
371 
372 template<>
373 struct FastCast<std::string>
374 {
375  std::string operator()(int a) { return boost::lexical_cast<std::string>(a); }
376  std::string operator()(double a) { return boost::lexical_cast<std::string>(a); }
377  std::string operator()(std::string a) { return a; }
378 };
379 
380 
381 
382 template<class vtype>
384 {
385  public:
386  template<class atype>
387  vtype operator()(const atype& a) { return static_cast<vtype>(a); }
388 };
389 
390 template<class vtype>
392 {
393  public:
394  template<class atype>
395  vtype operator()(const atype& a) { return boost::lexical_cast<vtype>(a); }
396 };
397 
398 template<class vtype, class vtype_orig, template<class> class CastType = StaticCast>
399 class TypecastOp : public Expression<vtype>
400 {
401  public:
404  private:
406  pExpressionOrig expr;
407  public:
408  TypecastOp(pExpressionOrig expr_) : expr(expr_) {}
409 
411  vtype eval() {
412  try {
413  return CastType<vtype>()(expr->eval());
414  }
415  catch(boost::bad_lexical_cast &e)
416  {
417  throw TypeCastException();
418  }
419  }
420 
422  bool isConstant() { return expr->isConstant(); }
423 
425  DependencyList getDependencies()
426  {
427  return expr->getDependencies();
428  }
429 };
430 
431 struct DependenciesGetter : public boost::static_visitor<DependencyList>
432 {
433  template<class ExpressionPointer>
434  DependencyList operator()(ExpressionPointer e) { return e->getDependencies(); }
435 };
436 
437 #undef LOGLEVEL
438 #define LOGLEVEL 0
439 
440 } // namespace schnek
441 
442 #endif // SCHNEK_EXPRESSION_HPP_
ReferencedValue(const pVariable &var_)
Construct with a value.
Definition: expression.hpp:155
boost::shared_ptr< Expression > pExpression
A pointer to an Expression.
Definition: expression.hpp:108
Expression< vtype_orig >::pExpression pExpressionOrig
A pointer to an original Expression.
Definition: expression.hpp:403
DependencyList getDependencies()
returns the dependencies of the sub expression
Definition: expression.hpp:226
Definition: expression.hpp:349
Definition: expression.hpp:68
Definition: expression.hpp:148
bool isConstant()
The value of the external variable can change.
Definition: expression.hpp:201
Definition: expression.hpp:391
vtype eval()
Return the value.
Definition: expression.hpp:194
bool isConstant()
Constancy depends on the constancy of both expressions.
Definition: expression.hpp:326
DependencyList getDependencies()
returns the dependencies of the sub expression
Definition: expression.hpp:425
vtype eval()
Return the modified value.
Definition: expression.hpp:411
Definition: algo.hpp:30
Definition: expression.hpp:74
vtype & getReference()
Return a reference to the value.
Definition: expression.hpp:140
Definition: expression.hpp:399
Definition: expression.hpp:91
Definition: expression.hpp:62
bool isConstant()
Constancy depends on the constancy of the expression.
Definition: expression.hpp:223
vtype eval()
Return the modified value.
Definition: expression.hpp:157
bool isConstant()
Constancy depends on the constancy of the variable.
Definition: expression.hpp:170
vtype eval()
Return the calculated value.
Definition: expression.hpp:309
vtype eval()
Return the stored value.
Definition: expression.hpp:132
Definition: expression.hpp:122
Definition: expression.hpp:246
vtype eval()
Return the modified value.
Definition: expression.hpp:220
Definition: expression.hpp:113
vtype operator()()
The () operator allows expressions to be used as function objects.
Definition: expression.hpp:103
Definition: expression.hpp:233
#define SCHNEK_TRACE_LOG(i, x)
Definition: logger.hpp:54
DependencyList getDependencies()
returns a list with the variable&#39;s id
Definition: expression.hpp:173
Value(vtype val_)
Construct with a value.
Definition: expression.hpp:130
Definition: expression.hpp:184
Definition: expression.hpp:210
bool isConstant()
A literal is a constant.
Definition: expression.hpp:138
Definition: expression.hpp:383
bool isConstant()
Constancy depends on the constancy of the expression.
Definition: expression.hpp:422
Definition: types.hpp:63
DependencyList getDependencies()
returns the joint dependencies of both sub expression
Definition: expression.hpp:335
Definition: expression.hpp:431
ExternalValue(vtype *var_)
Construct with a pointer to the value.
Definition: expression.hpp:191