32 virtual Type getType()
const noexcept = 0;
33 virtual Term* clone()
const = 0;
35 virtual String toString()
const = 0;
36 virtual double toDouble()
const {
return 0; }
37 virtual int getInputIndexFor (
const Term*)
const {
return -1; }
38 virtual int getOperatorPrecedence()
const {
return 0; }
39 virtual int getNumInputs()
const {
return 0; }
40 virtual Term* getInput (
int)
const {
return nullptr; }
44 double ,
Term* )
const
50 virtual String getName()
const
56 virtual void renameSymbol (
const Symbol& oldSymbol,
const String& newName,
const Scope& scope,
int recursionDepth)
58 for (
int i = getNumInputs(); --i >= 0;)
59 getInput (i)->renameSymbol (oldSymbol, newName, scope, recursionDepth);
66 virtual void useSymbol (
const Symbol&) = 0;
69 virtual void visitAllSymbols (
SymbolVisitor& visitor,
const Scope& scope,
int recursionDepth)
71 for (
int i = getNumInputs(); --i >= 0;)
72 getInput(i)->visitAllSymbols (visitor, scope, recursionDepth);
76 JUCE_DECLARE_NON_COPYABLE (
Term)
85 static void checkRecursionDepth (
int depth)
100 DBG (
"Expression::EvaluationError: " + description);
110 Constant (
double val,
bool resolutionTarget)
111 : value (val), isResolutionTarget (resolutionTarget) {}
113 Type getType()
const noexcept {
return constantType; }
114 Term* clone()
const {
return new Constant (value, isResolutionTarget); }
116 double toDouble()
const {
return value; }
117 TermPtr negated() {
return *
new Constant (-value, isResolutionTarget); }
122 if (isResolutionTarget)
129 bool isResolutionTarget;
138 jassert (left !=
nullptr && right !=
nullptr);
141 int getInputIndexFor (
const Term* possibleInput)
const
143 return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
146 Type getType()
const noexcept {
return operatorType; }
147 int getNumInputs()
const {
return 2; }
148 Term* getInput (
int index)
const {
return index == 0 ? left.
get() : (index == 1 ? right.
get() :
nullptr); }
150 virtual double performFunction (
double left,
double right)
const = 0;
151 virtual void writeOperator (
String& dest)
const = 0;
153 TermPtr resolve (
const Scope& scope,
int recursionDepth)
155 return *
new Constant (performFunction (left ->resolve (scope, recursionDepth)->toDouble(),
156 right->resolve (scope, recursionDepth)->toDouble()),
false);
162 auto ourPrecendence = getOperatorPrecedence();
164 if (left->getOperatorPrecedence() > ourPrecendence)
165 s <<
'(' << left->toString() <<
')';
167 s = left->toString();
171 if (right->getOperatorPrecedence() >= ourPrecendence)
172 s <<
'(' << right->toString() <<
')';
174 s << right->toString();
182 TermPtr createDestinationTerm (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const
184 jassert (input == left || input == right);
185 if (input != left && input != right)
188 if (
auto dest = findDestinationFor (topLevelTerm,
this))
189 return dest->createTermToEvaluateInput (scope,
this, overallTarget, topLevelTerm);
191 return *
new Constant (overallTarget,
false);
201 TermPtr resolve (
const Scope& scope,
int recursionDepth)
203 checkRecursionDepth (recursionDepth);
204 return scope.
getSymbolValue (symbol).term->resolve (scope, recursionDepth + 1);
207 Type getType()
const noexcept {
return symbolType; }
209 String toString()
const {
return symbol; }
210 String getName()
const {
return symbol; }
214 checkRecursionDepth (recursionDepth);
216 scope.
getSymbolValue (symbol).term->visitAllSymbols (visitor, scope, recursionDepth + 1);
219 void renameSymbol (
const Symbol& oldSymbol,
const String& newName,
const Scope& scope,
int )
235 : functionName (name), parameters (params)
238 Type getType()
const noexcept {
return functionType; }
239 Term* clone()
const {
return new Function (functionName, parameters); }
240 int getNumInputs()
const {
return parameters.size(); }
241 Term* getInput (
int i)
const {
return parameters.getReference(i).term.get(); }
242 String getName()
const {
return functionName; }
244 TermPtr resolve (
const Scope& scope,
int recursionDepth)
246 checkRecursionDepth (recursionDepth);
248 auto numParams = parameters.size();
254 for (
int i = 0; i < numParams; ++i)
255 params[i] = parameters.getReference(i).term->resolve (scope, recursionDepth + 1)->toDouble();
264 return *
new Constant (result,
false);
267 int getInputIndexFor (
const Term* possibleInput)
const
269 for (
int i = 0; i < parameters.size(); ++i)
270 if (parameters.getReference(i).term == possibleInput)
278 if (parameters.size() == 0)
279 return functionName +
"()";
281 String s (functionName +
" (");
283 for (
int i = 0; i < parameters.size(); ++i)
285 s << parameters.getReference(i).term->toString();
287 if (i < parameters.size() - 1)
295 const String functionName;
305 TermPtr resolve (
const Scope& scope,
int recursionDepth)
307 checkRecursionDepth (recursionDepth);
309 EvaluationVisitor visitor (right, recursionDepth + 1);
311 return visitor.output;
315 String getName()
const {
return "."; }
316 int getOperatorPrecedence()
const {
return 1; }
317 void writeOperator (
String& dest)
const { dest <<
'.'; }
318 double performFunction (
double,
double)
const {
return 0.0; }
322 checkRecursionDepth (recursionDepth);
325 SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);
334 void renameSymbol (
const Symbol& oldSymbol,
const String& newName,
const Scope& scope,
int recursionDepth)
336 checkRecursionDepth (recursionDepth);
337 getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth);
339 SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1);
353 EvaluationVisitor (
const TermPtr& t,
const int recursion)
354 : input (t), output (t), recursionCount (recursion) {}
356 void visit (
const Scope& scope) { output = input->resolve (scope, recursionCount); }
360 const int recursionCount;
363 JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor)
370 : input (t), visitor (v), recursionCount (recursion) {}
372 void visit (
const Scope& scope) { input->visitAllSymbols (visitor, scope, recursionCount); }
377 const int recursionCount;
379 JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor)
386 : input (t),
symbol (symbol_), newName (newName_), recursionCount (recursionCount_) {}
388 void visit (
const Scope& scope) { input->renameSymbol (
symbol, newName, scope, recursionCount); }
394 const int recursionCount;
396 JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor)
410 jassert (t !=
nullptr);
413 Type getType()
const noexcept {
return operatorType; }
414 int getInputIndexFor (
const Term* possibleInput)
const {
return possibleInput == input ? 0 : -1; }
415 int getNumInputs()
const {
return 1; }
416 Term* getInput (
int index)
const {
return index == 0 ? input.
get() :
nullptr; }
417 Term* clone()
const {
return new Negate (*input->clone()); }
419 TermPtr resolve (
const Scope& scope,
int recursionDepth)
421 return *
new Constant (-input->resolve (scope, recursionDepth)->toDouble(),
false);
424 String getName()
const {
return "-"; }
425 TermPtr negated() {
return input; }
427 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* t,
double overallTarget,
Term* topLevelTerm)
const
430 jassert (t == input);
432 const Term*
const dest = findDestinationFor (topLevelTerm,
this);
435 : dest->createTermToEvaluateInput (scope,
this, overallTarget, topLevelTerm));
440 if (input->getOperatorPrecedence() > 0)
441 return "-(" + input->toString() +
")";
443 return "-" + input->toString();
456 Term* clone()
const {
return new Add (*left->clone(), *right->clone()); }
457 double performFunction (
double lhs,
double rhs)
const {
return lhs + rhs; }
458 int getOperatorPrecedence()
const {
return 3; }
459 String getName()
const {
return "+"; }
460 void writeOperator (
String& dest)
const { dest <<
" + "; }
462 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const
464 if (
auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
465 return *
new Subtract (newDest, *(input == left ? right : left)->clone());
471 JUCE_DECLARE_NON_COPYABLE (
Add)
480 Term* clone()
const {
return new Subtract (*left->clone(), *right->clone()); }
481 double performFunction (
double lhs,
double rhs)
const {
return lhs - rhs; }
482 int getOperatorPrecedence()
const {
return 3; }
483 String getName()
const {
return "-"; }
484 void writeOperator (
String& dest)
const { dest <<
" - "; }
486 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const
488 if (
auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
491 return *
new Add (*newDest, *right->clone());
493 return *
new Subtract (*left->clone(), *newDest);
500 JUCE_DECLARE_NON_COPYABLE (
Subtract)
509 Term* clone()
const {
return new Multiply (*left->clone(), *right->clone()); }
510 double performFunction (
double lhs,
double rhs)
const {
return lhs * rhs; }
511 String getName()
const {
return "*"; }
512 void writeOperator (
String& dest)
const { dest <<
" * "; }
513 int getOperatorPrecedence()
const {
return 2; }
515 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const
517 if (
auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
518 return *
new Divide (newDest, *(input == left ? right : left)->clone());
523 JUCE_DECLARE_NON_COPYABLE (
Multiply)
532 Term* clone()
const {
return new Divide (*left->clone(), *right->clone()); }
533 double performFunction (
double lhs,
double rhs)
const {
return lhs / rhs; }
534 String getName()
const {
return "/"; }
535 void writeOperator (
String& dest)
const { dest <<
" / "; }
536 int getOperatorPrecedence()
const {
return 2; }
538 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const
540 auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm);
542 if (newDest ==
nullptr)
546 return *
new Multiply (*newDest, *right->clone());
548 return *
new Divide (*left->clone(), *newDest);
551 JUCE_DECLARE_NON_COPYABLE (
Divide)
555 static Term* findDestinationFor (
Term*
const topLevel,
const Term*
const inputTerm)
557 const int inputIndex = topLevel->getInputIndexFor (inputTerm);
561 for (
int i = topLevel->getNumInputs(); --i >= 0;)
563 Term*
const t = findDestinationFor (topLevel->getInput (i), inputTerm);
572 static Constant* findTermToAdjust (Term*
const term,
const bool mustBeFlagged)
574 jassert (term !=
nullptr);
576 if (term->getType() == constantType)
578 Constant*
const c =
static_cast<Constant*
> (term);
579 if (c->isResolutionTarget || ! mustBeFlagged)
583 if (term->getType() == functionType)
586 const int numIns = term->getNumInputs();
588 for (
int i = 0; i < numIns; ++i)
590 Term*
const input = term->getInput (i);
592 if (input->getType() == constantType)
594 Constant*
const c =
static_cast<Constant*
> (input);
596 if (c->isResolutionTarget || ! mustBeFlagged)
601 for (
int i = 0; i < numIns; ++i)
602 if (
auto c = findTermToAdjust (term->getInput (i), mustBeFlagged))
608 static bool containsAnySymbols (
const Term& t)
610 if (t.getType() == Expression::symbolType)
613 for (
int i = t.getNumInputs(); --i >= 0;)
614 if (containsAnySymbols (*t.getInput (i)))
625 void useSymbol (
const Symbol& s) { wasFound = wasFound || s == symbol; }
627 bool wasFound =
false;
640 void useSymbol (
const Symbol& s) { list.addIfNotAlreadyThere (s); }
662 auto e = readExpression();
664 if (e ==
nullptr || ((! readOperator (
",")) && ! text.
isEmpty()))
665 return parseError (
"Syntax error: \"" +
String (text) +
"\"");
684 static inline bool isDecimalDigit (
const juce_wchar c) noexcept
686 return c >=
'0' && c <=
'9';
689 bool readChar (
const juce_wchar required) noexcept
691 if (*text == required)
700 bool readOperator (
const char* ops,
char*
const opType =
nullptr) noexcept
706 if (readChar ((juce_wchar) (uint8) *ops))
708 if (opType !=
nullptr)
720 bool readIdentifier (
String& identifier) noexcept
726 if (t.isLetter() || *t ==
'_')
731 while (t.isLetterOrDigit() || *t ==
'_')
740 identifier =
String (text, (
size_t) numChars);
748 Term* readNumber() noexcept
752 bool isResolutionTarget = (*t ==
'@');
754 if (isResolutionTarget)
767 if (isDecimalDigit (*t) || (*t ==
'.' && isDecimalDigit (t[1])))
775 auto lhs = readMultiplyOrDivideExpression();
778 while (lhs !=
nullptr && readOperator (
"+-", &opType))
780 auto rhs = readMultiplyOrDivideExpression();
783 return parseError (
"Expected expression after \"" +
String::charToString ((juce_wchar) (uint8) opType) +
"\"");
786 lhs = *
new Add (lhs, rhs);
794 TermPtr readMultiplyOrDivideExpression()
796 auto lhs = readUnaryExpression();
799 while (lhs !=
nullptr && readOperator (
"*/", &opType))
801 TermPtr rhs (readUnaryExpression());
804 return parseError (
"Expected expression after \"" +
String::charToString ((juce_wchar) (uint8) opType) +
"\"");
809 lhs = *
new Divide (lhs, rhs);
818 if (readOperator (
"+-", &opType))
820 TermPtr e (readUnaryExpression());
823 return parseError (
"Expected expression after \"" +
String::charToString ((juce_wchar) (uint8) opType) +
"\"");
831 return readPrimaryExpression();
834 TermPtr readPrimaryExpression()
836 if (
auto e = readParenthesisedExpression())
839 if (
auto e = readNumber())
842 return readSymbolOrFunction();
849 if (readIdentifier (identifier))
851 if (readOperator (
"("))
854 std::unique_ptr<Term> func (f);
856 auto param = readExpression();
858 if (param ==
nullptr)
860 if (readOperator (
")"))
861 return TermPtr (func.release());
863 return parseError (
"Expected parameters after \"" + identifier +
" (\"");
868 while (readOperator (
","))
870 param = readExpression();
872 if (param ==
nullptr)
873 return parseError (
"Expected expression after \",\"");
878 if (readOperator (
")"))
879 return TermPtr (func.release());
881 return parseError (
"Expected \")\"");
884 if (readOperator (
"."))
886 TermPtr rhs (readSymbolOrFunction());
889 return parseError (
"Expected symbol or function after \".\"");
891 if (identifier ==
"this")
898 jassert (identifier.
trim() == identifier);
905 TermPtr readParenthesisedExpression()
907 if (! readOperator (
"("))
910 auto e = readExpression();
912 if (e ==
nullptr || ! readOperator (
")"))
918 JUCE_DECLARE_NON_COPYABLE (
Parser)
934 jassert (term !=
nullptr);
954 : term (std::move (other.term))
960 term = std::move (other.term);
968 term = parser.readUpToComma();
969 parseError = parser.error;
976 parseError = parser.error;
995 return term->resolve (scope, 0)->toDouble();
999 evaluationError = e.description;
1019 std::unique_ptr<Term> newTerm (term->clone());
1021 auto termToAdjust = Helpers::findTermToAdjust (newTerm.get(),
true);
1023 if (termToAdjust ==
nullptr)
1024 termToAdjust = Helpers::findTermToAdjust (newTerm.get(),
false);
1026 if (termToAdjust ==
nullptr)
1029 termToAdjust = Helpers::findTermToAdjust (newTerm.get(),
false);
1032 jassert (termToAdjust !=
nullptr);
1034 if (
const Term* parent = Helpers::findDestinationFor (newTerm.get(), termToAdjust))
1036 if (
Helpers::TermPtr reverseTerm = parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm.get()))
1037 termToAdjust->value =
Expression (reverseTerm.get()).evaluate (scope);
1043 termToAdjust->value = targetValue;
1057 e.term->renameSymbol (oldSymbol, newName, scope, 0);
1067 term->visitAllSymbols (visitor, scope, 0);
1072 return visitor.wasFound;
1080 term->visitAllSymbols (visitor, scope, 0);
1096 return *
new Helpers::Negate (*
this);
1100 Expression::Symbol::Symbol (
const String& scope,
const String&
symbol)
1101 : scopeUID (scope), symbolName (
symbol)
1105 bool Expression::Symbol::operator== (
const Symbol& other)
const noexcept
1107 return symbolName == other.symbolName && scopeUID == other.scopeUID;
1110 bool Expression::Symbol::operator!= (
const Symbol& other)
const noexcept
1112 return ! operator== (other);
1116 Expression::Scope::Scope() {}
1117 Expression::Scope::~Scope() {}
1131 if (functionName ==
"min")
1133 double v = parameters[0];
1134 for (
int i = 1; i < numParams; ++i)
1135 v = jmin (v, parameters[i]);
1140 if (functionName ==
"max")
1142 double v = parameters[0];
1143 for (
int i = 1; i < numParams; ++i)
1144 v = jmax (v, parameters[i]);
1151 if (functionName ==
"sin")
return std::sin (parameters[0]);
1152 if (functionName ==
"cos")
return std::cos (parameters[0]);
1153 if (functionName ==
"tan")
return std::tan (parameters[0]);
1154 if (functionName ==
"abs")
return std::abs (parameters[0]);