KSeExpr 6.0.0.0
ExprNode.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 <sstream>
9
10#include "ExprEnv.h"
11#include "ExprFunc.h"
12#include "ExprNode.h"
13#include "ExprType.h"
14#include "Expression.h"
15#include "StringUtils.h"
16#include "VarBlock.h"
17#include "Vec.h"
18
19// TODO: add and other binary op demote to scalar if wantScalar
20// TODO: logical operations like foo<bar should they do vector returns... right now no... implicit demote
21// TODO: local function evaluation
22// TODO: buildInterpreter for higher level nodes so the return location can be routed back
23// TODO: ExprFuncNode interpreter stuff
24// TODO: check each node for possibility of strings
25
26namespace KSeExpr
27{
29 : _expr(expr)
30 , _isVec(false)
31{
32}
33
34ExprNode::ExprNode(const Expression *expr, const ExprType &type)
35 : _expr(expr)
36 , _isVec(false)
37 , _type(type)
38{
39}
40
42 : _expr(expr)
43 , _isVec(false)
44{
45 _children.reserve(1);
46 addChild(a);
47}
48
49ExprNode::ExprNode(const Expression *expr, ExprNode *a, const ExprType &type)
50 : _expr(expr)
51 , _isVec(false)
52 , _type(type)
53{
54 _children.reserve(1);
55 addChild(a);
56}
57
59 : _expr(expr)
60 , _isVec(false)
61{
62 _children.reserve(2);
63 addChild(a);
64 addChild(b);
65}
66
68 : _expr(expr)
69 , _isVec(false)
70 , _type(type)
71{
72 _children.reserve(2);
73 addChild(a);
74 addChild(b);
75}
76
78 : _expr(expr)
79 , _isVec(false)
80{
81 _children.reserve(3);
82 addChild(a);
83 addChild(b);
84 addChild(c);
85}
86
88 : _expr(expr)
89 , _isVec(false)
90 , _type(type)
91{
92 _children.reserve(3);
93 addChild(a);
94 addChild(b);
95 addChild(c);
96}
97
99{
100 // delete children
101 std::vector<ExprNode *>::iterator iter;
102 for (iter = _children.begin(); iter != _children.end(); iter++)
103 delete *iter;
104}
105
107{
108 _children.push_back(child);
109 child->_parent = this;
110}
111
113{
114 for (auto & iter : surrogate->_children) {
115 addChild(iter);
116 }
117 surrogate->_children.clear();
118 delete surrogate;
119}
120
122{
128 bool error = false;
129
130 _maxChildDim = 0;
131 for (int c = 0; c < numChildren(); c++) {
132 error |= !child(c)->prep(false, envBuilder).isValid();
133 int childDim = child(c)->type().isFP() ? child(c)->type().dim() : 0;
136 }
137
138 if (error)
139 setType(ExprType().Error());
140 else
142
143 return _type;
144}
145
147{
148 bool error = false;
149
150 for (int c = 0; c < numChildren(); c++)
151 error |= !child(c)->prep(false, envBuilder).isValid();
152 if (error)
153 setType(ExprType().Error());
154 else
155 setType(child(numChildren() - 1)->type());
156
157 return _type;
158}
159
161{
162 bool error = false;
163
164#if 0 // TODO: implement prototype
165 if (_retTypeSet) checkCondition(returnType().isValid(), "Function has bad return type", error);
166
167 _argTypes.clear();
168 for (int c = 0; c < numChildren(); c++) {
169 ExprType type = child(c)->type();
170 checkCondition(type.isValid(), "Function has a parameter with a bad type", error);
171 _argTypes.push_back(type);
172 ExprLocalVar* localVar = new ExprLocalVar(type);
173 envBuilder.current()->add(((ExprVarNode*)child(c))->name(), localVar);
174 std::cerr << "after create localvar phi " << localVar->getPhi() << std::endl;
175 child(c)->prep(wantScalar, envBuilder);
176 }
177#else
178 checkCondition(false, ErrorCode::Unknown, {"Prototypes are currently not supported"}, error);
179#endif
180 if (error)
181 setType(ExprType().Error());
182 else
183 setType(ExprType().None().Varying());
184
185 return _type;
186}
187
189{
191
192 for (int i = 0; i < numChildren(); i++)
193 _argTypes.push_back(child(i)->type());
194}
195
197{
199#if 0
200 ExprNode * child;
202 for(int i = 0; i < numChildren(); i++) {
203 child = this->child(i);
204 type = child->type();
205
206 _argTypes.push_back(type);
207 _env.add(((ExprVarNode*)child)->name(), new ExprLocalVar(type));
208 }
209#endif
210}
211
213{
214 bool error = false;
215
216#if 0 // TODO: no local functions for now
217
218 // prep prototype and check for errors
221 functionEnv.resetAndSetParent(&env);
222 if (!prototype->prep(false, functionEnv).isValid()) error = true;
223
224 // decide what return type we want
225 bool returnWantsScalar = false;
226 if (!error && prototype->isReturnTypeSet()) returnWantsScalar = prototype->returnType().isFP(1);
227
228 // prep block and check for errors
229 ExprNode* block = child(1);
231
232 if (!error && blockType.isValid()) {
233 if (prototype->isReturnTypeSet()) {
234 if (blockType != prototype->returnType()) {
235 checkCondition(false,
236 "In function result of block '" + blockType.toString() +
237 "' does not match given return type " + prototype->returnType().toString(),
238 error);
239 }
240
241 } else
242 prototype->setReturnType(blockType);
243 // register the function in the symbol table
244
245 env.addFunction(prototype->name(), this);
246 } else {
247 checkCondition(false, "Invalid type for blockType is " + blockType.toString(), error);
248 error = true;
249 }
250#else
251 checkCondition(false, ErrorCode::Unknown, {"Local functions are currently not supported."}, error);
252#endif
253
254 if (error)
255 setType(ExprType().Error());
256 else
257 setType(ExprType().None().Varying());
258
259 return _type;
260}
261
262// TODO: write buildInterpreter for local function node
264{
265#if 0
266 bool error = false;
267 callerNode->checkCondition(callerNode->numChildren() == prototype()->numChildren(),
268 "Incorrect number of arguments to function call",
269 error);
270 for (int i = 0; i < callerNode->numChildren(); i++) {
271 // TODO: is this right?
272 // bool compatible=ExprType::valuesCompatible(callerNode->child(i)->prep(false,env), prototype()->argType(i));
273 if (!callerNode->checkArg(i, prototype()->argType(i), envBuilder)) error = true;
274 // callerNode->child(i)->checkCondition(compatible,"Incorrect type for argument",error);
275 }
276 return error ? ExprType().Error() : prototype()->returnType();
277#else
278 bool error = false;
279 callerNode->checkCondition(false, ErrorCode::Unknown, {"Local functions are currently not supported."}, error);
280 return ExprType().Error();
281#endif
282}
283
285{
286 ExprType assignType = child(0)->prep(false, envBuilder);
288
289 if (!assignType.isValid())
290 setType(ExprType().Error());
291 else
293
294 return _type;
295}
296
298{
302
303 bool error = false;
304
305 condType = child(0)->prep(true, envBuilder);
306 checkIsFP(condType, error);
307
308 ExprVarEnv *parentEnv = envBuilder.current();
309 ExprVarEnv *thenEnv = envBuilder.createDescendant(parentEnv);
310 ExprVarEnv *elseEnv = envBuilder.createDescendant(parentEnv);
311 envBuilder.setCurrent(thenEnv);
312 thenType = child(1)->prep(false, envBuilder);
313 thenEnv = envBuilder.current();
314 envBuilder.setCurrent(elseEnv);
315 elseType = child(2)->prep(false, envBuilder);
316 elseEnv = envBuilder.current();
317
318 if (!error && thenType.isValid() && elseType.isValid()) {
319 ExprVarEnv *newEnv = envBuilder.createDescendant(parentEnv);
320 _varEnvMergeIndex = newEnv->mergeBranches(condType, *thenEnv, *elseEnv);
321 envBuilder.setCurrent(newEnv);
322 // TODO: aselle insert the phi nodes!
323 } else {
324 envBuilder.setCurrent(parentEnv); // since the conditionals broke don't include them in new environment
325 error = true;
326 }
327 _varEnv = envBuilder.current();
328
329 if (error)
330 setType(ExprType().Error());
331 else
332 setType(ExprType().None().setLifetime(condType, thenType, elseType));
333
334 return _type;
335}
336
338{
339 _assignedType = child(0)->prep(false, envBuilder);
340
341 std::unique_ptr<ExprLocalVar> localVar(new ExprLocalVar(child(0)->type()));
342 _localVar = localVar.get();
343 envBuilder.current()->add(_name, std::move(localVar));
344 bool error = false;
346
347 if (error)
348 setType(ExprType().Error());
349 else
351 return _type;
352}
353
355{
356 bool error = false;
357
358 int max_child_d = 0;
359 for (int c = 0; c < numChildren(); c++) {
360 ExprType childType = child(c)->prep(true, envBuilder);
361 // TODO: add way to tell what element of vector has the type mismatch
362 checkIsFP(childType, error);
363 max_child_d = std::max(max_child_d, childType.dim());
364 }
365
366 if (error)
367 setType(ExprType().Error());
368 else
370 return _type;
371}
372
374{
375 if (const auto *f = dynamic_cast<const ExprNumNode *>(child(0))) {
376 double first = f->value();
377 if (const auto *s = dynamic_cast<const ExprNumNode *>(child(1))) {
378 double second = s->value();
379 if (const auto *t = dynamic_cast<const ExprNumNode *>(child(2))) {
380 double third = t->value();
381 return {first, second, third};
382 };
383 };
384 };
385
386 return {0.0};
387}
388
390{
391 bool error = false;
392
393 // TODO: aselle may want to implicitly demote to FP[1] if wantScalar is true!
395 checkIsFP(childType, error);
396 if (error)
397 setType(ExprType().Error());
398 else
400 return _type;
401}
402
404{
405 // TODO: determine if extra environments are necessary, currently not included
409
410 bool error = false;
411
412 condType = child(0)->prep(true, envBuilder);
413
414 checkIsFP(condType, error);
415
416 thenType = child(1)->prep(wantScalar, envBuilder);
417 elseType = child(2)->prep(wantScalar, envBuilder);
418
419 checkIsValue(thenType, error);
420 checkIsValue(elseType, error);
422
423 if (error)
424 setType(ExprType().Error());
425 else {
426 if (thenType.isString())
428 else
429 setType(thenType.isFP(1) ? elseType : thenType);
431 }
432
433 return _type;
434}
435
437{
438 // TODO: double-check order of evaluation - order MAY effect environment evaluation (probably not, though)
441
442 bool error = false;
443
444 vecType = child(0)->prep(false, envBuilder); // want scalar is false because we aren't just doing foo[0]
445 checkIsFP(vecType, error);
446
447 scriptType = child(1)->prep(true, envBuilder);
448 checkIsFP(scriptType, error);
449
450 if (error)
451 setType(ExprType().Error());
452 else
453 setType(ExprType().FP(1).setLifetime(vecType, scriptType));
454
455 return _type;
456}
457
459{
460 // TODO: double-check order of evaluation - order MAY effect environment evaluation (probably not, though)
463
464 bool error = false;
465
466 firstType = child(0)->prep(false, envBuilder);
467 checkIsValue(firstType, error);
468 secondType = child(1)->prep(false, envBuilder);
469 checkIsValue(secondType, error);
470
471 if (firstType.isValid() && secondType.isValid())
473
474 if (error)
475 setType(ExprType().Error());
476 else
477 setType(ExprType().FP(1).setLifetime(firstType, secondType));
478
479 return _type;
480}
481
483{
484 // TODO: assume we want scalar
485 // TODO: double-check order of evaluation - order MAY effect environment evaluation (probably not, though)
488
489 bool error = false;
490
491 firstType = child(0)->prep(true, envBuilder);
492 checkIsFP(firstType, error);
493 secondType = child(1)->prep(true, envBuilder);
494 checkIsFP(secondType, error);
495
496 if (firstType.isValid() && secondType.isValid())
498
499 if (error)
500 setType(ExprType().Error());
501 else
502 setType(ExprType().FP(1).setLifetime(firstType, secondType));
503
504 return _type;
505}
506
508{
509 // TODO: aselle this probably should set the type to be FP1 if wantScalar is true!
510 // TODO: double-check order of evaluation - order MAY effect environment evaluation (probably not, though)
513
514 bool error = false;
515
516 // prep children and get their types
517 firstType = child(0)->prep(false, envBuilder);
518 secondType = child(1)->prep(false, envBuilder);
519
520 // check compatibility and get return type
521 // TODO: handle string + fp or fp + string, the same as in Python or equivalent
523 if (error)
524 setType(ExprType().Error());
525 else
526 setType((firstType.isFP(1) ? secondType : firstType).setLifetime(firstType, secondType));
527
528 return _type;
529}
530
532{
533 // ask expression to resolve var
534 bool error = false;
535 if ((_localVar = envBuilder.current()->find(name()))) {
536 if (_localVar->type().isError()) {
538 if (auto *phi = dynamic_cast<ExprLocalVarPhi *>(_localVar)) {
539 if (!phi->_thenVar->type().isError() && !phi->_elseVar->type().isError()) {
541 }
542 }
543 }
545 return _type;
546 } else {
547 // user defined external variable
548 _var = _expr->resolveVar(name());
549 if (!_var) {
550 if (const VarBlockCreator *creator = _expr->varBlockCreator()) {
551 // data block defined external var
552 _var = creator->resolveVar(name());
553 }
554 }
555 if (_var) {
556 _expr->addVar(name()); // register used variable so _expr->usedVar() works
557 setType(_var->type());
558 return _type;
559 }
560 }
561 // If we get here we do not have a variable!
563 setType(ExprType().Error());
564 return _type;
565}
566
568{
569 _type = ExprType().FP(1).Constant();
570 return _type;
571}
572
573ExprStrNode::ExprStrNode(const Expression *expr, const char *str)
574 : ExprNode(expr)
575 , _str(unescapeString(str))
576{
577}
578
580{
582 return _type;
583}
584
586{
587 bool error = false;
588
589 int nargs = numChildren();
590 _promote.resize(nargs, 0);
591
592 // find function using per-expression callback and then global table
593 // TODO: put lookup of local functions here
594 _func = nullptr;
595 if (ExprLocalFunctionNode *localFunction = envBuilder.current()->findFunction(_name)) {
598 // TODO: we need to type check arguments here
599 } else {
600 if (!_func)
601 _func = _expr->resolveFunc(_name);
602 if (!_func)
604
605 // check that function exists and that the function has the right number of arguments
606 if (checkCondition(_func, ErrorCode::UndeclaredFunction, {_name}, error) && checkCondition(nargs >= _func->minArgs(), ErrorCode::FunctionTooFewArguments, {_name}, error) &&
607 checkCondition(nargs <= _func->maxArgs() || _func->maxArgs() < 0, ErrorCode::FunctionTooManyArguments, {_name}, error)) {
608 const ExprFuncX *funcx = _func->funcx();
609 ExprType type = funcx->prep(this, wantScalar, envBuilder);
611 } else { // didn't match num args or function not found
612 ExprNode::prep(false, envBuilder); // prep arguments anyways to catch as many errors as possible!
614 }
615 }
616
617 return _type;
618}
619
621{
622 if (_localFunc)
623 return _localFunc->buildInterpreterForCall(this, interpreter);
624 else if (_func)
625 return _func->funcx()->buildInterpreter(this, interpreter);
626
627 assert(false);
628 return 0;
629}
630
632{
633 ExprType childType = child(arg)->prep(type.isFP(1), envBuilder);
634 _promote[arg] = 0;
635 if (ExprType::valuesCompatible(type, childType) && type.isLifeCompatible(childType)) {
636 if (type.isFP() && type.dim() > childType.dim()) {
637 _promote[arg] = type.dim();
638 }
639 return true;
640 }
641 child(arg)->addError(ErrorCode::ArgumentTypeMismatch, {type.toString(), childType.toString()});
642 return false;
643}
644} // namespace KSeExpr
std::string unescapeString(const std::string &string)
Definition StringUtils.h:13
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:337
ExprLocalVar * _localVar
Definition ExprNode.h:442
const ExprLocalVar * localVar() const
Definition ExprNode.h:435
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:507
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:284
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:458
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:482
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:403
Node that calls a function.
Definition ExprNode.h:654
std::string _name
Definition ExprNode.h:768
bool checkArg(int argIndex, const ExprType &type, ExprVarEnvBuilder &envBuilder)
Definition ExprNode.cpp:631
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:585
int buildInterpreter(Interpreter *interpreter) const override
builds an interpreter. Returns the location index for the evaluated data
Definition ExprNode.cpp:620
std::vector< int > _promote
Definition ExprNode.h:774
const ExprFunc * _func
Definition ExprNode.h:769
const ExprLocalFunctionNode * _localFunc
Definition ExprNode.h:770
Extension function spec, used for complicated argument custom functions.
Definition ExprFuncX.h:23
virtual ExprType prep(ExprFuncNode *node, bool scalarWanted, ExprVarEnvBuilder &env) const =0
static const ExprFunc * lookup(const std::string &name)
Lookup a builtin function by name.
Definition ExprFunc.cpp:116
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:297
Node that contains local function.
Definition ExprNode.h:351
const ExprPrototypeNode * prototype() const
TODO: Accessor for prototype (probably not needed when we use prep right)
Definition ExprNode.h:363
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Preps the definition of this site.
Definition ExprNode.cpp:212
ExprLocalVar join (merge) references. Remembers which variables are possible assigners to this.
Definition ExprEnv.h:84
ExprLocalVar reference, all local variables in seexpr are subclasses of this or this itself.
Definition ExprEnv.h:28
const ExprLocalVar * getPhi() const
get the primary representative phi node (i.e. the global parent of a dependent phi node)
Definition ExprEnv.h:47
ExprType type() const
returns type of the variable
Definition ExprEnv.h:52
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:146
void addChildren(ExprNode *surrogate)
Transfer children from surrogate parent (for parser use only)
Definition ExprNode.cpp:112
virtual ExprType prep(bool dontNeedScalar, ExprVarEnvBuilder &envBuilder)
Definition ExprNode.cpp:121
ExprNode(const Expression *expr)
Definition ExprNode.cpp:28
virtual ~ExprNode()
Definition ExprNode.cpp:98
bool checkIsFP(const ExprType &type, bool &error) const
Checks if the type is a float[d] for any d.
Definition ExprNode.h:224
void setTypeWithChildLife(const ExprType &t)
Set's the type to the argument but uses the children to determine lifetime.
Definition ExprNode.h:194
const ExprType & type() const
The type of the node.
Definition ExprNode.h:150
int numChildren() const
Number of children.
Definition ExprNode.h:108
bool checkCondition(bool check, const ErrorCode message, const std::vector< std::string > &ids, bool &error) const
Checks the boolean value and records an error string with node if it is false.
Definition ExprNode.h:210
std::vector< ExprNode * > _children
List of children.
Definition ExprNode.h:247
bool checkIsValue(const ExprType &type, bool &error) const
Checks if the type is a value (i.e. string or float[d])
Definition ExprNode.h:219
const ExprNode * child(size_t i) const
Get 0 indexed child.
Definition ExprNode.h:114
bool checkTypesCompatible(const ExprType &first, const ExprType &second, bool &error) const
types match (true if they do)
Definition ExprNode.h:234
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
const Expression * _expr
Owning expression (node can't modify)
Definition ExprNode.h:241
void setType(const ExprType &t)
Set type of parameter.
Definition ExprNode.h:189
void addChild(ExprNode *child)
Add a child to the child list (for parser use only)
Definition ExprNode.cpp:106
Node that stores a numeric constant.
Definition ExprNode.h:610
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:567
Node that contains prototype of function.
Definition ExprNode.h:276
std::vector< ExprType > _argTypes
Definition ExprNode.h:343
void addArgs(ExprNode *surrogate)
Definition ExprNode.cpp:196
ExprType returnType() const
Definition ExprNode.h:311
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:160
void addArgTypes(ExprNode *surrogate)
Definition ExprNode.cpp:188
const std::string & name() const
Definition ExprNode.h:325
ExprStrNode(const Expression *expr, const char *str)
Definition ExprNode.cpp:573
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:579
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:436
ExprType & FP(int d)
Mutate this into a floating point type of dimension d.
Definition ExprType.h:97
ExprType & Constant()
Mutate this into a constant lifetime.
Definition ExprType.h:122
bool isValid() const
Definition ExprType.h:202
bool isError() const
Definition ExprType.h:206
ExprType & setLifetime(const ExprType &a)
Assign the lifetime from type a to be my type.
Definition ExprType.h:150
ExprType & String()
Mutate this into a string type.
Definition ExprType.h:104
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
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:389
Variable scope builder is used by the type checking and code gen to track visiblity of variables and ...
Definition ExprEnv.h:181
Variable scope for tracking variable lookup.
Definition ExprEnv.h:120
Node that references a variable.
Definition ExprNode.h:572
ExprVarRef * _var
Definition ExprNode.h:605
ExprLocalVar * _localVar
Definition ExprNode.h:604
const char * name() const
Definition ExprNode.h:589
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:531
virtual ExprType type() const
returns (current) type
Definition Expression.h:50
ExprType prep(bool wantScalar, ExprVarEnvBuilder &envBuilder) override
Definition ExprNode.cpp:354
Vec3d value() const
Definition ExprNode.cpp:373
main expression class
Definition Expression.h:67
A class that lets you register for the variables used by one or more expressions.
Definition VarBlock.h:90
@ ConditionalTypesNotCompatible
"Types of conditional are not compatible",
Definition ErrorCode.h:41
@ UndeclaredFunction
"Function " << _name << " has no definition"
Definition ErrorCode.h:37
@ ArgumentTypeMismatch
"Expected "<< type << " for argument, got " << childType
Definition ErrorCode.h:22
@ BadAssignmentOperator
"Assignment operation has bad type: " << _type
Definition ErrorCode.h:39
@ FunctionTooManyArguments
"Too many args for function " << _name
Definition ErrorCode.h:47
@ UndeclaredVariable
Definition ErrorCode.h:35
@ Unknown
Unknown error (message = %1)
Definition ErrorCode.h:64
@ None
OK.
Definition ErrorCode.h:9
@ FunctionTooFewArguments
"Too few args for function " << _name
Definition ErrorCode.h:45
@ InconsistentDefinition
"Variable " << name() << " defined in conditionals inconsistently."
Definition ErrorCode.h:43