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
58 for (
int i = getNumInputs(); --i >= 0;)
66 virtual void useSymbol (
const Symbol&) = 0;
71 for (
int i = getNumInputs(); --i >= 0;)
85 static void checkRecursionDepth (
int depth)
100 DBG (
"Expression::EvaluationError: " + description);
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);
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;
159 String toString()
const override
165 s <<
'(' << left->toString() <<
')';
167 s = left->toString();
172 s <<
'(' << right->toString() <<
')';
174 s << right->toString();
184 jassert (input == left || input == right);
185 if (input != left && input != right)
188 if (
auto dest = findDestinationFor (
topLevelTerm,
this))
207 Type getType()
const noexcept override {
return symbolType; }
209 String toString()
const override {
return symbol; }
210 String getName()
const override {
return symbol; }
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; }
255 params[i] = parameters.getReference (i).term->resolve (scope,
recursionDepth + 1)->toDouble();
264 return *
new Constant (result,
false);
269 for (
int i = 0; i < parameters.size(); ++i)
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;
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; }
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;
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; }
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()); }
424 String getName()
const override {
return "-"; }
425 TermPtr negated()
override {
return input; }
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 <<
" + "; }
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 <<
" - "; }
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; }
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; }
560 for (
int i =
topLevel->getNumInputs(); --i >= 0;)
571 static Constant* findTermToAdjust (Term*
const term,
const bool mustBeFlagged)
579 if (term->getType() == constantType)
581 Constant*
const c =
static_cast<Constant*
> (term);
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);
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';
703 bool readOperator (
const char*
ops,
char*
const opType =
nullptr)
noexcept
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();
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];
1138 v =
jmin (v, parameters[i]);
1143 if (functionName ==
"max")
1145 double v = parameters[0];
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.
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.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
Represents a symbol that is used in an Expression.