KSeExpr  4.0.4.0
Expression.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2019 Disney Enterprises, Inc.
2 // SPDX-License-Identifier: LicenseRef-Apache-2.0
3 // SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 
6 #include <algorithm>
7 #include <cmath>
8 #include <cstdio>
9 #include <iostream>
10 #include <sstream>
11 #include <stack>
12 #include <typeinfo>
13 
14 #include "Evaluator.h"
15 #include "ExprConfig.h"
16 #include "ExprEnv.h"
17 #include "ExprFunc.h"
18 #include "ExprNode.h"
19 #include "ExprParser.h"
20 #include "ExprType.h"
21 #include "ExprWalker.h"
22 #include "Expression.h"
23 #include "TypePrinter.h"
24 
25 namespace KSeExpr {
26 
27 // Get debugging flag from environment
28 bool Expression::debugging = getenv("SE_EXPR_DEBUG") != nullptr;
29 // Choose the defeault strategy based on what we've compiled with (SEEXPR_ENABLE_LLVM)
30 // And the environment variables SE_EXPR_DEBUG
33  std::cerr << "KSeExpr Debug Mode Enabled " <<
34 #if defined(_MSC_VER)
35  _MSC_FULL_VER
36 #else
37  __VERSION__
38 #endif
39  << std::endl;
40  }
41 #if defined(SEEXPR_ENABLE_LLVM)
42  if (char* env = getenv("SE_EXPR_EVAL")) {
43  if (Expression::debugging) std::cerr << "Overriding SeExpr Evaluation Default to be " << env << std::endl;
44  return !strcmp(env, "LLVM") ? Expression::UseLLVM : !strcmp(env, "INTERPRETER") ? Expression::UseInterpreter
46  } else
47  return Expression::UseLLVM;
48 #else
50 #endif
51 }
53 
55  : _wantVec(true), _expression(""), _evaluationStrategy(evaluationStrategy), _context(&Context::global()),
56  _desiredReturnType(ExprType().FP(3).Varying()), _parseTree(nullptr), _isValid(false), _parsed(false), _prepped(false),
57  _interpreter(nullptr), _llvmEvaluator(new LLVMEvaluator()) {
59 }
60 
61 Expression::Expression(const std::string& e,
62  const ExprType& type,
63  EvaluationStrategy evaluationStrategy,
64  const Context& context)
65  : _wantVec(true), _expression(e), _evaluationStrategy(evaluationStrategy), _context(&context),
66  _desiredReturnType(type), _parseTree(nullptr), _isValid(false), _parsed(false), _prepped(false), _interpreter(nullptr),
67  _llvmEvaluator(new LLVMEvaluator()) {
69 }
70 
72  reset();
73  delete _llvmEvaluator;
74 }
75 
77  if (_interpreter) {
79  std::cerr << "return slot " << _returnSlot << std::endl;
80  }
81 }
82 
84 
86  if (_parseTree) {
87  // print the parse tree
88  std::cerr << "Parse tree desired type " << _desiredReturnType.toString() << " actual "
89  << _parseTree->type().toString() << std::endl;
90  TypePrintExaminer _examiner;
91  KSeExpr::ConstWalker _walker(&_examiner);
92  _walker.walk(_parseTree);
93  }
94 }
95 
97  delete _llvmEvaluator;
99  delete _parseTree;
100  _parseTree = nullptr;
102  delete _interpreter;
103  _interpreter = nullptr;
104  }
105  _isValid = 0;
106  _parsed = 0;
107  _prepped = 0;
109  _parseErrorIds.clear();
110  _vars.clear();
111  _funcs.clear();
112  //_localVars.clear();
113  _errors.clear();
114  _envBuilder.reset();
116  _comments.clear();
117 }
118 
119 void Expression::setContext(const Context& context) {
120  reset();
121  _context = &context;
122 }
123 
125  reset();
126  _desiredReturnType = type;
127 }
128 
130  reset();
131  _varBlockCreator = creator;
132 }
133 
134 void Expression::setExpr(const std::string& e) {
135  if (_expression != "") reset();
136  _expression = e;
137 }
138 
139 bool Expression::syntaxOK() const {
140  parseIfNeeded();
141  return _isValid;
142 }
143 
145  parseIfNeeded();
146  return returnType().isLifetimeConstant();
147 }
148 
149 bool Expression::usesVar(const std::string& name) const {
150  parseIfNeeded();
151  return _vars.find(name) != _vars.end();
152 }
153 
154 bool Expression::usesFunc(const std::string& name) const {
155  parseIfNeeded();
156  return _funcs.find(name) != _funcs.end();
157 }
158 
159 void Expression::parse() const {
160  if (_parsed) return;
161  _parsed = true;
162  int tempStartPos, tempEndPos;
163  ExprParse(_parseTree, _parseErrorCode, _parseErrorIds, tempStartPos, tempEndPos, _comments, this, _expression.c_str(), _wantVec);
164  if (!_parseTree) {
165  addError(_parseErrorCode, _parseErrorIds, tempStartPos, tempEndPos);
166  }
167 }
168 
169 void Expression::prep() const {
170  if (_prepped) return;
171 #ifdef SEEXPR_PERFORMANCE
172  PerformanceTimer timer("[ PREP ] v2 prep time: ");
173 #endif
174  _prepped = true;
175  parseIfNeeded();
176 
177  bool error = false;
178  std::string _parseError;
179 
180  if (!_parseTree) {
181  // parse error
182  error = true;
184  // prep error
185  error = true;
187  // incompatible type error
188  error = true;
190  } else {
191  _isValid = true;
192 
194  if (debugging) {
196  std::cerr << "Eval strategy is interpreter" << std::endl;
197  }
198  assert(!_interpreter);
201  if (_desiredReturnType.isFP()) {
202  int dimWanted = _desiredReturnType.dim();
203  int dimHave = _parseTree->type().dim();
204  if (dimWanted > dimHave) {
205  _interpreter->addOp(getTemplatizedOp<Promote>(dimWanted));
206  int finalOp = _interpreter->allocFP(dimWanted);
208  _interpreter->addOperand(finalOp);
209  _returnSlot = finalOp;
210  _interpreter->endOp();
211  }
212  }
213  if (debugging) _interpreter->print();
214  } else { // useLLVM
215  if (debugging) {
216  std::cerr << "Eval strategy is llvm" << std::endl;
218  }
220  error = true;
221  }
222  }
223 
224  // TODO: need promote
226  }
227 
228  if (error) {
229  _isValid = false;
230  _returnType = ExprType().Error();
231 
232  // build line lookup table
233  std::vector<int> lines;
234  const char* start = _expression.c_str();
235  const char* p = _expression.c_str();
236  while (*p != 0) {
237  if (*p == '\n') lines.push_back(static_cast<int>(p - start));
238  p++;
239  }
240  lines.push_back(static_cast<int>(p - start));
241 
242  std::stringstream sstream;
243  for (unsigned int i = 0; i < _errors.size(); i++) {
244  int* bound = std::lower_bound(&*lines.begin(), &*lines.end(), _errors[i].startPos);
245  int line = static_cast<int>(bound - &*lines.begin() + 1);
246  int lineStart = line == 1 ? 0 : lines[line - 1];
247  int col = _errors[i].startPos - lineStart;
248  sstream << " Line " << line << " Col " << col << " - " << _errors[i].error << std::endl;
249  }
250  _parseError = std::string(sstream.str());
251  }
252 
253  if (debugging) {
254  std::cerr << "ending with isValid " << _isValid << std::endl;
255  std::cerr << "parse error \n" << _parseError << std::endl;
256  }
257 }
258 
259 bool Expression::isVec() const {
260  prepIfNeeded();
261  return _isValid ? _parseTree->isVec() : _wantVec;
262 }
263 
265  prepIfNeeded();
266  return _returnType;
267 }
268 
269 const double* Expression::evalFP(VarBlock* varBlock) const {
270  prepIfNeeded();
271  if (_isValid) {
273  _interpreter->eval(varBlock);
274  return (varBlock && varBlock->threadSafe) ? &(varBlock->d[_returnSlot]) : &_interpreter->d[_returnSlot];
275  } else { // useLLVM
276  return _llvmEvaluator->evalFP(varBlock);
277  }
278  }
279  static double noCrash[16] = {};
280  return noCrash;
281 }
282 
283 void Expression::evalMultiple(VarBlock* varBlock, int outputVarBlockOffset, size_t rangeStart, size_t rangeEnd) const {
284  prepIfNeeded();
285  if (_isValid) {
287  // TODO: need strings to work
288  int dim = _desiredReturnType.dim();
289  // double* iHack=reinterpret_cast<double**>(varBlock->data())[outputVarBlockOffset];
290  double* destBase = reinterpret_cast<double**>(varBlock->data())[outputVarBlockOffset];
291  for (size_t i = rangeStart; i < rangeEnd; i++) {
292  varBlock->indirectIndex = static_cast<int>(i);
293  const double* f = evalFP(varBlock);
294  for (int k = 0; k < dim; k++) {
295  destBase[dim * i + k] = f[k];
296  }
297  }
298  } else { // useLLVM
299  _llvmEvaluator->evalMultiple(varBlock, outputVarBlockOffset, rangeStart, rangeEnd);
300  }
301  }
302 }
303 
304 const char* Expression::evalStr(VarBlock* varBlock) const {
305  prepIfNeeded();
306  if (_isValid) {
308  _interpreter->eval(varBlock);
309  return (varBlock && varBlock->threadSafe) ? varBlock->s[_returnSlot] : _interpreter->s[_returnSlot];
310  } else { // useLLVM
311  return _llvmEvaluator->evalStr(varBlock);
312  }
313  }
314  return nullptr;
315 }
316 
317 } // end namespace KSeExpr/
static constexpr std::array< int, 514 > p
Definition: NoiseTables.h:10
static void init()
call to define built-in funcs
Definition: ExprFunc.cpp:104
virtual ExprType prep(bool dontNeedScalar, ExprVarEnvBuilder &envBuilder)
Definition: ExprNode.cpp:121
virtual int buildInterpreter(Interpreter *interpreter) const
builds an interpreter. Returns the location index for the evaluated data
const ExprType & type() const
The type of the node.
Definition: ExprNode.h:150
void addError(const ErrorCode error, const std::vector< std::string > &ids={}) const
Register error. This will allow users and sophisticated editors to highlight where in code problem wa...
Definition: ExprNode.h:182
bool isVec() const
True if node has a vector result.
Definition: ExprNode.h:83
bool isValid() const
Definition: ExprType.h:202
int dim() const
Definition: ExprType.h:180
bool isLifetimeConstant() const
validity check: type is not an error
Definition: ExprType.h:230
std::string toString() const
Stringify the type into a printable string.
Definition: ExprType.h:253
bool isFP() const
Direct is predicate checks.
Definition: ExprType.h:190
ExprType & Error()
Mutate this into an error type.
Definition: ExprType.h:111
static bool valuesCompatible(const ExprType &a, const ExprType &b)
Checks if value types are compatible.
Definition: ExprType.h:220
void reset()
Reset to factory state (one empty environment that is current)
Definition: ExprEnv.h:189
const VarBlockCreator * _varBlockCreator
Definition: Expression.h:318
void evalMultiple(VarBlock *varBlock, int outputVarBlockOffset, size_t rangeStart, size_t rangeEnd) const
Evaluate multiple blocks.
Definition: Expression.cpp:283
ErrorCode _parseErrorCode
Definition: Expression.h:287
void setExpr(const std::string &e)
Definition: Expression.cpp:134
bool syntaxOK() const
Definition: Expression.cpp:139
static bool debugging
Whether to debug expressions.
Definition: Expression.h:77
std::set< std::string > _vars
Definition: Expression.h:299
bool usesFunc(const std::string &name) const
Definition: Expression.cpp:154
const Context * _context
Definition: Expression.h:264
void parse() const
Definition: Expression.cpp:159
bool isConstant() const
Definition: Expression.cpp:144
void parseIfNeeded() const
Definition: Expression.h:244
void prep() const
Definition: Expression.cpp:169
EvaluationStrategy _evaluationStrategy
Definition: Expression.h:261
Expression(EvaluationStrategy be=Expression::defaultEvaluationStrategy)
Definition: Expression.cpp:54
void addError(const ErrorCode error, const std::vector< std::string > ids, const int startPos, const int endPos) const
Definition: Expression.h:207
std::set< std::string > _funcs
Definition: Expression.h:302
bool usesVar(const std::string &name) const
Definition: Expression.cpp:149
ExprNode * _parseTree
Definition: Expression.h:273
Interpreter * _interpreter
Definition: Expression.h:311
std::vector< std::string > _parseErrorIds
Definition: Expression.h:290
const double * evalFP(VarBlock *varBlock=nullptr) const
Definition: Expression.cpp:269
void prepIfNeeded() const
Definition: Expression.h:276
ExprType _returnType
Definition: Expression.h:256
bool isVec() const
Definition: Expression.cpp:259
EvaluationStrategy
Types of evaluation strategies that are available.
Definition: Expression.h:70
void debugPrintParseTree() const
Definition: Expression.cpp:85
void setContext(const Context &context)
Definition: Expression.cpp:119
ExprVarEnvBuilder _envBuilder
Definition: Expression.h:271
void debugPrintInterpreter() const
Definition: Expression.cpp:76
virtual ~Expression()
Definition: Expression.cpp:71
const ExprType & returnType() const
Definition: Expression.cpp:264
std::vector< std::pair< int, int > > _comments
Definition: Expression.h:296
const Context & context() const
Definition: Expression.h:218
const char * evalStr(VarBlock *varBlock=nullptr) const
Definition: Expression.cpp:304
std::vector< Error > _errors
Definition: Expression.h:293
void setVarBlockCreator(const VarBlockCreator *varBlockCreator)
Definition: Expression.cpp:129
ExprType _desiredReturnType
Definition: Expression.h:268
std::vector< std::string > _threadUnsafeFunctionCalls
Definition: Expression.h:308
void setDesiredReturnType(const ExprType &type)
Definition: Expression.cpp:124
static EvaluationStrategy defaultEvaluationStrategy
What evaluation strategy to use by default.
Definition: Expression.h:75
std::string _expression
Definition: Expression.h:259
void debugPrintLLVM() const
Definition: Expression.cpp:83
LLVMEvaluator * _llvmEvaluator
Definition: Expression.h:315
std::vector< double > d
Double data (constants and evaluated)
Definition: Interpreter.h:33
int addOp(OpF op)
! adds an operator to the program (pointing to the data at the current location)
Definition: Interpreter.h:63
void eval(VarBlock *varBlock, bool debug=false)
Evaluate program.
Definition: Interpreter.cpp:20
void endOp(bool execute=true)
Definition: Interpreter.h:73
std::vector< char * > s
constant and evaluated pointer data
Definition: Interpreter.h:35
int allocFP(int n)
! Allocate a floating point set of data of dimension n
Definition: Interpreter.h:94
int addOperand(int param)
! Adds an operand. Note this should be done after doing the addOp!
Definition: Interpreter.h:86
void print(int pc=-1) const
Debug by printing program.
Definition: Interpreter.cpp:58
static bool prepLLVM(ExprNode *, ExprType)
Definition: Evaluator.h:466
static const char * evalStr(VarBlock *)
Definition: Evaluator.h:456
static const double * evalFP(VarBlock *)
Definition: Evaluator.h:461
static void evalMultiple(VarBlock *, int, size_t, size_t)
Definition: Evaluator.h:471
A class that lets you register for the variables used by one or more expressions.
Definition: VarBlock.h:90
A thread local evaluation context. Just allocate and fill in with data.
Definition: VarBlock.h:22
int indirectIndex
indirect index to add to pointer based data
Definition: VarBlock.h:64
std::vector< char * > s
copy of Interpreter's str data
Definition: VarBlock.h:73
std::vector< double > d
copy of Interpreter's double data
Definition: VarBlock.h:70
char ** data()
Raw data of the data block pointer (used by compiler)
Definition: VarBlock.h:76
bool threadSafe
if true, interpreter's data will be copied to this instance before evaluation.
Definition: VarBlock.h:67
void walk(T_NODE *examinee)
Preorder walk.
Definition: ExprWalker.cpp:15
static Expression::EvaluationStrategy chooseDefaultEvaluationStrategy()
Definition: Expression.cpp:31
bool ExprParse(KSeExpr::ExprNode *&parseTree, KSeExpr::ErrorCode &errorCode, std::vector< std::string > &errorIds, int &errorStart, int &errorEnd, std::vector< std::pair< int, int > > &_comments, const KSeExpr::Expression *expr, const char *str, bool wantVec=true)
@ None
OK.
Definition: ErrorCode.h:9
@ ExpressionIncompatibleTypes
"Expression generated type " << _parseTree->type() << " incompatible with desired type " << _desiredR...
Definition: ErrorCode.h:50