26class Expression::Term :
public SingleThreadedReferenceCountedObject
33 virtual Term* clone() const = 0;
34 virtual ReferenceCountedObjectPtr<Term> resolve (const Scope&,
int recursionDepth) = 0;
36 virtual
double toDouble()
const {
return 0; }
37 virtual int getInputIndexFor (
const Term*)
const {
return -1; }
38 virtual int getOperatorPrecedence()
const {
return 0; }
40 virtual Term*
getInput (
int)
const {
return nullptr; }
41 virtual ReferenceCountedObjectPtr<Term> negated();
43 virtual ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (
const Scope&,
const Term* ,
44 double , Term* )
const
47 return ReferenceCountedObjectPtr<Term>();
50 virtual String getName()
const
56 virtual void renameSymbol (
const Symbol& oldSymbol,
const String& newName,
const Scope& scope,
int recursionDepth)
59 getInput (i)->renameSymbol (oldSymbol, newName, scope, recursionDepth);
65 virtual ~SymbolVisitor() {}
66 virtual void useSymbol (
const Symbol&) = 0;
69 virtual void visitAllSymbols (SymbolVisitor& visitor,
const Scope& scope,
int recursionDepth)
72 getInput (i)->visitAllSymbols (visitor, scope, recursionDepth);
76 JUCE_DECLARE_NON_COPYABLE (Term)
81struct Expression::Helpers
83 using TermPtr = ReferenceCountedObjectPtr<Term>;
85 static void checkRecursionDepth (
int depth)
88 throw EvaluationError (
"Recursive symbol references");
91 friend class Expression::Term;
100 DBG (
"Expression::EvaluationError: " + description);
107 class Constant final :
public Term
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); }
122 if (isResolutionTarget)
129 bool isResolutionTarget;
133 class BinaryTerm :
public Term
136 BinaryTerm (TermPtr l, TermPtr r) : left (std::move (l)), right (std::move (r))
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; }
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);
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();
180 const TermPtr left, right;
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);
196 class SymbolTerm final :
public Term
199 explicit SymbolTerm (
const String& sym) :
symbol (sym) {}
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; }
208 Term* clone()
const override {
return new SymbolTerm (
symbol); }
210 String getName()
const override {
return symbol; }
212 void visitAllSymbols (SymbolVisitor& visitor,
const Scope& scope,
int recursionDepth)
override
214 checkRecursionDepth (recursionDepth);
215 visitor.useSymbol (Symbol (scope.getScopeUID(),
symbol));
216 scope.getSymbolValue (
symbol).term->visitAllSymbols (visitor, scope, recursionDepth + 1);
219 void renameSymbol (
const Symbol& oldSymbol,
const String& newName,
const Scope& scope,
int )
override
221 if (oldSymbol.symbolName ==
symbol && scope.getScopeUID() == oldSymbol.scopeUID)
229 class Function final :
public Term
232 explicit Function (
const String& name) : functionName (name) {}
234 Function (
const String& name,
const Array<Expression>& params)
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();
252 HeapBlock<double> params (numParams);
254 for (
int i = 0; i < numParams; ++i)
255 params[i] = parameters.getReference (i).term->resolve (scope, recursionDepth + 1)->toDouble();
257 result = scope.evaluateFunction (functionName, params, numParams);
261 result = scope.evaluateFunction (functionName,
nullptr, 0);
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)
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;
296 Array<Expression> parameters;
300 class DotOperator final :
public BinaryTerm
303 DotOperator (SymbolTerm* l, TermPtr r) : BinaryTerm (TermPtr (l), r) {}
305 TermPtr resolve (
const Scope& scope,
int recursionDepth)
override
307 checkRecursionDepth (recursionDepth);
309 EvaluationVisitor visitor (right, recursionDepth + 1);
310 scope.visitRelativeScope (getSymbol()->
symbol, visitor);
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);
323 visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->
symbol));
325 SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);
329 scope.visitRelativeScope (getSymbol()->
symbol, v);
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);
343 scope.visitRelativeScope (getSymbol()->
symbol, visitor);
350 class EvaluationVisitor final :
public Scope::Visitor
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;
363 JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor)
366 class SymbolVisitingVisitor final :
public Scope::Visitor
369 SymbolVisitingVisitor (
const TermPtr& t, SymbolVisitor& v,
const int recursion)
370 : input (t), visitor (v), recursionCount (recursion) {}
372 void visit (
const Scope& scope)
override { input->visitAllSymbols (visitor, scope, recursionCount); }
376 SymbolVisitor& visitor;
377 const int recursionCount;
379 JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor)
382 class SymbolRenamingVisitor final :
public Scope::Visitor
385 SymbolRenamingVisitor (
const TermPtr& t,
const Expression::Symbol& symbol_,
const String& newName_,
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); }
393 const String newName;
394 const int recursionCount;
396 JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor)
399 SymbolTerm* getSymbol()
const {
return static_cast<SymbolTerm*
> (left.get()); }
401 JUCE_DECLARE_NON_COPYABLE (DotOperator)
405 class Negate final :
public Term
408 explicit Negate (
const TermPtr& t) : input (t)
410 jassert (t !=
nullptr);
413 Type getType() const noexcept
override {
return operatorType; }
414 int getInputIndexFor (
const Term* possibleInput)
const override {
return possibleInput == input ? 0 : -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
429 jassert (t == input);
431 const Term*
const dest = findDestinationFor (topLevelTerm,
this);
433 return *
new Negate (dest ==
nullptr ? TermPtr (*
new Constant (overallTarget,
false))
434 : dest->createTermToEvaluateInput (scope,
this, overallTarget, topLevelTerm));
439 if (input->getOperatorPrecedence() > 0)
440 return "-(" + input->toString() +
")";
442 return "-" + input->toString();
450 class Add final :
public BinaryTerm
453 Add (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
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());
470 JUCE_DECLARE_NON_COPYABLE (Add)
474 class Subtract final :
public BinaryTerm
477 Subtract (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
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);
499 JUCE_DECLARE_NON_COPYABLE (Subtract)
503 class Multiply final :
public BinaryTerm
506 Multiply (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
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());
522 JUCE_DECLARE_NON_COPYABLE (Multiply)
526 class Divide final :
public BinaryTerm
529 Divide (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
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);
550 JUCE_DECLARE_NON_COPYABLE (Divide)
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)))
624 class SymbolCheckVisitor final :
public Term::SymbolVisitor
627 SymbolCheckVisitor (
const Symbol& s) :
symbol (s) {}
628 void useSymbol (
const Symbol& s)
override { wasFound = wasFound || s ==
symbol; }
630 bool wasFound =
false;
635 JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor)
639 class SymbolListVisitor final :
public Term::SymbolVisitor
642 SymbolListVisitor (Array<Symbol>& list_) : list (list_) {}
643 void useSymbol (
const Symbol& s)
override { list.addIfNotAlreadyThere (s); }
648 JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor)
656 Parser (String::CharPointerType& stringToParse) : text (stringToParse)
660 TermPtr readUpToComma()
663 return *
new Constant (0.0,
false);
665 auto e = readExpression();
667 if (e ==
nullptr || ((! readOperator (
",")) && ! text.isEmpty()))
668 return parseError (
"Syntax error: \"" + String (text) +
"\"");
676 String::CharPointerType& text;
678 TermPtr parseError (
const String& message)
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
705 text.incrementToEndOfWhitespace();
709 if (readChar ((juce_wchar) (uint8) *ops))
711 if (opType !=
nullptr)
723 bool readIdentifier (String& identifier)
noexcept
725 text.incrementToEndOfWhitespace();
729 if (t.isLetter() || *t ==
'_')
734 while (t.isLetterOrDigit() || *t ==
'_')
743 identifier = String (text, (
size_t) numChars);
751 Term* readNumber() noexcept
753 text.incrementToEndOfWhitespace();
755 bool isResolutionTarget = (*t ==
'@');
757 if (isResolutionTarget)
760 t.incrementToEndOfWhitespace();
767 t.incrementToEndOfWhitespace();
770 if (isDecimalDigit (*t) || (*t ==
'.' && isDecimalDigit (t[1])))
776 TermPtr readExpression()
778 auto lhs = readMultiplyOrDivideExpression();
781 while (lhs !=
nullptr && readOperator (
"+-", &opType))
783 auto rhs = readMultiplyOrDivideExpression();
786 return parseError (
"Expected expression after \"" +
String::charToString ((juce_wchar) (uint8) opType) +
"\"");
789 lhs = *
new Add (lhs, rhs);
791 lhs = *
new Subtract (lhs, rhs);
797 TermPtr readMultiplyOrDivideExpression()
799 auto lhs = readUnaryExpression();
802 while (lhs !=
nullptr && readOperator (
"*/", &opType))
804 TermPtr rhs (readUnaryExpression());
807 return parseError (
"Expected expression after \"" +
String::charToString ((juce_wchar) (uint8) opType) +
"\"");
810 lhs = *
new Multiply (lhs, rhs);
812 lhs = *
new Divide (lhs, rhs);
818 TermPtr readUnaryExpression()
821 if (readOperator (
"+-", &opType))
823 TermPtr e (readUnaryExpression());
826 return parseError (
"Expected expression after \"" +
String::charToString ((juce_wchar) (uint8) opType) +
"\"");
834 return readPrimaryExpression();
837 TermPtr readPrimaryExpression()
839 if (
auto e = readParenthesisedExpression())
842 if (
auto e = readNumber())
845 return readSymbolOrFunction();
848 TermPtr readSymbolOrFunction()
852 if (readIdentifier (identifier))
854 if (readOperator (
"("))
856 auto f =
new Function (identifier);
857 std::unique_ptr<Term> func (f);
859 auto param = readExpression();
861 if (param ==
nullptr)
863 if (readOperator (
")"))
864 return TermPtr (func.release());
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 (
")"))
882 return TermPtr (func.release());
884 return parseError (
"Expected \")\"");
887 if (readOperator (
"."))
889 TermPtr rhs (readSymbolOrFunction());
892 return parseError (
"Expected symbol or function after \".\"");
894 if (identifier ==
"this")
897 return *
new DotOperator (
new SymbolTerm (identifier), rhs);
901 jassert (identifier.trim() == identifier);
902 return *
new SymbolTerm (identifier);
908 TermPtr readParenthesisedExpression()
910 if (! readOperator (
"("))
913 auto e = readExpression();
915 if (e ==
nullptr || ! readOperator (
")"))
921 JUCE_DECLARE_NON_COPYABLE (Parser)
927 : term (new
Expression::Helpers::Constant (0, false))
937 jassert (term !=
nullptr);
941 : term (new
Expression::Helpers::Constant (constant, false))
957 : term (std::move (other.term))
963 term = std::move (other.term);
970 Helpers::Parser parser (text);
971 term = parser.readUpToComma();
972 parseError = parser.error;
977 Helpers::Parser parser (stringToParse);
979 parseError = parser.error;
998 return term->resolve (scope, 0)->toDouble();
1002 evaluationError = e.description;
1017 return Expression (
new Helpers::Function (functionName, parameters));
1022 std::unique_ptr<Term> newTerm (term->clone());
1024 auto termToAdjust = Helpers::findTermToAdjust (newTerm.get(),
true);
1026 if (termToAdjust ==
nullptr)
1027 termToAdjust = Helpers::findTermToAdjust (newTerm.get(),
false);
1029 if (termToAdjust ==
nullptr)
1031 newTerm.reset (
new Helpers::Add (*newTerm.release(), *
new Helpers::Constant (0,
false)));
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);
1066 Helpers::SymbolCheckVisitor visitor (symbolToCheck);
1070 term->visitAllSymbols (visitor, scope, 0);
1075 return visitor.wasFound;
1082 Helpers::SymbolListVisitor visitor (results);
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]);
static double readDoubleValue(CharPointerType &text) noexcept
virtual Expression getSymbolValue(const String &symbol) const
virtual void visitRelativeScope(const String &scopeName, Visitor &visitor) const
virtual String getScopeUID() const
virtual double evaluateFunction(const String &functionName, const double *parameters, int numParameters) const
Expression operator*(const Expression &) const
Expression adjustedToGiveNewResult(double targetValue, const Scope &scope) const
void findReferencedSymbols(Array< Symbol > &results, const Scope &scope) const
Expression operator+(const Expression &) const
static Expression function(const String &functionName, const Array< Expression > ¶meters)
String getSymbolOrFunction() const
bool usesAnySymbols() const
Expression withRenamedSymbol(const Symbol &oldSymbol, const String &newName, const Scope &scope) const
Expression operator/(const Expression &) const
Type getType() const noexcept
static Expression parse(String::CharPointerType &stringToParse, String &parseError)
Expression getInput(int index) const
bool referencesSymbol(const Symbol &symbol, const Scope &scope) const
static Expression symbol(const String &symbol)
Expression operator-() const
Expression & operator=(const Expression &)
ReferencedType * get() const noexcept
CharPointerType getCharPointer() const noexcept
String toLowerCase() const
static String charToString(juce_wchar character)
bool containsOnly(StringRef charactersItMightContain) const noexcept