2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../core/juce_StandardHeader.h"
30 #include "juce_Expression.h"
31 #include "../memory/juce_HeapBlock.h"
34 //==============================================================================
35 class Expression::Term
: public SingleThreadedReferenceCountedObject
41 virtual Type
getType() const noexcept
= 0;
42 virtual Term
* clone() const = 0;
43 virtual ReferenceCountedObjectPtr
<Term
> resolve (const Scope
&, int recursionDepth
) = 0;
44 virtual String
toString() const = 0;
45 virtual double toDouble() const { return 0; }
46 virtual int getInputIndexFor (const Term
*) const { return -1; }
47 virtual int getOperatorPrecedence() const { return 0; }
48 virtual int getNumInputs() const { return 0; }
49 virtual Term
* getInput (int) const { return nullptr; }
50 virtual ReferenceCountedObjectPtr
<Term
> negated();
52 virtual ReferenceCountedObjectPtr
<Term
> createTermToEvaluateInput (const Scope
&, const Term
* /*inputTerm*/,
53 double /*overallTarget*/, Term
* /*topLevelTerm*/) const
59 virtual String
getName() const
61 jassertfalse
; // You shouldn't call this for an expression that's not actually a function!
65 virtual void renameSymbol (const Symbol
& oldSymbol
, const String
& newName
, const Scope
& scope
, int recursionDepth
)
67 for (int i
= getNumInputs(); --i
>= 0;)
68 getInput (i
)->renameSymbol (oldSymbol
, newName
, scope
, recursionDepth
);
74 virtual ~SymbolVisitor() {}
75 virtual void useSymbol (const Symbol
&) = 0;
78 virtual void visitAllSymbols (SymbolVisitor
& visitor
, const Scope
& scope
, int recursionDepth
)
80 for (int i
= getNumInputs(); --i
>= 0;)
81 getInput(i
)->visitAllSymbols (visitor
, scope
, recursionDepth
);
85 JUCE_DECLARE_NON_COPYABLE (Term
);
89 //==============================================================================
90 class Expression::Helpers
93 typedef ReferenceCountedObjectPtr
<Term
> TermPtr
;
95 // This helper function is needed to work around VC6 scoping bugs
96 static inline const TermPtr
& getTermFor (const Expression
& exp
) noexcept
{ return exp
.term
; }
98 static void checkRecursionDepth (const int depth
)
101 throw EvaluationError ("Recursive symbol references");
104 friend class Expression::Term
; // (also only needed as a VC6 workaround)
106 //==============================================================================
107 /** An exception that can be thrown by Expression::evaluate(). */
108 class EvaluationError
: public std::exception
111 EvaluationError (const String
& description_
)
112 : description (description_
)
114 DBG ("Expression::EvaluationError: " + description
);
120 //==============================================================================
121 class Constant
: public Term
124 Constant (const double value_
, const bool isResolutionTarget_
)
125 : value (value_
), isResolutionTarget (isResolutionTarget_
) {}
127 Type
getType() const noexcept
{ return constantType
; }
128 Term
* clone() const { return new Constant (value
, isResolutionTarget
); }
129 TermPtr
resolve (const Scope
&, int) { return this; }
130 double toDouble() const { return value
; }
131 TermPtr
negated() { return new Constant (-value
, isResolutionTarget
); }
133 String
toString() const
136 if (isResolutionTarget
)
143 bool isResolutionTarget
;
146 //==============================================================================
147 class BinaryTerm
: public Term
150 BinaryTerm (Term
* const left_
, Term
* const right_
) : left (left_
), right (right_
)
152 jassert (left_
!= nullptr && right_
!= nullptr);
155 int getInputIndexFor (const Term
* possibleInput
) const
157 return possibleInput
== left
? 0 : (possibleInput
== right
? 1 : -1);
160 Type
getType() const noexcept
{ return operatorType
; }
161 int getNumInputs() const { return 2; }
162 Term
* getInput (int index
) const { return index
== 0 ? left
.getObject() : (index
== 1 ? right
.getObject() : 0); }
164 virtual double performFunction (double left
, double right
) const = 0;
165 virtual void writeOperator (String
& dest
) const = 0;
167 TermPtr
resolve (const Scope
& scope
, int recursionDepth
)
169 return new Constant (performFunction (left
->resolve (scope
, recursionDepth
)->toDouble(),
170 right
->resolve (scope
, recursionDepth
)->toDouble()), false);
173 String
toString() const
177 const int ourPrecendence
= getOperatorPrecedence();
178 if (left
->getOperatorPrecedence() > ourPrecendence
)
179 s
<< '(' << left
->toString() << ')';
181 s
= left
->toString();
185 if (right
->getOperatorPrecedence() >= ourPrecendence
)
186 s
<< '(' << right
->toString() << ')';
188 s
<< right
->toString();
194 const TermPtr left
, right
;
196 TermPtr
createDestinationTerm (const Scope
& scope
, const Term
* input
, double overallTarget
, Term
* topLevelTerm
) const
198 jassert (input
== left
|| input
== right
);
199 if (input
!= left
&& input
!= right
)
202 const Term
* const dest
= findDestinationFor (topLevelTerm
, this);
205 return new Constant (overallTarget
, false);
207 return dest
->createTermToEvaluateInput (scope
, this, overallTarget
, topLevelTerm
);
211 //==============================================================================
212 class SymbolTerm
: public Term
215 explicit SymbolTerm (const String
& symbol_
) : symbol (symbol_
) {}
217 TermPtr
resolve (const Scope
& scope
, int recursionDepth
)
219 checkRecursionDepth (recursionDepth
);
220 return getTermFor (scope
.getSymbolValue (symbol
))->resolve (scope
, recursionDepth
+ 1);
223 Type
getType() const noexcept
{ return symbolType
; }
224 Term
* clone() const { return new SymbolTerm (symbol
); }
225 String
toString() const { return symbol
; }
226 String
getName() const { return symbol
; }
228 void visitAllSymbols (SymbolVisitor
& visitor
, const Scope
& scope
, int recursionDepth
)
230 checkRecursionDepth (recursionDepth
);
231 visitor
.useSymbol (Symbol (scope
.getScopeUID(), symbol
));
232 getTermFor (scope
.getSymbolValue (symbol
))->visitAllSymbols (visitor
, scope
, recursionDepth
+ 1);
235 void renameSymbol (const Symbol
& oldSymbol
, const String
& newName
, const Scope
& scope
, int /*recursionDepth*/)
237 if (oldSymbol
.symbolName
== symbol
&& scope
.getScopeUID() == oldSymbol
.scopeUID
)
244 //==============================================================================
245 class Function
: public Term
248 explicit Function (const String
& functionName_
) : functionName (functionName_
) {}
250 Function (const String
& functionName_
, const Array
<Expression
>& parameters_
)
251 : functionName (functionName_
), parameters (parameters_
)
254 Type
getType() const noexcept
{ return functionType
; }
255 Term
* clone() const { return new Function (functionName
, parameters
); }
256 int getNumInputs() const { return parameters
.size(); }
257 Term
* getInput (int i
) const { return getTermFor (parameters
[i
]); }
258 String
getName() const { return functionName
; }
260 TermPtr
resolve (const Scope
& scope
, int recursionDepth
)
262 checkRecursionDepth (recursionDepth
);
264 const int numParams
= parameters
.size();
267 HeapBlock
<double> params (numParams
);
268 for (int i
= 0; i
< numParams
; ++i
)
269 params
[i
] = getTermFor (parameters
.getReference(i
))->resolve (scope
, recursionDepth
+ 1)->toDouble();
271 result
= scope
.evaluateFunction (functionName
, params
, numParams
);
275 result
= scope
.evaluateFunction (functionName
, nullptr, 0);
278 return new Constant (result
, false);
281 int getInputIndexFor (const Term
* possibleInput
) const
283 for (int i
= 0; i
< parameters
.size(); ++i
)
284 if (getTermFor (parameters
.getReference(i
)) == possibleInput
)
290 String
toString() const
292 if (parameters
.size() == 0)
293 return functionName
+ "()";
295 String
s (functionName
+ " (");
297 for (int i
= 0; i
< parameters
.size(); ++i
)
299 s
<< getTermFor (parameters
.getReference(i
))->toString();
301 if (i
< parameters
.size() - 1)
309 const String functionName
;
310 Array
<Expression
> parameters
;
313 //==============================================================================
314 class DotOperator
: public BinaryTerm
317 DotOperator (SymbolTerm
* const left_
, Term
* const right_
) : BinaryTerm (left_
, right_
) {}
319 TermPtr
resolve (const Scope
& scope
, int recursionDepth
)
321 checkRecursionDepth (recursionDepth
);
323 EvaluationVisitor
visitor (right
, recursionDepth
+ 1);
324 scope
.visitRelativeScope (getSymbol()->symbol
, visitor
);
325 return visitor
.output
;
328 Term
* clone() const { return new DotOperator (getSymbol(), right
); }
329 String
getName() const { return "."; }
330 int getOperatorPrecedence() const { return 1; }
331 void writeOperator (String
& dest
) const { dest
<< '.'; }
332 double performFunction (double, double) const { return 0.0; }
334 void visitAllSymbols (SymbolVisitor
& visitor
, const Scope
& scope
, int recursionDepth
)
336 checkRecursionDepth (recursionDepth
);
337 visitor
.useSymbol (Symbol (scope
.getScopeUID(), getSymbol()->symbol
));
339 SymbolVisitingVisitor
v (right
, visitor
, recursionDepth
+ 1);
343 scope
.visitRelativeScope (getSymbol()->symbol
, v
);
348 void renameSymbol (const Symbol
& oldSymbol
, const String
& newName
, const Scope
& scope
, int recursionDepth
)
350 checkRecursionDepth (recursionDepth
);
351 getSymbol()->renameSymbol (oldSymbol
, newName
, scope
, recursionDepth
);
353 SymbolRenamingVisitor
visitor (right
, oldSymbol
, newName
, recursionDepth
+ 1);
357 scope
.visitRelativeScope (getSymbol()->symbol
, visitor
);
363 //==============================================================================
364 class EvaluationVisitor
: public Scope::Visitor
367 EvaluationVisitor (const TermPtr
& input_
, const int recursionCount_
)
368 : input (input_
), output (input_
), recursionCount (recursionCount_
) {}
370 void visit (const Scope
& scope
) { output
= input
->resolve (scope
, recursionCount
); }
374 const int recursionCount
;
377 JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor
);
380 class SymbolVisitingVisitor
: public Scope::Visitor
383 SymbolVisitingVisitor (const TermPtr
& input_
, SymbolVisitor
& visitor_
, const int recursionCount_
)
384 : input (input_
), visitor (visitor_
), recursionCount (recursionCount_
) {}
386 void visit (const Scope
& scope
) { input
->visitAllSymbols (visitor
, scope
, recursionCount
); }
390 SymbolVisitor
& visitor
;
391 const int recursionCount
;
393 JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor
);
396 class SymbolRenamingVisitor
: public Scope::Visitor
399 SymbolRenamingVisitor (const TermPtr
& input_
, const Expression::Symbol
& symbol_
, const String
& newName_
, const int recursionCount_
)
400 : input (input_
), symbol (symbol_
), newName (newName_
), recursionCount (recursionCount_
) {}
402 void visit (const Scope
& scope
) { input
->renameSymbol (symbol
, newName
, scope
, recursionCount
); }
406 const Symbol
& symbol
;
407 const String newName
;
408 const int recursionCount
;
410 JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor
);
413 SymbolTerm
* getSymbol() const { return static_cast <SymbolTerm
*> (left
.getObject()); }
415 JUCE_DECLARE_NON_COPYABLE (DotOperator
);
418 //==============================================================================
419 class Negate
: public Term
422 explicit Negate (const TermPtr
& input_
) : input (input_
)
424 jassert (input_
!= nullptr);
427 Type
getType() const noexcept
{ return operatorType
; }
428 int getInputIndexFor (const Term
* possibleInput
) const { return possibleInput
== input
? 0 : -1; }
429 int getNumInputs() const { return 1; }
430 Term
* getInput (int index
) const { return index
== 0 ? input
.getObject() : nullptr; }
431 Term
* clone() const { return new Negate (input
->clone()); }
433 TermPtr
resolve (const Scope
& scope
, int recursionDepth
)
435 return new Constant (-input
->resolve (scope
, recursionDepth
)->toDouble(), false);
438 String
getName() const { return "-"; }
439 TermPtr
negated() { return input
; }
441 TermPtr
createTermToEvaluateInput (const Scope
& scope
, const Term
* input_
, double overallTarget
, Term
* topLevelTerm
) const
444 jassert (input_
== input
);
446 const Term
* const dest
= findDestinationFor (topLevelTerm
, this);
448 return new Negate (dest
== nullptr ? new Constant (overallTarget
, false)
449 : dest
->createTermToEvaluateInput (scope
, this, overallTarget
, topLevelTerm
));
452 String
toString() const
454 if (input
->getOperatorPrecedence() > 0)
455 return "-(" + input
->toString() + ")";
457 return "-" + input
->toString();
464 //==============================================================================
465 class Add
: public BinaryTerm
468 Add (Term
* const left_
, Term
* const right_
) : BinaryTerm (left_
, right_
) {}
470 Term
* clone() const { return new Add (left
->clone(), right
->clone()); }
471 double performFunction (double lhs
, double rhs
) const { return lhs
+ rhs
; }
472 int getOperatorPrecedence() const { return 3; }
473 String
getName() const { return "+"; }
474 void writeOperator (String
& dest
) const { dest
<< " + "; }
476 TermPtr
createTermToEvaluateInput (const Scope
& scope
, const Term
* input
, double overallTarget
, Term
* topLevelTerm
) const
478 const TermPtr
newDest (createDestinationTerm (scope
, input
, overallTarget
, topLevelTerm
));
479 if (newDest
== nullptr)
482 return new Subtract (newDest
, (input
== left
? right
: left
)->clone());
486 JUCE_DECLARE_NON_COPYABLE (Add
);
489 //==============================================================================
490 class Subtract
: public BinaryTerm
493 Subtract (Term
* const left_
, Term
* const right_
) : BinaryTerm (left_
, right_
) {}
495 Term
* clone() const { return new Subtract (left
->clone(), right
->clone()); }
496 double performFunction (double lhs
, double rhs
) const { return lhs
- rhs
; }
497 int getOperatorPrecedence() const { return 3; }
498 String
getName() const { return "-"; }
499 void writeOperator (String
& dest
) const { dest
<< " - "; }
501 TermPtr
createTermToEvaluateInput (const Scope
& scope
, const Term
* input
, double overallTarget
, Term
* topLevelTerm
) const
503 const TermPtr
newDest (createDestinationTerm (scope
, input
, overallTarget
, topLevelTerm
));
504 if (newDest
== nullptr)
508 return new Add (newDest
, right
->clone());
510 return new Subtract (left
->clone(), newDest
);
514 JUCE_DECLARE_NON_COPYABLE (Subtract
);
517 //==============================================================================
518 class Multiply
: public BinaryTerm
521 Multiply (Term
* const left_
, Term
* const right_
) : BinaryTerm (left_
, right_
) {}
523 Term
* clone() const { return new Multiply (left
->clone(), right
->clone()); }
524 double performFunction (double lhs
, double rhs
) const { return lhs
* rhs
; }
525 String
getName() const { return "*"; }
526 void writeOperator (String
& dest
) const { dest
<< " * "; }
527 int getOperatorPrecedence() const { return 2; }
529 TermPtr
createTermToEvaluateInput (const Scope
& scope
, const Term
* input
, double overallTarget
, Term
* topLevelTerm
) const
531 const TermPtr
newDest (createDestinationTerm (scope
, input
, overallTarget
, topLevelTerm
));
532 if (newDest
== nullptr)
535 return new Divide (newDest
, (input
== left
? right
: left
)->clone());
539 JUCE_DECLARE_NON_COPYABLE (Multiply
);
542 //==============================================================================
543 class Divide
: public BinaryTerm
546 Divide (Term
* const left_
, Term
* const right_
) : BinaryTerm (left_
, right_
) {}
548 Term
* clone() const { return new Divide (left
->clone(), right
->clone()); }
549 double performFunction (double lhs
, double rhs
) const { return lhs
/ rhs
; }
550 String
getName() const { return "/"; }
551 void writeOperator (String
& dest
) const { dest
<< " / "; }
552 int getOperatorPrecedence() const { return 2; }
554 TermPtr
createTermToEvaluateInput (const Scope
& scope
, const Term
* input
, double overallTarget
, Term
* topLevelTerm
) const
556 const TermPtr
newDest (createDestinationTerm (scope
, input
, overallTarget
, topLevelTerm
));
557 if (newDest
== nullptr)
561 return new Multiply (newDest
, right
->clone());
563 return new Divide (left
->clone(), newDest
);
567 JUCE_DECLARE_NON_COPYABLE (Divide
);
570 //==============================================================================
571 static Term
* findDestinationFor (Term
* const topLevel
, const Term
* const inputTerm
)
573 const int inputIndex
= topLevel
->getInputIndexFor (inputTerm
);
577 for (int i
= topLevel
->getNumInputs(); --i
>= 0;)
579 Term
* const t
= findDestinationFor (topLevel
->getInput (i
), inputTerm
);
588 static Constant
* findTermToAdjust (Term
* const term
, const bool mustBeFlagged
)
591 Constant
* const c
= dynamic_cast<Constant
*> (term
);
592 if (c
!= nullptr && (c
->isResolutionTarget
|| ! mustBeFlagged
))
596 if (dynamic_cast<Function
*> (term
) != nullptr)
600 const int numIns
= term
->getNumInputs();
601 for (i
= 0; i
< numIns
; ++i
)
603 Constant
* const c
= dynamic_cast<Constant
*> (term
->getInput (i
));
604 if (c
!= nullptr && (c
->isResolutionTarget
|| ! mustBeFlagged
))
608 for (i
= 0; i
< numIns
; ++i
)
610 Constant
* const c
= findTermToAdjust (term
->getInput (i
), mustBeFlagged
);
618 static bool containsAnySymbols (const Term
* const t
)
620 if (t
->getType() == Expression::symbolType
)
623 for (int i
= t
->getNumInputs(); --i
>= 0;)
624 if (containsAnySymbols (t
->getInput (i
)))
630 //==============================================================================
631 class SymbolCheckVisitor
: public Term::SymbolVisitor
634 SymbolCheckVisitor (const Symbol
& symbol_
) : wasFound (false), symbol (symbol_
) {}
635 void useSymbol (const Symbol
& s
) { wasFound
= wasFound
|| s
== symbol
; }
640 const Symbol
& symbol
;
642 JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor
);
645 //==============================================================================
646 class SymbolListVisitor
: public Term::SymbolVisitor
649 SymbolListVisitor (Array
<Symbol
>& list_
) : list (list_
) {}
650 void useSymbol (const Symbol
& s
) { list
.addIfNotAlreadyThere (s
); }
655 JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor
);
658 //==============================================================================
662 //==============================================================================
663 Parser (String::CharPointerType
& stringToParse
)
664 : text (stringToParse
)
668 TermPtr
readUpToComma()
671 return new Constant (0.0, false);
673 const TermPtr
e (readExpression());
675 if (e
== nullptr || ((! readOperator (",")) && ! text
.isEmpty()))
676 throw ParseError ("Syntax error: \"" + String (text
) + "\"");
682 String::CharPointerType
& text
;
684 //==============================================================================
685 static inline bool isDecimalDigit (const juce_wchar c
) noexcept
687 return c
>= '0' && c
<= '9';
690 bool readChar (const juce_wchar required
) noexcept
692 if (*text
== required
)
701 bool readOperator (const char* ops
, char* const opType
= nullptr) noexcept
703 text
= text
.findEndOfWhitespace();
709 if (opType
!= nullptr)
721 bool readIdentifier (String
& identifier
) noexcept
723 text
= text
.findEndOfWhitespace();
724 String::CharPointerType
t (text
);
727 if (t
.isLetter() || *t
== '_')
732 while (t
.isLetterOrDigit() || *t
== '_')
741 identifier
= String (text
, numChars
);
749 Term
* readNumber() noexcept
751 text
= text
.findEndOfWhitespace();
752 String::CharPointerType
t (text
);
754 const bool isResolutionTarget
= (*t
== '@');
755 if (isResolutionTarget
)
758 t
= t
.findEndOfWhitespace();
765 t
= t
.findEndOfWhitespace();
768 if (isDecimalDigit (*t
) || (*t
== '.' && isDecimalDigit (t
[1])))
769 return new Constant (CharacterFunctions::readDoubleValue (text
), isResolutionTarget
);
774 TermPtr
readExpression()
776 TermPtr
lhs (readMultiplyOrDivideExpression());
779 while (lhs
!= nullptr && readOperator ("+-", &opType
))
781 TermPtr
rhs (readMultiplyOrDivideExpression());
784 throw ParseError ("Expected expression after \"" + String::charToString (opType
) + "\"");
787 lhs
= new Add (lhs
, rhs
);
789 lhs
= new Subtract (lhs
, rhs
);
795 TermPtr
readMultiplyOrDivideExpression()
797 TermPtr
lhs (readUnaryExpression());
800 while (lhs
!= nullptr && readOperator ("*/", &opType
))
802 TermPtr
rhs (readUnaryExpression());
805 throw ParseError ("Expected expression after \"" + String::charToString (opType
) + "\"");
808 lhs
= new Multiply (lhs
, rhs
);
810 lhs
= new Divide (lhs
, rhs
);
816 TermPtr
readUnaryExpression()
819 if (readOperator ("+-", &opType
))
821 TermPtr
term (readUnaryExpression());
824 throw ParseError ("Expected expression after \"" + String::charToString (opType
) + "\"");
827 term
= term
->negated();
832 return readPrimaryExpression();
835 TermPtr
readPrimaryExpression()
837 TermPtr
e (readParenthesisedExpression());
845 return readSymbolOrFunction();
848 TermPtr
readSymbolOrFunction()
851 if (readIdentifier (identifier
))
853 if (readOperator ("(")) // method call...
855 Function
* const f
= new Function (identifier
);
856 ScopedPointer
<Term
> func (f
); // (can't use ScopedPointer<Function> in MSVC)
858 TermPtr
param (readExpression());
860 if (param
== nullptr)
862 if (readOperator (")"))
863 return func
.release();
865 throw ParseError ("Expected parameters after \"" + identifier
+ " (\"");
868 f
->parameters
.add (Expression (param
));
870 while (readOperator (","))
872 param
= readExpression();
874 if (param
== nullptr)
875 throw ParseError ("Expected expression after \",\"");
877 f
->parameters
.add (Expression (param
));
880 if (readOperator (")"))
881 return func
.release();
883 throw ParseError ("Expected \")\"");
885 else if (readOperator ("."))
887 TermPtr
rhs (readSymbolOrFunction());
890 throw ParseError ("Expected symbol or function after \".\"");
892 if (identifier
== "this")
895 return new DotOperator (new SymbolTerm (identifier
), rhs
);
897 else // just a symbol..
899 jassert (identifier
.trim() == identifier
);
900 return new SymbolTerm (identifier
);
907 TermPtr
readParenthesisedExpression()
909 if (! readOperator ("("))
912 const TermPtr
e (readExpression());
913 if (e
== nullptr || ! readOperator (")"))
919 JUCE_DECLARE_NON_COPYABLE (Parser
);
923 //==============================================================================
924 Expression::Expression()
925 : term (new Expression::Helpers::Constant (0, false))
929 Expression::~Expression()
933 Expression::Expression (Term
* const term_
)
936 jassert (term
!= nullptr);
939 Expression::Expression (const double constant
)
940 : term (new Expression::Helpers::Constant (constant
, false))
944 Expression::Expression (const Expression
& other
)
949 Expression
& Expression::operator= (const Expression
& other
)
955 Expression::Expression (const String
& stringToParse
)
957 String::CharPointerType
text (stringToParse
.getCharPointer());
958 Helpers::Parser
parser (text
);
959 term
= parser
.readUpToComma();
962 Expression
Expression::parse (String::CharPointerType
& stringToParse
)
964 Helpers::Parser
parser (stringToParse
);
965 return Expression (parser
.readUpToComma());
968 double Expression::evaluate() const
970 return evaluate (Expression::Scope());
973 double Expression::evaluate (const Expression::Scope
& scope
) const
977 return term
->resolve (scope
, 0)->toDouble();
979 catch (Helpers::EvaluationError
&)
985 double Expression::evaluate (const Scope
& scope
, String
& evaluationError
) const
989 return term
->resolve (scope
, 0)->toDouble();
991 catch (Helpers::EvaluationError
& e
)
993 evaluationError
= e
.description
;
999 Expression
Expression::operator+ (const Expression
& other
) const { return Expression (new Helpers::Add (term
, other
.term
)); }
1000 Expression
Expression::operator- (const Expression
& other
) const { return Expression (new Helpers::Subtract (term
, other
.term
)); }
1001 Expression
Expression::operator* (const Expression
& other
) const { return Expression (new Helpers::Multiply (term
, other
.term
)); }
1002 Expression
Expression::operator/ (const Expression
& other
) const { return Expression (new Helpers::Divide (term
, other
.term
)); }
1003 Expression
Expression::operator-() const { return Expression (term
->negated()); }
1004 Expression
Expression::symbol (const String
& symbol
) { return Expression (new Helpers::SymbolTerm (symbol
)); }
1006 Expression
Expression::function (const String
& functionName
, const Array
<Expression
>& parameters
)
1008 return Expression (new Helpers::Function (functionName
, parameters
));
1011 Expression
Expression::adjustedToGiveNewResult (const double targetValue
, const Expression::Scope
& scope
) const
1013 ScopedPointer
<Term
> newTerm (term
->clone());
1015 Helpers::Constant
* termToAdjust
= Helpers::findTermToAdjust (newTerm
, true);
1017 if (termToAdjust
== nullptr)
1018 termToAdjust
= Helpers::findTermToAdjust (newTerm
, false);
1020 if (termToAdjust
== nullptr)
1022 newTerm
= new Helpers::Add (newTerm
.release(), new Helpers::Constant (0, false));
1023 termToAdjust
= Helpers::findTermToAdjust (newTerm
, false);
1026 jassert (termToAdjust
!= nullptr);
1028 const Term
* const parent
= Helpers::findDestinationFor (newTerm
, termToAdjust
);
1030 if (parent
== nullptr)
1032 termToAdjust
->value
= targetValue
;
1036 const Helpers::TermPtr
reverseTerm (parent
->createTermToEvaluateInput (scope
, termToAdjust
, targetValue
, newTerm
));
1038 if (reverseTerm
== nullptr)
1039 return Expression (targetValue
);
1041 termToAdjust
->value
= reverseTerm
->resolve (scope
, 0)->toDouble();
1044 return Expression (newTerm
.release());
1047 Expression
Expression::withRenamedSymbol (const Expression::Symbol
& oldSymbol
, const String
& newName
, const Scope
& scope
) const
1049 jassert (newName
.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
1051 if (oldSymbol
.symbolName
== newName
)
1054 Expression
e (term
->clone());
1055 e
.term
->renameSymbol (oldSymbol
, newName
, scope
, 0);
1059 bool Expression::referencesSymbol (const Expression::Symbol
& symbolToCheck
, const Scope
& scope
) const
1061 Helpers::SymbolCheckVisitor
visitor (symbolToCheck
);
1065 term
->visitAllSymbols (visitor
, scope
, 0);
1067 catch (Helpers::EvaluationError
&)
1070 return visitor
.wasFound
;
1073 void Expression::findReferencedSymbols (Array
<Symbol
>& results
, const Scope
& scope
) const
1077 Helpers::SymbolListVisitor
visitor (results
);
1078 term
->visitAllSymbols (visitor
, scope
, 0);
1080 catch (Helpers::EvaluationError
&)
1084 String
Expression::toString() const { return term
->toString(); }
1085 bool Expression::usesAnySymbols() const { return Helpers::containsAnySymbols (term
); }
1086 Expression::Type
Expression::getType() const noexcept
{ return term
->getType(); }
1087 String
Expression::getSymbolOrFunction() const { return term
->getName(); }
1088 int Expression::getNumInputs() const { return term
->getNumInputs(); }
1089 Expression
Expression::getInput (int index
) const { return Expression (term
->getInput (index
)); }
1091 //==============================================================================
1092 ReferenceCountedObjectPtr
<Expression::Term
> Expression::Term::negated()
1094 return new Helpers::Negate (this);
1097 //==============================================================================
1098 Expression::ParseError::ParseError (const String
& message
)
1099 : description (message
)
1101 DBG ("Expression::ParseError: " + message
);
1104 //==============================================================================
1105 Expression::Symbol::Symbol (const String
& scopeUID_
, const String
& symbolName_
)
1106 : scopeUID (scopeUID_
), symbolName (symbolName_
)
1110 bool Expression::Symbol::operator== (const Symbol
& other
) const noexcept
1112 return symbolName
== other
.symbolName
&& scopeUID
== other
.scopeUID
;
1115 bool Expression::Symbol::operator!= (const Symbol
& other
) const noexcept
1117 return ! operator== (other
);
1120 //==============================================================================
1121 Expression::Scope::Scope() {}
1122 Expression::Scope::~Scope() {}
1124 Expression
Expression::Scope::getSymbolValue (const String
& symbol
) const
1126 throw Helpers::EvaluationError ("Unknown symbol: " + symbol
);
1129 double Expression::Scope::evaluateFunction (const String
& functionName
, const double* parameters
, int numParams
) const
1133 if (functionName
== "min")
1135 double v
= parameters
[0];
1136 for (int i
= 1; i
< numParams
; ++i
)
1137 v
= jmin (v
, parameters
[i
]);
1141 else if (functionName
== "max")
1143 double v
= parameters
[0];
1144 for (int i
= 1; i
< numParams
; ++i
)
1145 v
= jmax (v
, parameters
[i
]);
1149 else if (numParams
== 1)
1151 if (functionName
== "sin") return sin (parameters
[0]);
1152 else if (functionName
== "cos") return cos (parameters
[0]);
1153 else if (functionName
== "tan") return tan (parameters
[0]);
1154 else if (functionName
== "abs") return std::abs (parameters
[0]);
1158 throw Helpers::EvaluationError ("Unknown function: \"" + functionName
+ "\"");
1161 void Expression::Scope::visitRelativeScope (const String
& scopeName
, Visitor
&) const
1163 throw Helpers::EvaluationError ("Unknown symbol: " + scopeName
);
1166 String
Expression::Scope::getScopeUID() const
1168 return String::empty
;