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);
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 override {
return constantType; }
114 Term* clone()
const override {
return new Constant (value, isResolutionTarget); }
115 TermPtr resolve (
const Scope&,
int)
override {
return *
this; }
116 double toDouble()
const override {
return value; }
117 TermPtr negated()
override {
return *
new Constant (-value, isResolutionTarget); }
119 String toString()
const override
122 if (isResolutionTarget)
129 bool isResolutionTarget;
138 jassert (left !=
nullptr && right !=
nullptr);
141 int getInputIndexFor (
const Term* possibleInput)
const override
143 return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
146 Type getType()
const noexcept override {
return operatorType; }
147 int getNumInputs()
const override {
return 2; }
148 Term* getInput (
int index)
const override {
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)
override
155 return *
new Constant (performFunction (left ->resolve (scope, recursionDepth)->toDouble(),
156 right->resolve (scope, recursionDepth)->toDouble()),
false);
159 String toString()
const override
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)
override
203 checkRecursionDepth (recursionDepth);
204 return scope.
getSymbolValue (symbol).term->resolve (scope, recursionDepth + 1);
207 Type getType()
const noexcept override {
return symbolType; }
209 String toString()
const override {
return symbol; }
210 String getName()
const override {
return symbol; }
212 void visitAllSymbols (
SymbolVisitor& visitor,
const Scope& scope,
int recursionDepth)
override
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 )
override
235 : functionName (name), parameters (params)
238 Type getType()
const noexcept override {
return functionType; }
239 Term* clone()
const override {
return new Function (functionName, parameters); }
240 int getNumInputs()
const override {
return parameters.size(); }
241 Term* getInput (
int i)
const override {
return parameters.getReference (i).term.get(); }
242 String getName()
const override {
return functionName; }
244 TermPtr resolve (
const Scope& scope,
int recursionDepth)
override
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 override
269 for (
int i = 0; i < parameters.size(); ++i)
270 if (parameters.getReference (i).term == possibleInput)
276 String toString()
const override
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)
override
307 checkRecursionDepth (recursionDepth);
309 EvaluationVisitor visitor (right, recursionDepth + 1);
311 return visitor.output;
314 Term* clone()
const override {
return new DotOperator (getSymbol(), *right); }
315 String getName()
const override {
return "."; }
316 int getOperatorPrecedence()
const override {
return 1; }
317 void writeOperator (
String& dest)
const override { dest <<
'.'; }
318 double performFunction (
double,
double)
const override {
return 0.0; }
320 void visitAllSymbols (
SymbolVisitor& visitor,
const Scope& scope,
int recursionDepth)
override
322 checkRecursionDepth (recursionDepth);
325 SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);
334 void renameSymbol (
const Symbol& oldSymbol,
const String& newName,
const Scope& scope,
int recursionDepth)
override
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)
override { output = input->resolve (scope, recursionCount); }
360 const int recursionCount;
370 : input (t), visitor (v), recursionCount (recursion) {}
372 void visit (
const Scope& scope)
override { input->visitAllSymbols (visitor, scope, recursionCount); }
377 const int recursionCount;
386 : input (t), symbol (symbol_), newName (newName_), recursionCount (recursionCount_) {}
388 void visit (
const Scope& scope)
override { input->renameSymbol (symbol, newName, scope, recursionCount); }
394 const int recursionCount;
413 Type getType()
const noexcept override {
return operatorType; }
414 int getInputIndexFor (
const Term* possibleInput)
const override {
return possibleInput == input ? 0 : -1; }
415 int getNumInputs()
const override {
return 1; }
416 Term* getInput (
int index)
const override {
return index == 0 ? input.
get() :
nullptr; }
417 Term* clone()
const override {
return new Negate (*input->clone()); }
419 TermPtr resolve (
const Scope& scope,
int recursionDepth)
override
421 return *
new Constant (-input->resolve (scope, recursionDepth)->toDouble(),
false);
424 String getName()
const override {
return "-"; }
425 TermPtr negated()
override {
return input; }
427 TermPtr createTermToEvaluateInput (
const Scope& scope, [[maybe_unused]]
const Term* t,
double overallTarget,
Term* topLevelTerm)
const override
431 const Term*
const dest = findDestinationFor (topLevelTerm,
this);
434 : dest->createTermToEvaluateInput (scope,
this, overallTarget, topLevelTerm));
437 String toString()
const override
439 if (input->getOperatorPrecedence() > 0)
440 return "-(" + input->toString() +
")";
442 return "-" + input->toString();
455 Term* clone()
const override {
return new Add (*left->clone(), *right->clone()); }
456 double performFunction (
double lhs,
double rhs)
const override {
return lhs + rhs; }
457 int getOperatorPrecedence()
const override {
return 3; }
458 String getName()
const override {
return "+"; }
459 void writeOperator (
String& dest)
const override { dest <<
" + "; }
461 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const override
463 if (
auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
464 return *
new Subtract (newDest, *(input == left ? right : left)->clone());
479 Term* clone()
const override {
return new Subtract (*left->clone(), *right->clone()); }
480 double performFunction (
double lhs,
double rhs)
const override {
return lhs - rhs; }
481 int getOperatorPrecedence()
const override {
return 3; }
482 String getName()
const override {
return "-"; }
483 void writeOperator (
String& dest)
const override { dest <<
" - "; }
485 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const override
487 if (
auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
490 return *
new Add (*newDest, *right->clone());
492 return *
new Subtract (*left->clone(), *newDest);
508 Term* clone()
const override {
return new Multiply (*left->clone(), *right->clone()); }
509 double performFunction (
double lhs,
double rhs)
const override {
return lhs * rhs; }
510 String getName()
const override {
return "*"; }
511 void writeOperator (
String& dest)
const override { dest <<
" * "; }
512 int getOperatorPrecedence()
const override {
return 2; }
514 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const override
516 if (
auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
517 return *
new Divide (newDest, *(input == left ? right : left)->clone());
531 Term* clone()
const override {
return new Divide (*left->clone(), *right->clone()); }
532 double performFunction (
double lhs,
double rhs)
const override {
return lhs / rhs; }
533 String getName()
const override {
return "/"; }
534 void writeOperator (
String& dest)
const override { dest <<
" / "; }
535 int getOperatorPrecedence()
const override {
return 2; }
537 TermPtr createTermToEvaluateInput (
const Scope& scope,
const Term* input,
double overallTarget,
Term* topLevelTerm)
const override
539 auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm);
541 if (newDest ==
nullptr)
545 return *
new Multiply (*newDest, *right->clone());
547 return *
new Divide (*left->clone(), *newDest);
554 static Term* findDestinationFor (
Term*
const topLevel,
const Term*
const inputTerm)
556 const int inputIndex = topLevel->getInputIndexFor (inputTerm);
560 for (
int i = topLevel->getNumInputs(); --i >= 0;)
562 Term*
const t = findDestinationFor (topLevel->getInput (i), inputTerm);
571 static Constant* findTermToAdjust (Term*
const term,
const bool mustBeFlagged)
579 if (term->getType() == constantType)
581 Constant*
const c =
static_cast<Constant*
> (term);
582 if (c->isResolutionTarget || ! mustBeFlagged)
586 if (term->getType() == functionType)
589 const int numIns = term->getNumInputs();
591 for (
int i = 0; i < numIns; ++i)
593 Term*
const input = term->getInput (i);
595 if (input->getType() == constantType)
597 Constant*
const c =
static_cast<Constant*
> (input);
599 if (c->isResolutionTarget || ! mustBeFlagged)
604 for (
int i = 0; i < numIns; ++i)
605 if (
auto c = findTermToAdjust (term->getInput (i), mustBeFlagged))
611 static bool containsAnySymbols (
const Term& t)
613 if (t.getType() == Expression::symbolType)
616 for (
int i = t.getNumInputs(); --i >= 0;)
617 if (containsAnySymbols (*t.getInput (i)))
628 void useSymbol (
const Symbol& s)
override { wasFound = wasFound || s == symbol; }
630 bool wasFound =
false;
643 void useSymbol (
const Symbol& s)
override { list.addIfNotAlreadyThere (s); }
665 auto e = readExpression();
667 if (e ==
nullptr || ((! readOperator (
",")) && ! text.
isEmpty()))
668 return parseError (
"Syntax error: \"" +
String (text) +
"\"");
687 static bool isDecimalDigit (
const juce_wchar c)
noexcept
689 return c >=
'0' && c <=
'9';
692 bool readChar (
const juce_wchar required)
noexcept
694 if (*text == required)
703 bool readOperator (
const char* ops,
char*
const opType =
nullptr)
noexcept
711 if (opType !=
nullptr)
723 bool readIdentifier (
String& identifier)
noexcept
729 if (t.isLetter() || *t ==
'_')
734 while (t.isLetterOrDigit() || *t ==
'_')
743 identifier =
String (text, (
size_t) numChars);
751 Term* readNumber()
noexcept
755 bool isResolutionTarget = (*t ==
'@');
757 if (isResolutionTarget)
770 if (isDecimalDigit (*t) || (*t ==
'.' && isDecimalDigit (t[1])))
778 auto lhs = readMultiplyOrDivideExpression();
781 while (lhs !=
nullptr && readOperator (
"+-", &opType))
783 auto rhs = readMultiplyOrDivideExpression();
789 lhs = *
new Add (lhs, rhs);
797 TermPtr readMultiplyOrDivideExpression()
799 auto lhs = readUnaryExpression();
802 while (lhs !=
nullptr && readOperator (
"*/", &opType))
804 TermPtr rhs (readUnaryExpression());
812 lhs = *
new Divide (lhs, rhs);
821 if (readOperator (
"+-", &opType))
823 TermPtr e (readUnaryExpression());
834 return readPrimaryExpression();
837 TermPtr readPrimaryExpression()
839 if (
auto e = readParenthesisedExpression())
842 if (
auto e = readNumber())
845 return readSymbolOrFunction();
852 if (readIdentifier (identifier))
854 if (readOperator (
"("))
859 auto param = readExpression();
861 if (param ==
nullptr)
863 if (readOperator (
")"))
866 return parseError (
"Expected parameters after \"" + identifier +
" (\"");
871 while (readOperator (
","))
873 param = readExpression();
875 if (param ==
nullptr)
876 return parseError (
"Expected expression after \",\"");
881 if (readOperator (
")"))
884 return parseError (
"Expected \")\"");
887 if (readOperator (
"."))
889 TermPtr rhs (readSymbolOrFunction());
892 return parseError (
"Expected symbol or function after \".\"");
894 if (identifier ==
"this")
908 TermPtr readParenthesisedExpression()
910 if (! readOperator (
"("))
913 auto e = readExpression();
915 if (e ==
nullptr || ! readOperator (
")"))
957 : term (std::move (other.term))
963 term = std::move (other.term);
971 term = parser.readUpToComma();
972 parseError = parser.error;
979 parseError = parser.error;
998 return term->resolve (scope, 0)->toDouble();
1002 evaluationError = e.description;
1024 auto termToAdjust = Helpers::findTermToAdjust (newTerm.
get(),
true);
1026 if (termToAdjust ==
nullptr)
1027 termToAdjust = Helpers::findTermToAdjust (newTerm.
get(),
false);
1029 if (termToAdjust ==
nullptr)
1032 termToAdjust = Helpers::findTermToAdjust (newTerm.
get(),
false);
1035 jassert (termToAdjust !=
nullptr);
1037 if (
const Term* parent = Helpers::findDestinationFor (newTerm.
get(), termToAdjust))
1039 if (
Helpers::TermPtr reverseTerm = parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm.
get()))
1040 termToAdjust->value =
Expression (reverseTerm.get()).evaluate (scope);
1046 termToAdjust->value = targetValue;
1060 e.term->renameSymbol (oldSymbol, newName, scope, 0);
1070 term->visitAllSymbols (visitor, scope, 0);
1075 return visitor.wasFound;
1083 term->visitAllSymbols (visitor, scope, 0);
1099 return *
new Helpers::Negate (*
this);
1103Expression::Symbol::Symbol (
const String& scope,
const String&
symbol)
1104 : scopeUID (scope), symbolName (
symbol)
1108bool Expression::Symbol::operator== (
const Symbol& other)
const noexcept
1110 return symbolName == other.symbolName && scopeUID == other.scopeUID;
1113bool Expression::Symbol::operator!= (
const Symbol& other)
const noexcept
1115 return ! operator== (other);
1119Expression::Scope::Scope() {}
1120Expression::Scope::~Scope() {}
1134 if (functionName ==
"min")
1136 double v = parameters[0];
1137 for (
int i = 1; i < numParams; ++i)
1138 v =
jmin (v, parameters[i]);
1143 if (functionName ==
"max")
1145 double v = parameters[0];
1146 for (
int i = 1; i < numParams; ++i)
1147 v =
jmax (v, parameters[i]);
1154 if (functionName ==
"sin")
return std::sin (parameters[0]);
1155 if (functionName ==
"cos")
return std::cos (parameters[0]);
1156 if (functionName ==
"tan")
return std::tan (parameters[0]);
1157 if (functionName ==
"abs")
return std::abs (parameters[0]);
Holds a resizable array of primitive or copy-by-value objects.
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
void incrementToEndOfWhitespace() noexcept
Move this pointer to the first non-whitespace character in the string.
bool isEmpty() const noexcept
Returns true if this pointer is pointing to a null character.
static double readDoubleValue(CharPointerType &text) noexcept
Parses a character string to read a floating-point number.
An exception that can be thrown by Expression::evaluate().
Used as a callback by the Scope::visitRelativeScope() method.
When evaluating an Expression object, this class is used to resolve symbols and perform functions tha...
virtual Expression getSymbolValue(const String &symbol) const
Returns the value of a symbol.
virtual void visitRelativeScope(const String &scopeName, Visitor &visitor) const
Creates a Scope object for a named scope, and then calls a visitor to do some kind of processing with...
virtual String getScopeUID() const
Returns some kind of globally unique ID that identifies this scope.
virtual double evaluateFunction(const String &functionName, const double *parameters, int numParameters) const
Executes a named function.
A class for dynamically evaluating simple numeric expressions.
Expression operator*(const Expression &) const
Returns an expression which is a multiplication operation of two existing expressions.
Expression adjustedToGiveNewResult(double targetValue, const Scope &scope) const
Attempts to return an expression which is a copy of this one, but with a constant adjusted to make th...
void findReferencedSymbols(Array< Symbol > &results, const Scope &scope) const
Returns a list of all symbols that may be needed to resolve this expression in the given scope.
Expression operator+(const Expression &) const
Returns an expression which is an addition operation of two existing expressions.
static Expression function(const String &functionName, const Array< Expression > ¶meters)
Returns an Expression which is a function call.
String getSymbolOrFunction() const
If this expression is a symbol, function or operator, this returns its identifier.
Expression()
Creates a simple expression with a value of 0.
bool usesAnySymbols() const
Returns true if this expression contains any symbols.
Expression withRenamedSymbol(const Symbol &oldSymbol, const String &newName, const Scope &scope) const
Returns a copy of this expression in which all instances of a given symbol have been renamed.
Expression operator/(const Expression &) const
Returns an expression which is a division operation of two existing expressions.
Type getType() const noexcept
Returns the type of this expression.
double evaluate() const
Evaluates this expression, without using a Scope.
static Expression parse(String::CharPointerType &stringToParse, String &parseError)
Returns an Expression which parses a string from a character pointer, and updates the pointer to indi...
int getNumInputs() const
Returns the number of inputs to this expression.
Expression getInput(int index) const
Retrieves one of the inputs to this expression.
bool referencesSymbol(const Symbol &symbol, const Scope &scope) const
Returns true if this expression makes use of the specified symbol.
static Expression symbol(const String &symbol)
Returns an Expression which is an identifier reference.
Expression operator-() const
Returns an expression which performs a negation operation on an existing expression.
String toString() const
Returns a string version of the expression.
Expression & operator=(const Expression &)
Copies another expression.
Very simple container class to hold a pointer to some data on the heap.
A smart-pointer class which points to a reference-counted object.
ReferencedType * get() const noexcept
Returns the object that this pointer references.
Adds reference-counting to an object.
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
String trim() const
Returns a copy of this string with any whitespace characters removed from the start and end.
bool isEmpty() const noexcept
Returns true if the string contains no characters.
String toLowerCase() const
Returns an lower-case version of this string.
static String charToString(juce_wchar character)
Creates a string from a single character.
bool containsOnly(StringRef charactersItMightContain) const noexcept
Looks for a set of characters in the string.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
Represents a symbol that is used in an Expression.
String symbolName
The name of the symbol.
String scopeUID
The unique ID of the Scope that contains this symbol.