OpenShot Audio Library | OpenShotAudio 0.3.2

Loading...
Searching...
No Matches
juce_Expression.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23 namespace juce
24{
25
26 class Expression::Term : public SingleThreadedReferenceCountedObject
27{
28 public:
29 Term() {}
30 virtual ~Term() {}
31
32 virtual Type getType() const noexcept = 0;
33 virtual Term* clone() const = 0;
34 virtual ReferenceCountedObjectPtr<Term> resolve (const Scope&, int recursionDepth) = 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; }
41 virtual ReferenceCountedObjectPtr<Term> negated();
42
43 virtual ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const Scope&, const Term* /*inputTerm*/,
44 double /*overallTarget*/, Term* /*topLevelTerm*/) const
45 {
46 jassertfalse;
47 return ReferenceCountedObjectPtr<Term>();
48 }
49
50 virtual String getName() const
51 {
52 jassertfalse; // You shouldn't call this for an expression that's not actually a function!
53 return {};
54 }
55
56 virtual void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
57 {
58 for (int i = getNumInputs(); --i >= 0;)
59 getInput (i)->renameSymbol (oldSymbol, newName, scope, recursionDepth);
60 }
61
62 class SymbolVisitor
63 {
64 public:
65 virtual ~SymbolVisitor() {}
66 virtual void useSymbol (const Symbol&) = 0;
67 };
68
69 virtual void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
70 {
71 for (int i = getNumInputs(); --i >= 0;)
72 getInput(i)->visitAllSymbols (visitor, scope, recursionDepth);
73 }
74
75 private:
76 JUCE_DECLARE_NON_COPYABLE (Term)
77};
78
79
80//==============================================================================
81 struct Expression::Helpers
82{
83 using TermPtr = ReferenceCountedObjectPtr<Term>;
84
85 static void checkRecursionDepth (int depth)
86 {
87 if (depth > 256)
88 throw EvaluationError ("Recursive symbol references");
89 }
90
91 friend class Expression::Term;
92
93 //==============================================================================
95 class EvaluationError : public std::exception
96 {
97 public:
98 EvaluationError (const String& desc) : description (desc)
99 {
100 DBG ("Expression::EvaluationError: " + description);
101 }
102
103 String description;
104 };
105
106 //==============================================================================
107 class Constant : public Term
108 {
109 public:
110 Constant (double val, bool resolutionTarget)
111 : value (val), isResolutionTarget (resolutionTarget) {}
112
113 Type getType() const noexcept { return constantType; }
114 Term* clone() const { return new Constant (value, isResolutionTarget); }
115 TermPtr resolve (const Scope&, int) { return *this; }
116 double toDouble() const { return value; }
117 TermPtr negated() { return *new Constant (-value, isResolutionTarget); }
118
119 String toString() const
120 {
121 String s (value);
122 if (isResolutionTarget)
123 s = "@" + s;
124
125 return s;
126 }
127
128 double value;
129 bool isResolutionTarget;
130 };
131
132 //==============================================================================
133 class BinaryTerm : public Term
134 {
135 public:
136 BinaryTerm (TermPtr l, TermPtr r) : left (std::move (l)), right (std::move (r))
137 {
138 jassert (left != nullptr && right != nullptr);
139 }
140
141 int getInputIndexFor (const Term* possibleInput) const
142 {
143 return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
144 }
145
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); }
149
150 virtual double performFunction (double left, double right) const = 0;
151 virtual void writeOperator (String& dest) const = 0;
152
153 TermPtr resolve (const Scope& scope, int recursionDepth)
154 {
155 return *new Constant (performFunction (left ->resolve (scope, recursionDepth)->toDouble(),
156 right->resolve (scope, recursionDepth)->toDouble()), false);
157 }
158
159 String toString() const
160 {
161 String s;
162 auto ourPrecendence = getOperatorPrecedence();
163
164 if (left->getOperatorPrecedence() > ourPrecendence)
165 s << '(' << left->toString() << ')';
166 else
167 s = left->toString();
168
169 writeOperator (s);
170
171 if (right->getOperatorPrecedence() >= ourPrecendence)
172 s << '(' << right->toString() << ')';
173 else
174 s << right->toString();
175
176 return s;
177 }
178
179 protected:
180 const TermPtr left, right;
181
182 TermPtr createDestinationTerm (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
183 {
184 jassert (input == left || input == right);
185 if (input != left && input != right)
186 return {};
187
188 if (auto dest = findDestinationFor (topLevelTerm, this))
189 return dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm);
190
191 return *new Constant (overallTarget, false);
192 }
193 };
194
195 //==============================================================================
196 class SymbolTerm : public Term
197 {
198 public:
199 explicit SymbolTerm (const String& sym) : symbol (sym) {}
200
201 TermPtr resolve (const Scope& scope, int recursionDepth)
202 {
203 checkRecursionDepth (recursionDepth);
204 return scope.getSymbolValue (symbol).term->resolve (scope, recursionDepth + 1);
205 }
206
207 Type getType() const noexcept { return symbolType; }
208 Term* clone() const { return new SymbolTerm (symbol); }
209 String toString() const { return symbol; }
210 String getName() const { return symbol; }
211
212 void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
213 {
214 checkRecursionDepth (recursionDepth);
215 visitor.useSymbol (Symbol (scope.getScopeUID(), symbol));
216 scope.getSymbolValue (symbol).term->visitAllSymbols (visitor, scope, recursionDepth + 1);
217 }
218
219 void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int /*recursionDepth*/)
220 {
221 if (oldSymbol.symbolName == symbol && scope.getScopeUID() == oldSymbol.scopeUID)
222 symbol = newName;
223 }
224
225 String symbol;
226 };
227
228 //==============================================================================
229 class Function : public Term
230 {
231 public:
232 explicit Function (const String& name) : functionName (name) {}
233
234 Function (const String& name, const Array<Expression>& params)
235 : functionName (name), parameters (params)
236 {}
237
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; }
243
244 TermPtr resolve (const Scope& scope, int recursionDepth)
245 {
246 checkRecursionDepth (recursionDepth);
247 double result = 0;
248 auto numParams = parameters.size();
249
250 if (numParams > 0)
251 {
252 HeapBlock<double> params (numParams);
253
254 for (int i = 0; i < numParams; ++i)
255 params[i] = parameters.getReference(i).term->resolve (scope, recursionDepth + 1)->toDouble();
256
257 result = scope.evaluateFunction (functionName, params, numParams);
258 }
259 else
260 {
261 result = scope.evaluateFunction (functionName, nullptr, 0);
262 }
263
264 return *new Constant (result, false);
265 }
266
267 int getInputIndexFor (const Term* possibleInput) const
268 {
269 for (int i = 0; i < parameters.size(); ++i)
270 if (parameters.getReference(i).term == possibleInput)
271 return i;
272
273 return -1;
274 }
275
276 String toString() const
277 {
278 if (parameters.size() == 0)
279 return functionName + "()";
280
281 String s (functionName + " (");
282
283 for (int i = 0; i < parameters.size(); ++i)
284 {
285 s << parameters.getReference(i).term->toString();
286
287 if (i < parameters.size() - 1)
288 s << ", ";
289 }
290
291 s << ')';
292 return s;
293 }
294
295 const String functionName;
296 Array<Expression> parameters;
297 };
298
299 //==============================================================================
300 class DotOperator : public BinaryTerm
301 {
302 public:
303 DotOperator (SymbolTerm* l, TermPtr r) : BinaryTerm (TermPtr (l), r) {}
304
305 TermPtr resolve (const Scope& scope, int recursionDepth)
306 {
307 checkRecursionDepth (recursionDepth);
308
309 EvaluationVisitor visitor (right, recursionDepth + 1);
310 scope.visitRelativeScope (getSymbol()->symbol, visitor);
311 return visitor.output;
312 }
313
314 Term* clone() const { return new DotOperator (getSymbol(), *right); }
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; }
319
320 void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
321 {
322 checkRecursionDepth (recursionDepth);
323 visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->symbol));
324
325 SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);
326
327 try
328 {
329 scope.visitRelativeScope (getSymbol()->symbol, v);
330 }
331 catch (...) {}
332 }
333
334 void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
335 {
336 checkRecursionDepth (recursionDepth);
337 getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth);
338
339 SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1);
340
341 try
342 {
343 scope.visitRelativeScope (getSymbol()->symbol, visitor);
344 }
345 catch (...) {}
346 }
347
348 private:
349 //==============================================================================
350 class EvaluationVisitor : public Scope::Visitor
351 {
352 public:
353 EvaluationVisitor (const TermPtr& t, const int recursion)
354 : input (t), output (t), recursionCount (recursion) {}
355
356 void visit (const Scope& scope) { output = input->resolve (scope, recursionCount); }
357
358 const TermPtr input;
359 TermPtr output;
360 const int recursionCount;
361
362 private:
363 JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor)
364 };
365
366 class SymbolVisitingVisitor : public Scope::Visitor
367 {
368 public:
369 SymbolVisitingVisitor (const TermPtr& t, SymbolVisitor& v, const int recursion)
370 : input (t), visitor (v), recursionCount (recursion) {}
371
372 void visit (const Scope& scope) { input->visitAllSymbols (visitor, scope, recursionCount); }
373
374 private:
375 const TermPtr input;
376 SymbolVisitor& visitor;
377 const int recursionCount;
378
379 JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor)
380 };
381
382 class SymbolRenamingVisitor : public Scope::Visitor
383 {
384 public:
385 SymbolRenamingVisitor (const TermPtr& t, const Expression::Symbol& symbol_, const String& newName_, const int recursionCount_)
386 : input (t), symbol (symbol_), newName (newName_), recursionCount (recursionCount_) {}
387
388 void visit (const Scope& scope) { input->renameSymbol (symbol, newName, scope, recursionCount); }
389
390 private:
391 const TermPtr input;
392 const Symbol& symbol;
393 const String newName;
394 const int recursionCount;
395
396 JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor)
397 };
398
399 SymbolTerm* getSymbol() const { return static_cast<SymbolTerm*> (left.get()); }
400
401 JUCE_DECLARE_NON_COPYABLE (DotOperator)
402 };
403
404 //==============================================================================
405 class Negate : public Term
406 {
407 public:
408 explicit Negate (const TermPtr& t) : input (t)
409 {
410 jassert (t != nullptr);
411 }
412
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()); }
418
419 TermPtr resolve (const Scope& scope, int recursionDepth)
420 {
421 return *new Constant (-input->resolve (scope, recursionDepth)->toDouble(), false);
422 }
423
424 String getName() const { return "-"; }
425 TermPtr negated() { return input; }
426
427 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* t, double overallTarget, Term* topLevelTerm) const
428 {
429 ignoreUnused (t);
430 jassert (t == input);
431
432 const Term* const dest = findDestinationFor (topLevelTerm, this);
433
434 return *new Negate (dest == nullptr ? TermPtr (*new Constant (overallTarget, false))
435 : dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm));
436 }
437
438 String toString() const
439 {
440 if (input->getOperatorPrecedence() > 0)
441 return "-(" + input->toString() + ")";
442
443 return "-" + input->toString();
444 }
445
446 private:
447 const TermPtr input;
448 };
449
450 //==============================================================================
451 class Add : public BinaryTerm
452 {
453 public:
454 Add (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
455
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 << " + "; }
461
462 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
463 {
464 if (auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
465 return *new Subtract (newDest, *(input == left ? right : left)->clone());
466
467 return {};
468 }
469
470 private:
471 JUCE_DECLARE_NON_COPYABLE (Add)
472 };
473
474 //==============================================================================
475 class Subtract : public BinaryTerm
476 {
477 public:
478 Subtract (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
479
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 << " - "; }
485
486 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
487 {
488 if (auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
489 {
490 if (input == left)
491 return *new Add (*newDest, *right->clone());
492
493 return *new Subtract (*left->clone(), *newDest);
494 }
495
496 return {};
497 }
498
499 private:
500 JUCE_DECLARE_NON_COPYABLE (Subtract)
501 };
502
503 //==============================================================================
504 class Multiply : public BinaryTerm
505 {
506 public:
507 Multiply (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
508
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; }
514
515 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
516 {
517 if (auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
518 return *new Divide (newDest, *(input == left ? right : left)->clone());
519
520 return {};
521 }
522
523 JUCE_DECLARE_NON_COPYABLE (Multiply)
524 };
525
526 //==============================================================================
527 class Divide : public BinaryTerm
528 {
529 public:
530 Divide (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
531
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; }
537
538 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
539 {
540 auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm);
541
542 if (newDest == nullptr)
543 return {};
544
545 if (input == left)
546 return *new Multiply (*newDest, *right->clone());
547
548 return *new Divide (*left->clone(), *newDest);
549 }
550
551 JUCE_DECLARE_NON_COPYABLE (Divide)
552 };
553
554 //==============================================================================
555 static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm)
556 {
557 const int inputIndex = topLevel->getInputIndexFor (inputTerm);
558 if (inputIndex >= 0)
559 return topLevel;
560
561 for (int i = topLevel->getNumInputs(); --i >= 0;)
562 {
563 Term* const t = findDestinationFor (topLevel->getInput (i), inputTerm);
564
565 if (t != nullptr)
566 return t;
567 }
568
569 return nullptr;
570 }
571
572 static Constant* findTermToAdjust (Term* const term, const bool mustBeFlagged)
573 {
574 jassert (term != nullptr);
575
576 if (term->getType() == constantType)
577 {
578 Constant* const c = static_cast<Constant*> (term);
579 if (c->isResolutionTarget || ! mustBeFlagged)
580 return c;
581 }
582
583 if (term->getType() == functionType)
584 return nullptr;
585
586 const int numIns = term->getNumInputs();
587
588 for (int i = 0; i < numIns; ++i)
589 {
590 Term* const input = term->getInput (i);
591
592 if (input->getType() == constantType)
593 {
594 Constant* const c = static_cast<Constant*> (input);
595
596 if (c->isResolutionTarget || ! mustBeFlagged)
597 return c;
598 }
599 }
600
601 for (int i = 0; i < numIns; ++i)
602 if (auto c = findTermToAdjust (term->getInput (i), mustBeFlagged))
603 return c;
604
605 return nullptr;
606 }
607
608 static bool containsAnySymbols (const Term& t)
609 {
610 if (t.getType() == Expression::symbolType)
611 return true;
612
613 for (int i = t.getNumInputs(); --i >= 0;)
614 if (containsAnySymbols (*t.getInput (i)))
615 return true;
616
617 return false;
618 }
619
620 //==============================================================================
621 class SymbolCheckVisitor : public Term::SymbolVisitor
622 {
623 public:
624 SymbolCheckVisitor (const Symbol& s) : symbol (s) {}
625 void useSymbol (const Symbol& s) { wasFound = wasFound || s == symbol; }
626
627 bool wasFound = false;
628
629 private:
630 const Symbol& symbol;
631
632 JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor)
633 };
634
635 //==============================================================================
636 class SymbolListVisitor : public Term::SymbolVisitor
637 {
638 public:
639 SymbolListVisitor (Array<Symbol>& list_) : list (list_) {}
640 void useSymbol (const Symbol& s) { list.addIfNotAlreadyThere (s); }
641
642 private:
643 Array<Symbol>& list;
644
645 JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor)
646 };
647
648 //==============================================================================
649 class Parser
650 {
651 public:
652 //==============================================================================
653 Parser (String::CharPointerType& stringToParse) : text (stringToParse)
654 {
655 }
656
657 TermPtr readUpToComma()
658 {
659 if (text.isEmpty())
660 return *new Constant (0.0, false);
661
662 auto e = readExpression();
663
664 if (e == nullptr || ((! readOperator (",")) && ! text.isEmpty()))
665 return parseError ("Syntax error: \"" + String (text) + "\"");
666
667 return e;
668 }
669
670 String error;
671
672 private:
673 String::CharPointerType& text;
674
675 TermPtr parseError (const String& message)
676 {
677 if (error.isEmpty())
678 error = message;
679
680 return {};
681 }
682
683 //==============================================================================
684 static inline bool isDecimalDigit (const juce_wchar c) noexcept
685 {
686 return c >= '0' && c <= '9';
687 }
688
689 bool readChar (const juce_wchar required) noexcept
690 {
691 if (*text == required)
692 {
693 ++text;
694 return true;
695 }
696
697 return false;
698 }
699
700 bool readOperator (const char* ops, char* const opType = nullptr) noexcept
701 {
702 text = text.findEndOfWhitespace();
703
704 while (*ops != 0)
705 {
706 if (readChar ((juce_wchar) (uint8) *ops))
707 {
708 if (opType != nullptr)
709 *opType = *ops;
710
711 return true;
712 }
713
714 ++ops;
715 }
716
717 return false;
718 }
719
720 bool readIdentifier (String& identifier) noexcept
721 {
722 text = text.findEndOfWhitespace();
723 auto t = text;
724 int numChars = 0;
725
726 if (t.isLetter() || *t == '_')
727 {
728 ++t;
729 ++numChars;
730
731 while (t.isLetterOrDigit() || *t == '_')
732 {
733 ++t;
734 ++numChars;
735 }
736 }
737
738 if (numChars > 0)
739 {
740 identifier = String (text, (size_t) numChars);
741 text = t;
742 return true;
743 }
744
745 return false;
746 }
747
748 Term* readNumber() noexcept
749 {
750 text = text.findEndOfWhitespace();
751 auto t = text;
752 bool isResolutionTarget = (*t == '@');
753
754 if (isResolutionTarget)
755 {
756 ++t;
757 t = t.findEndOfWhitespace();
758 text = t;
759 }
760
761 if (*t == '-')
762 {
763 ++t;
764 t = t.findEndOfWhitespace();
765 }
766
767 if (isDecimalDigit (*t) || (*t == '.' && isDecimalDigit (t[1])))
768 return new Constant (CharacterFunctions::readDoubleValue (text), isResolutionTarget);
769
770 return nullptr;
771 }
772
773 TermPtr readExpression()
774 {
775 auto lhs = readMultiplyOrDivideExpression();
776 char opType;
777
778 while (lhs != nullptr && readOperator ("+-", &opType))
779 {
780 auto rhs = readMultiplyOrDivideExpression();
781
782 if (rhs == nullptr)
783 return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
784
785 if (opType == '+')
786 lhs = *new Add (lhs, rhs);
787 else
788 lhs = *new Subtract (lhs, rhs);
789 }
790
791 return lhs;
792 }
793
794 TermPtr readMultiplyOrDivideExpression()
795 {
796 auto lhs = readUnaryExpression();
797 char opType;
798
799 while (lhs != nullptr && readOperator ("*/", &opType))
800 {
801 TermPtr rhs (readUnaryExpression());
802
803 if (rhs == nullptr)
804 return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
805
806 if (opType == '*')
807 lhs = *new Multiply (lhs, rhs);
808 else
809 lhs = *new Divide (lhs, rhs);
810 }
811
812 return lhs;
813 }
814
815 TermPtr readUnaryExpression()
816 {
817 char opType;
818 if (readOperator ("+-", &opType))
819 {
820 TermPtr e (readUnaryExpression());
821
822 if (e == nullptr)
823 return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
824
825 if (opType == '-')
826 e = e->negated();
827
828 return e;
829 }
830
831 return readPrimaryExpression();
832 }
833
834 TermPtr readPrimaryExpression()
835 {
836 if (auto e = readParenthesisedExpression())
837 return e;
838
839 if (auto e = readNumber())
840 return e;
841
842 return readSymbolOrFunction();
843 }
844
845 TermPtr readSymbolOrFunction()
846 {
847 String identifier;
848
849 if (readIdentifier (identifier))
850 {
851 if (readOperator ("(")) // method call...
852 {
853 auto f = new Function (identifier);
854 std::unique_ptr<Term> func (f); // (can't use std::unique_ptr<Function> in MSVC)
855
856 auto param = readExpression();
857
858 if (param == nullptr)
859 {
860 if (readOperator (")"))
861 return TermPtr (func.release());
862
863 return parseError ("Expected parameters after \"" + identifier + " (\"");
864 }
865
866 f->parameters.add (Expression (param.get()));
867
868 while (readOperator (","))
869 {
870 param = readExpression();
871
872 if (param == nullptr)
873 return parseError ("Expected expression after \",\"");
874
875 f->parameters.add (Expression (param.get()));
876 }
877
878 if (readOperator (")"))
879 return TermPtr (func.release());
880
881 return parseError ("Expected \")\"");
882 }
883
884 if (readOperator ("."))
885 {
886 TermPtr rhs (readSymbolOrFunction());
887
888 if (rhs == nullptr)
889 return parseError ("Expected symbol or function after \".\"");
890
891 if (identifier == "this")
892 return rhs;
893
894 return *new DotOperator (new SymbolTerm (identifier), rhs);
895 }
896
897 // just a symbol..
898 jassert (identifier.trim() == identifier);
899 return *new SymbolTerm (identifier);
900 }
901
902 return {};
903 }
904
905 TermPtr readParenthesisedExpression()
906 {
907 if (! readOperator ("("))
908 return {};
909
910 auto e = readExpression();
911
912 if (e == nullptr || ! readOperator (")"))
913 return {};
914
915 return e;
916 }
917
918 JUCE_DECLARE_NON_COPYABLE (Parser)
919 };
920};
921
922//==============================================================================
923 Expression::Expression()
924 : term (new Expression::Helpers::Constant (0, false))
925{
926}
927
928 Expression::~Expression()
929{
930}
931
932 Expression::Expression (Term* t) : term (t)
933{
934 jassert (term != nullptr);
935}
936
937 Expression::Expression (const double constant)
938 : term (new Expression::Helpers::Constant (constant, false))
939{
940}
941
942 Expression::Expression (const Expression& other)
943 : term (other.term)
944{
945}
946
947 Expression& Expression::operator= (const Expression& other)
948{
949 term = other.term;
950 return *this;
951}
952
953 Expression::Expression (Expression&& other) noexcept
954 : term (std::move (other.term))
955{
956}
957
958 Expression& Expression::operator= (Expression&& other) noexcept
959{
960 term = std::move (other.term);
961 return *this;
962}
963
964 Expression::Expression (const String& stringToParse, String& parseError)
965{
966 auto text = stringToParse.getCharPointer();
967 Helpers::Parser parser (text);
968 term = parser.readUpToComma();
969 parseError = parser.error;
970}
971
972 Expression Expression::parse (String::CharPointerType& stringToParse, String& parseError)
973{
974 Helpers::Parser parser (stringToParse);
975 Expression e (parser.readUpToComma().get());
976 parseError = parser.error;
977 return e;
978}
979
980 double Expression::evaluate() const
981{
982 return evaluate (Expression::Scope());
983}
984
985 double Expression::evaluate (const Expression::Scope& scope) const
986{
987 String err;
988 return evaluate (scope, err);
989}
990
991 double Expression::evaluate (const Scope& scope, String& evaluationError) const
992{
993 try
994 {
995 return term->resolve (scope, 0)->toDouble();
996 }
997 catch (Helpers::EvaluationError& e)
998 {
999 evaluationError = e.description;
1000 }
1001
1002 return 0;
1003}
1004
1005 Expression Expression::operator+ (const Expression& other) const { return Expression (new Helpers::Add (term, other.term)); }
1006 Expression Expression::operator- (const Expression& other) const { return Expression (new Helpers::Subtract (term, other.term)); }
1007 Expression Expression::operator* (const Expression& other) const { return Expression (new Helpers::Multiply (term, other.term)); }
1008 Expression Expression::operator/ (const Expression& other) const { return Expression (new Helpers::Divide (term, other.term)); }
1009 Expression Expression::operator-() const { return Expression (term->negated().get()); }
1010 Expression Expression::symbol (const String& symbol) { return Expression (new Helpers::SymbolTerm (symbol)); }
1011
1012 Expression Expression::function (const String& functionName, const Array<Expression>& parameters)
1013{
1014 return Expression (new Helpers::Function (functionName, parameters));
1015}
1016
1017 Expression Expression::adjustedToGiveNewResult (const double targetValue, const Expression::Scope& scope) const
1018{
1019 std::unique_ptr<Term> newTerm (term->clone());
1020
1021 auto termToAdjust = Helpers::findTermToAdjust (newTerm.get(), true);
1022
1023 if (termToAdjust == nullptr)
1024 termToAdjust = Helpers::findTermToAdjust (newTerm.get(), false);
1025
1026 if (termToAdjust == nullptr)
1027 {
1028 newTerm.reset (new Helpers::Add (*newTerm.release(), *new Helpers::Constant (0, false)));
1029 termToAdjust = Helpers::findTermToAdjust (newTerm.get(), false);
1030 }
1031
1032 jassert (termToAdjust != nullptr);
1033
1034 if (const Term* parent = Helpers::findDestinationFor (newTerm.get(), termToAdjust))
1035 {
1036 if (Helpers::TermPtr reverseTerm = parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm.get()))
1037 termToAdjust->value = Expression (reverseTerm.get()).evaluate (scope);
1038 else
1039 return Expression (targetValue);
1040 }
1041 else
1042 {
1043 termToAdjust->value = targetValue;
1044 }
1045
1046 return Expression (newTerm.release());
1047}
1048
1049 Expression Expression::withRenamedSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Scope& scope) const
1050{
1051 jassert (newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
1052
1053 if (oldSymbol.symbolName == newName)
1054 return *this;
1055
1056 Expression e (term->clone());
1057 e.term->renameSymbol (oldSymbol, newName, scope, 0);
1058 return e;
1059}
1060
1061 bool Expression::referencesSymbol (const Expression::Symbol& symbolToCheck, const Scope& scope) const
1062{
1063 Helpers::SymbolCheckVisitor visitor (symbolToCheck);
1064
1065 try
1066 {
1067 term->visitAllSymbols (visitor, scope, 0);
1068 }
1069 catch (Helpers::EvaluationError&)
1070 {}
1071
1072 return visitor.wasFound;
1073}
1074
1075 void Expression::findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const
1076{
1077 try
1078 {
1079 Helpers::SymbolListVisitor visitor (results);
1080 term->visitAllSymbols (visitor, scope, 0);
1081 }
1082 catch (Helpers::EvaluationError&)
1083 {}
1084}
1085
1086 String Expression::toString() const { return term->toString(); }
1087 bool Expression::usesAnySymbols() const { return Helpers::containsAnySymbols (*term); }
1088 Expression::Type Expression::getType() const noexcept { return term->getType(); }
1089 String Expression::getSymbolOrFunction() const { return term->getName(); }
1090 int Expression::getNumInputs() const { return term->getNumInputs(); }
1091 Expression Expression::getInput (int index) const { return Expression (term->getInput (index)); }
1092
1093//==============================================================================
1094 ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated()
1095{
1096 return *new Helpers::Negate (*this);
1097}
1098
1099//==============================================================================
1100Expression::Symbol::Symbol (const String& scope, const String& symbol)
1101 : scopeUID (scope), symbolName (symbol)
1102{
1103}
1104
1105 bool Expression::Symbol::operator== (const Symbol& other) const noexcept
1106{
1107 return symbolName == other.symbolName && scopeUID == other.scopeUID;
1108}
1109
1110 bool Expression::Symbol::operator!= (const Symbol& other) const noexcept
1111{
1112 return ! operator== (other);
1113}
1114
1115//==============================================================================
1116Expression::Scope::Scope() {}
1117Expression::Scope::~Scope() {}
1118
1119 Expression Expression::Scope::getSymbolValue (const String& symbol) const
1120{
1121 if (symbol.isNotEmpty())
1122 throw Helpers::EvaluationError ("Unknown symbol: " + symbol);
1123
1124 return Expression();
1125}
1126
1127 double Expression::Scope::evaluateFunction (const String& functionName, const double* parameters, int numParams) const
1128{
1129 if (numParams > 0)
1130 {
1131 if (functionName == "min")
1132 {
1133 double v = parameters[0];
1134 for (int i = 1; i < numParams; ++i)
1135 v = jmin (v, parameters[i]);
1136
1137 return v;
1138 }
1139
1140 if (functionName == "max")
1141 {
1142 double v = parameters[0];
1143 for (int i = 1; i < numParams; ++i)
1144 v = jmax (v, parameters[i]);
1145
1146 return v;
1147 }
1148
1149 if (numParams == 1)
1150 {
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]);
1155 }
1156 }
1157
1158 throw Helpers::EvaluationError ("Unknown function: \"" + functionName + "\"");
1159}
1160
1161 void Expression::Scope::visitRelativeScope (const String& scopeName, Visitor&) const
1162{
1163 throw Helpers::EvaluationError ("Unknown symbol: " + scopeName);
1164}
1165
1166 String Expression::Scope::getScopeUID() const
1167{
1168 return {};
1169}
1170
1171} // namespace juce
juce::Array
Definition: juce_Array.h:56
juce::CharacterFunctions::readDoubleValue
static double readDoubleValue(CharPointerType &text) noexcept
Definition: juce_CharacterFunctions.h:147
juce::Expression::Helpers::EvaluationError
Definition: juce_Expression.cpp:96
juce::Expression::Scope::Visitor
Definition: juce_Expression.h:137
juce::Expression::Scope
Definition: juce_Expression.h:109
juce::Expression::Scope::getSymbolValue
virtual Expression getSymbolValue(const String &symbol) const
Definition: juce_Expression.cpp:1119
juce::Expression::Scope::visitRelativeScope
virtual void visitRelativeScope(const String &scopeName, Visitor &visitor) const
Definition: juce_Expression.cpp:1161
juce::Expression::Scope::getScopeUID
virtual String getScopeUID() const
Definition: juce_Expression.cpp:1166
juce::Expression::Scope::evaluateFunction
virtual double evaluateFunction(const String &functionName, const double *parameters, int numParameters) const
Definition: juce_Expression.cpp:1127
juce::Expression
Definition: juce_Expression.h:44
juce::Expression::operator*
Expression operator*(const Expression &) const
Definition: juce_Expression.cpp:1007
juce::Expression::adjustedToGiveNewResult
Expression adjustedToGiveNewResult(double targetValue, const Scope &scope) const
Definition: juce_Expression.cpp:1017
juce::Expression::findReferencedSymbols
void findReferencedSymbols(Array< Symbol > &results, const Scope &scope) const
Definition: juce_Expression.cpp:1075
juce::Expression::operator+
Expression operator+(const Expression &) const
Definition: juce_Expression.cpp:1005
juce::Expression::function
static Expression function(const String &functionName, const Array< Expression > &parameters)
Definition: juce_Expression.cpp:1012
juce::Expression::getSymbolOrFunction
String getSymbolOrFunction() const
Definition: juce_Expression.cpp:1089
juce::Expression::Expression
Expression()
Definition: juce_Expression.cpp:923
juce::Expression::usesAnySymbols
bool usesAnySymbols() const
Definition: juce_Expression.cpp:1087
juce::Expression::withRenamedSymbol
Expression withRenamedSymbol(const Symbol &oldSymbol, const String &newName, const Scope &scope) const
Definition: juce_Expression.cpp:1049
juce::Expression::~Expression
~Expression()
Definition: juce_Expression.cpp:928
juce::Expression::operator/
Expression operator/(const Expression &) const
Definition: juce_Expression.cpp:1008
juce::Expression::getType
Type getType() const noexcept
Definition: juce_Expression.cpp:1088
juce::Expression::evaluate
double evaluate() const
Definition: juce_Expression.cpp:980
juce::Expression::parse
static Expression parse(String::CharPointerType &stringToParse, String &parseError)
Definition: juce_Expression.cpp:972
juce::Expression::getNumInputs
int getNumInputs() const
Definition: juce_Expression.cpp:1090
juce::Expression::getInput
Expression getInput(int index) const
Definition: juce_Expression.cpp:1091
juce::Expression::referencesSymbol
bool referencesSymbol(const Symbol &symbol, const Scope &scope) const
Definition: juce_Expression.cpp:1061
juce::Expression::symbol
static Expression symbol(const String &symbol)
Definition: juce_Expression.cpp:1010
juce::Expression::operator-
Expression operator-() const
Definition: juce_Expression.cpp:1009
juce::Expression::Type
Type
Definition: juce_Expression.h:219
juce::Expression::toString
String toString() const
Definition: juce_Expression.cpp:1086
juce::Expression::operator=
Expression & operator=(const Expression &)
Definition: juce_Expression.cpp:947
juce::ReferenceCountedObjectPtr< Term >
juce::String
Definition: juce_String.h:39
juce::String::getCharPointer
CharPointerType getCharPointer() const noexcept
Definition: juce_String.h:1198
juce::String::toLowerCase
String toLowerCase() const
Definition: juce_String.cpp:1485
juce::String::charToString
static String charToString(juce_wchar character)
Definition: juce_String.cpp:371
juce::String::containsOnly
bool containsOnly(StringRef charactersItMightContain) const noexcept
Definition: juce_String.cpp:1807
juce::Expression::Symbol
Definition: juce_Expression.h:186
juce::Expression::Symbol::symbolName
String symbolName
Definition: juce_Expression.h:192