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 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
35 #pragma GCC diagnostic push
36 #pragma GCC diagnostic ignored "-Wdeprecated-copy"
37 
38 #include <boost/lexical_cast.hpp>
39 #include <boost/function.hpp>
40 
41 #include <boost/fusion/include/push_back.hpp>
42 #include <boost/fusion/include/invoke.hpp>
43 #include <boost/fusion/include/cons.hpp>
44 
45 #include <boost/mpl/begin.hpp>
46 #include <boost/mpl/end.hpp>
47 #include <boost/mpl/next.hpp>
48 #include <boost/mpl/deref.hpp>
49 
50 #pragma GCC diagnostic pop
51 #pragma GCC diagnostic pop
52 
53 #include <memory>
54 #include <string>
55 #include <iostream>
56 #include <set>
57 
58 #undef LOGLEVEL
59 #define LOGLEVEL 0
60 
61 namespace fusion = boost::fusion;
62 namespace mpl = boost::mpl;
63 namespace bft = boost::function_types;
64 
65 namespace schnek {
66 
68 {
69  public:
70  WrongNumberOfArgsException() : EvaluationException("Wrong number of arguments!") {}
71 };
72 
74 {
75  public:
76  FunctionNotFoundException(std::string functionName) : EvaluationException("Function '"+functionName+"' was not defined!") {}
77 };
78 
80 {
81  public:
82  TypeCastException() : EvaluationException("Could not convert types") {}
83 };
84 
85 typedef std::set<long> DependencyList;
86 
95 template<typename vtype>
97 {
98  public:
99  virtual ~Expression() {}
100 
102  virtual vtype eval() = 0;
103 
105  virtual bool isConstant() = 0;
106 
108  vtype operator()() { return eval(); }
109 
110  virtual DependencyList getDependencies() { return DependencyList(); }
111 
113  typedef std::shared_ptr<Expression> pExpression;
114  typedef vtype ValueType;
115 };
116 
117 template<class ResultVariant>
118 struct ExpressionEvaluator : public boost::static_visitor<ResultVariant>
119 {
120  template<class ExpressionPointer>
121  ResultVariant operator()(ExpressionPointer e) { return e->eval(); }
122 };
123 
126 template<typename vtype>
127 class Value : public Expression<vtype>
128 {
129  private:
131  vtype val;
132  public:
133  typedef vtype ValueType;
135  Value(vtype val_) : val(val_) {}
137  vtype eval()
138  {
139  SCHNEK_TRACE_LOG(5, "Value<vtype>::eval(" << val << ")")
140  return val;
141  }
143  bool isConstant() { return true; }
145  vtype &getReference() { return val; }
146 };
147 
152 template<typename vtype>
153 class ReferencedValue : public Expression<vtype>
154 {
155  private:
157  pVariable var;
158  public:
160  ReferencedValue(const pVariable &var_) : var(var_) {}
162  vtype eval() {
163 // if (var->isConstant())
164 // {
165 // //std::cerr << "Attempting to assign variable\n";
166 // return boost::get<vtype>(var->getValue());
167 // }
168 // else
169 // return boost::get<vtype>(var->evaluateExpression());
170  // it is assumed that the referenced variable has been evaluated
171  SCHNEK_TRACE_LOG(5, "ReferencedValue<vtype>::eval(" << var->getValue() << ")")
172  return boost::get<vtype>(var->getValue());
173  }
175  bool isConstant() { return var->isConstant(); }
176 
178  DependencyList getDependencies()
179  {
180  DependencyList dep;
181  dep.insert(var->getId());
182  return dep;
183  }
184 };
185 
188 template<typename vtype>
189 class ExternalValue : public Expression<vtype>
190 {
191  private:
193  vtype *var;
194  public:
196  ExternalValue(vtype *var_) : var(var_) {}
197 
199  vtype eval() {
200 // std::cout << "Returning value " << *var << "\n";
201  SCHNEK_TRACE_LOG(5, "ExternalValue<vtype>::eval(" << *var << ")")
202  return *var;
203  }
204 
206  bool isConstant() { return false; }
207 };
208 
214 template<class oper, class vtype>
215 class UnaryOp : public Expression<vtype>
216 {
217  private:
218  typedef typename Expression<vtype>::pExpression pExpression;
220  pExpression expr;
221  public:
222  UnaryOp(pExpression expr_) : expr(expr_) {}
223 
225  vtype eval() { return oper::eval(expr->eval()); }
226 
228  bool isConstant() { return expr->isConstant(); }
229 
231  DependencyList getDependencies()
232  {
233  return expr->getDependencies();
234  }
235 };
236 
237 template<class vtype>
239  bool positive;
240  typename Expression<vtype>::pExpression expression;
241  ExpressionInfo(bool positive_, typename Expression<vtype>::pExpression expression_)
242  : positive(positive_), expression(expression_) {}
243 };
244 
250 template<class oper, class vtype>
251 class BinaryOp : public Expression<vtype>
252 {
253  private:
256 
258  typedef std::shared_ptr<InvType> pInvType;
259  friend class BinaryOp<typename oper::Inverted, vtype>;
260 
262  std::list<ExpressionInfo<vtype> > expressions;
263  public:
264  BinaryOp(pExpression expr1_, pExpression expr2_)
265  {
266  typedef std::shared_ptr<BinaryOp<oper, vtype> > pBinaryOp;
267 
268  pBinaryOp binaryExpr1 = std::dynamic_pointer_cast<SelfType>(expr1_);
269  pInvType invExpr1 = std::dynamic_pointer_cast<InvType>(expr1_);
270 
271  pBinaryOp binaryExpr2 = std::dynamic_pointer_cast<SelfType>(expr2_);
272  pInvType invExpr2 = std::dynamic_pointer_cast<InvType>(expr2_);
273 
274  if (binaryExpr1)
275  {
276  expressions.insert(expressions.end(), binaryExpr1->expressions.begin(), binaryExpr1->expressions.end());
277  }
278  else if (invExpr1)
279  {
280  expressions.insert(expressions.end(), invExpr1->expressions.begin(), invExpr1->expressions.end());
281  }
282  else
283  {
284  expressions.push_back(ExpressionInfo<vtype>(true, expr1_));
285  }
286 
287  if (binaryExpr2)
288  {
289  typename std::list<ExpressionInfo<vtype> >::iterator it = binaryExpr2->expressions.begin();
290  if (!oper::isPositive)
291  {
292  expressions.push_back(ExpressionInfo<vtype>(!it->positive, it->expression));
293  ++it;
294  }
295  expressions.insert(expressions.end(), it, binaryExpr2->expressions.end());
296  }
297  else if (invExpr2)
298  {
299  typename std::list<ExpressionInfo<vtype> >::iterator it = invExpr2->expressions.begin();
300  if (!oper::isPositive)
301  {
302  expressions.push_back(ExpressionInfo<vtype>(!it->positive, it->expression));
303  ++it;
304  }
305  expressions.insert(expressions.end(), it, invExpr2->expressions.end());
306  }
307  else
308  {
309  expressions.push_back(ExpressionInfo<vtype>(oper::isPositive, expr2_));
310  }
311  }
312 
314  vtype eval() {
315  typedef typename oper::Positive opPositive;
316  typedef typename oper::Negative opNegative;
317  typename std::list<ExpressionInfo<vtype> >::iterator it = expressions.begin();
318 // std::cout << std::endl << "EVAL: " << expressions.size() << std::endl;
319  vtype val = it->expression->eval();
320 
321  while (++it != expressions.end())
322  {
323 // std::cout << " : " << val << " " << it->positive << " " << it->expression->eval() << " ";
324  val = it->positive ? opPositive::eval(val, it->expression->eval()) : opNegative::eval(val, it->expression->eval());
325 // std::cout << val << std::endl;
326  }
327  return val;
328  }
329 
331  bool isConstant() {
332  for(ExpressionInfo<vtype> exp: expressions)
333  {
334  if (!exp.expression->isConstant()) return false;
335  }
336  return true;
337  }
338 
340  DependencyList getDependencies()
341  {
342  DependencyList dependencies;
343 
344  for(ExpressionInfo<vtype> exp: expressions)
345  {
346  DependencyList dep = exp.expression->getDependencies();
347  dependencies.insert(dep.begin(), dep.end());
348  }
349  return dependencies;
350  }
351 };
352 
353 template<class vtype>
354 struct FastCast
355 {
356  vtype operator()(int a);
357  vtype operator()(double a);
358  vtype operator()(std::string a);
359 };
360 
361 template<>
362 struct FastCast<int>
363 {
364  int operator()(int a) { return a; }
365  int operator()(double a) { return static_cast<int>(a); }
366  int operator()(std::string a) { return boost::lexical_cast<int>(a); }
367 };
368 
369 template<>
370 struct FastCast<double>
371 {
372  double operator()(int a) { return static_cast<double>(a); }
373  double operator()(double a) { return a; }
374  double operator()(std::string a) { return boost::lexical_cast<double>(a); }
375 };
376 
377 template<>
378 struct FastCast<std::string>
379 {
380  std::string operator()(int a) { return boost::lexical_cast<std::string>(a); }
381  std::string operator()(double a) { return boost::lexical_cast<std::string>(a); }
382  std::string operator()(std::string a) { return a; }
383 };
384 
385 
386 
387 template<class vtype>
389 {
390  public:
391  template<class atype>
392  vtype operator()(const atype& a) { return static_cast<vtype>(a); }
393 };
394 
395 template<class vtype>
397 {
398  public:
399  template<class atype>
400  vtype operator()(const atype& a) { return boost::lexical_cast<vtype>(a); }
401 };
402 
403 template<class vtype, class vtype_orig, template<class> class CastType = StaticCast>
404 class TypecastOp : public Expression<vtype>
405 {
406  public:
409  private:
411  pExpressionOrig expr;
412  public:
413  TypecastOp(pExpressionOrig expr_) : expr(expr_) {}
414 
416  vtype eval() {
417  try {
418  return CastType<vtype>()(expr->eval());
419  }
420  catch(boost::bad_lexical_cast &e)
421  {
422  throw TypeCastException();
423  }
424  }
425 
427  bool isConstant() { return expr->isConstant(); }
428 
430  DependencyList getDependencies()
431  {
432  return expr->getDependencies();
433  }
434 };
435 
436 struct DependenciesGetter : public boost::static_visitor<DependencyList>
437 {
438  template<class ExpressionPointer>
439  DependencyList operator()(ExpressionPointer e) { return e->getDependencies(); }
440 };
441 
442 #undef LOGLEVEL
443 #define LOGLEVEL 0
444 
445 } // namespace schnek
446 
447 #endif // SCHNEK_EXPRESSION_HPP_
std::shared_ptr< Expression > pExpression
A pointer to an Expression.
Definition: expression.hpp:113
ReferencedValue(const pVariable &var_)
Construct with a value.
Definition: expression.hpp:160
Expression< vtype_orig >::pExpression pExpressionOrig
A pointer to an original Expression.
Definition: expression.hpp:408
DependencyList getDependencies()
returns the dependencies of the sub expression
Definition: expression.hpp:231
Definition: expression.hpp:354
Definition: expression.hpp:73
Definition: expression.hpp:153
bool isConstant()
The value of the external variable can change.
Definition: expression.hpp:206
Definition: expression.hpp:396
vtype eval()
Return the value.
Definition: expression.hpp:199
bool isConstant()
Constancy depends on the constancy of both expressions.
Definition: expression.hpp:331
DependencyList getDependencies()
returns the dependencies of the sub expression
Definition: expression.hpp:430
vtype eval()
Return the modified value.
Definition: expression.hpp:416
Definition: algo.hpp:30
Definition: expression.hpp:79
vtype & getReference()
Return a reference to the value.
Definition: expression.hpp:145
Definition: expression.hpp:404
Definition: expression.hpp:96
Definition: expression.hpp:67
bool isConstant()
Constancy depends on the constancy of the expression.
Definition: expression.hpp:228
vtype eval()
Return the modified value.
Definition: expression.hpp:162
bool isConstant()
Constancy depends on the constancy of the variable.
Definition: expression.hpp:175
vtype eval()
Return the calculated value.
Definition: expression.hpp:314
vtype eval()
Return the stored value.
Definition: expression.hpp:137
Definition: expression.hpp:127
Definition: expression.hpp:251
vtype eval()
Return the modified value.
Definition: expression.hpp:225
Definition: expression.hpp:118
vtype operator()()
The () operator allows expressions to be used as function objects.
Definition: expression.hpp:108
Definition: expression.hpp:238
#define SCHNEK_TRACE_LOG(i, x)
Definition: logger.hpp:54
DependencyList getDependencies()
returns a list with the variable&#39;s id
Definition: expression.hpp:178
Value(vtype val_)
Construct with a value.
Definition: expression.hpp:135
Definition: expression.hpp:189
Definition: expression.hpp:215
bool isConstant()
A literal is a constant.
Definition: expression.hpp:143
Definition: expression.hpp:388
bool isConstant()
Constancy depends on the constancy of the expression.
Definition: expression.hpp:427
Definition: types.hpp:69
DependencyList getDependencies()
returns the joint dependencies of both sub expression
Definition: expression.hpp:340
Definition: expression.hpp:436
ExternalValue(vtype *var_)
Construct with a pointer to the value.
Definition: expression.hpp:196