OpenShot Audio Library | OpenShotAudio 0.4.0
 
Loading...
Searching...
No Matches
juce_Expression.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
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
23namespace juce
24{
25
26class Expression::Term : public SingleThreadedReferenceCountedObject
27{
28public:
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
75private:
76 JUCE_DECLARE_NON_COPYABLE (Term)
77};
78
79
80//==============================================================================
81struct 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 final : 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 final : public Term
108 {
109 public:
110 Constant (double val, bool resolutionTarget)
111 : value (val), isResolutionTarget (resolutionTarget) {}
112
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); }
118
119 String toString() const override
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 override
142 {
143 return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
144 }
145
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); }
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) override
154 {
155 return *new Constant (performFunction (left ->resolve (scope, recursionDepth)->toDouble(),
156 right->resolve (scope, recursionDepth)->toDouble()), false);
157 }
158
159 String toString() const override
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 final : public Term
197 {
198 public:
199 explicit SymbolTerm (const String& sym) : symbol (sym) {}
200
201 TermPtr resolve (const Scope& scope, int recursionDepth) override
202 {
203 checkRecursionDepth (recursionDepth);
204 return scope.getSymbolValue (symbol).term->resolve (scope, recursionDepth + 1);
205 }
206
207 Type getType() const noexcept override { return symbolType; }
208 Term* clone() const override { return new SymbolTerm (symbol); }
209 String toString() const override { return symbol; }
210 String getName() const override { return symbol; }
211
212 void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth) override
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*/) override
220 {
221 if (oldSymbol.symbolName == symbol && scope.getScopeUID() == oldSymbol.scopeUID)
222 symbol = newName;
223 }
224
225 String symbol;
226 };
227
228 //==============================================================================
229 class Function final : 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 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; }
243
244 TermPtr resolve (const Scope& scope, int recursionDepth) override
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 override
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 override
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 final : public BinaryTerm
301 {
302 public:
303 DotOperator (SymbolTerm* l, TermPtr r) : BinaryTerm (TermPtr (l), r) {}
304
305 TermPtr resolve (const Scope& scope, int recursionDepth) override
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 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; }
319
320 void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth) override
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) override
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 final : 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) override { 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 final : 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) override { 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 final : 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) override { 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 final : 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 override { return operatorType; }
414 int getInputIndexFor (const Term* possibleInput) const override { return possibleInput == input ? 0 : -1; }
415 int getNumInputs() const override { return 1; }
416 Term* getInput (int index) const override { return index == 0 ? input.get() : nullptr; }
417 Term* clone() const override { return new Negate (*input->clone()); }
418
419 TermPtr resolve (const Scope& scope, int recursionDepth) override
420 {
421 return *new Constant (-input->resolve (scope, recursionDepth)->toDouble(), false);
422 }
423
424 String getName() const override { return "-"; }
425 TermPtr negated() override { return input; }
426
427 TermPtr createTermToEvaluateInput (const Scope& scope, [[maybe_unused]] const Term* t, double overallTarget, Term* topLevelTerm) const override
428 {
429 jassert (t == input);
430
431 const Term* const dest = findDestinationFor (topLevelTerm, this);
432
433 return *new Negate (dest == nullptr ? TermPtr (*new Constant (overallTarget, false))
434 : dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm));
435 }
436
437 String toString() const override
438 {
439 if (input->getOperatorPrecedence() > 0)
440 return "-(" + input->toString() + ")";
441
442 return "-" + input->toString();
443 }
444
445 private:
446 const TermPtr input;
447 };
448
449 //==============================================================================
450 class Add final : public BinaryTerm
451 {
452 public:
453 Add (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
454
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 << " + "; }
460
461 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const override
462 {
463 if (auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
464 return *new Subtract (newDest, *(input == left ? right : left)->clone());
465
466 return {};
467 }
468
469 private:
470 JUCE_DECLARE_NON_COPYABLE (Add)
471 };
472
473 //==============================================================================
474 class Subtract final : public BinaryTerm
475 {
476 public:
477 Subtract (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
478
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 << " - "; }
484
485 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const override
486 {
487 if (auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
488 {
489 if (input == left)
490 return *new Add (*newDest, *right->clone());
491
492 return *new Subtract (*left->clone(), *newDest);
493 }
494
495 return {};
496 }
497
498 private:
499 JUCE_DECLARE_NON_COPYABLE (Subtract)
500 };
501
502 //==============================================================================
503 class Multiply final : public BinaryTerm
504 {
505 public:
506 Multiply (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
507
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; }
513
514 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const override
515 {
516 if (auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm))
517 return *new Divide (newDest, *(input == left ? right : left)->clone());
518
519 return {};
520 }
521
522 JUCE_DECLARE_NON_COPYABLE (Multiply)
523 };
524
525 //==============================================================================
526 class Divide final : public BinaryTerm
527 {
528 public:
529 Divide (TermPtr l, TermPtr r) : BinaryTerm (l, r) {}
530
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; }
536
537 TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const override
538 {
539 auto newDest = createDestinationTerm (scope, input, overallTarget, topLevelTerm);
540
541 if (newDest == nullptr)
542 return {};
543
544 if (input == left)
545 return *new Multiply (*newDest, *right->clone());
546
547 return *new Divide (*left->clone(), *newDest);
548 }
549
550 JUCE_DECLARE_NON_COPYABLE (Divide)
551 };
552
553 //==============================================================================
554 static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm)
555 {
556 const int inputIndex = topLevel->getInputIndexFor (inputTerm);
557 if (inputIndex >= 0)
558 return topLevel;
559
560 for (int i = topLevel->getNumInputs(); --i >= 0;)
561 {
562 Term* const t = findDestinationFor (topLevel->getInput (i), inputTerm);
563
564 if (t != nullptr)
565 return t;
566 }
567
568 return nullptr;
569 }
570
571 static Constant* findTermToAdjust (Term* const term, const bool mustBeFlagged)
572 {
573 if (term == nullptr)
574 {
575 jassertfalse;
576 return nullptr;
577 }
578
579 if (term->getType() == constantType)
580 {
581 Constant* const c = static_cast<Constant*> (term);
582 if (c->isResolutionTarget || ! mustBeFlagged)
583 return c;
584 }
585
586 if (term->getType() == functionType)
587 return nullptr;
588
589 const int numIns = term->getNumInputs();
590
591 for (int i = 0; i < numIns; ++i)
592 {
593 Term* const input = term->getInput (i);
594
595 if (input->getType() == constantType)
596 {
597 Constant* const c = static_cast<Constant*> (input);
598
599 if (c->isResolutionTarget || ! mustBeFlagged)
600 return c;
601 }
602 }
603
604 for (int i = 0; i < numIns; ++i)
605 if (auto c = findTermToAdjust (term->getInput (i), mustBeFlagged))
606 return c;
607
608 return nullptr;
609 }
610
611 static bool containsAnySymbols (const Term& t)
612 {
613 if (t.getType() == Expression::symbolType)
614 return true;
615
616 for (int i = t.getNumInputs(); --i >= 0;)
617 if (containsAnySymbols (*t.getInput (i)))
618 return true;
619
620 return false;
621 }
622
623 //==============================================================================
624 class SymbolCheckVisitor final : public Term::SymbolVisitor
625 {
626 public:
627 SymbolCheckVisitor (const Symbol& s) : symbol (s) {}
628 void useSymbol (const Symbol& s) override { wasFound = wasFound || s == symbol; }
629
630 bool wasFound = false;
631
632 private:
633 const Symbol& symbol;
634
635 JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor)
636 };
637
638 //==============================================================================
639 class SymbolListVisitor final : public Term::SymbolVisitor
640 {
641 public:
642 SymbolListVisitor (Array<Symbol>& list_) : list (list_) {}
643 void useSymbol (const Symbol& s) override { list.addIfNotAlreadyThere (s); }
644
645 private:
646 Array<Symbol>& list;
647
648 JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor)
649 };
650
651 //==============================================================================
652 class Parser
653 {
654 public:
655 //==============================================================================
656 Parser (String::CharPointerType& stringToParse) : text (stringToParse)
657 {
658 }
659
660 TermPtr readUpToComma()
661 {
662 if (text.isEmpty())
663 return *new Constant (0.0, false);
664
665 auto e = readExpression();
666
667 if (e == nullptr || ((! readOperator (",")) && ! text.isEmpty()))
668 return parseError ("Syntax error: \"" + String (text) + "\"");
669
670 return e;
671 }
672
673 String error;
674
675 private:
676 String::CharPointerType& text;
677
678 TermPtr parseError (const String& message)
679 {
680 if (error.isEmpty())
681 error = message;
682
683 return {};
684 }
685
686 //==============================================================================
687 static bool isDecimalDigit (const juce_wchar c) noexcept
688 {
689 return c >= '0' && c <= '9';
690 }
691
692 bool readChar (const juce_wchar required) noexcept
693 {
694 if (*text == required)
695 {
696 ++text;
697 return true;
698 }
699
700 return false;
701 }
702
703 bool readOperator (const char* ops, char* const opType = nullptr) noexcept
704 {
705 text.incrementToEndOfWhitespace();
706
707 while (*ops != 0)
708 {
709 if (readChar ((juce_wchar) (uint8) *ops))
710 {
711 if (opType != nullptr)
712 *opType = *ops;
713
714 return true;
715 }
716
717 ++ops;
718 }
719
720 return false;
721 }
722
723 bool readIdentifier (String& identifier) noexcept
724 {
725 text.incrementToEndOfWhitespace();
726 auto t = text;
727 int numChars = 0;
728
729 if (t.isLetter() || *t == '_')
730 {
731 ++t;
732 ++numChars;
733
734 while (t.isLetterOrDigit() || *t == '_')
735 {
736 ++t;
737 ++numChars;
738 }
739 }
740
741 if (numChars > 0)
742 {
743 identifier = String (text, (size_t) numChars);
744 text = t;
745 return true;
746 }
747
748 return false;
749 }
750
751 Term* readNumber() noexcept
752 {
753 text.incrementToEndOfWhitespace();
754 auto t = text;
755 bool isResolutionTarget = (*t == '@');
756
757 if (isResolutionTarget)
758 {
759 ++t;
760 t.incrementToEndOfWhitespace();
761 text = t;
762 }
763
764 if (*t == '-')
765 {
766 ++t;
767 t.incrementToEndOfWhitespace();
768 }
769
770 if (isDecimalDigit (*t) || (*t == '.' && isDecimalDigit (t[1])))
771 return new Constant (CharacterFunctions::readDoubleValue (text), isResolutionTarget);
772
773 return nullptr;
774 }
775
776 TermPtr readExpression()
777 {
778 auto lhs = readMultiplyOrDivideExpression();
779 char opType;
780
781 while (lhs != nullptr && readOperator ("+-", &opType))
782 {
783 auto rhs = readMultiplyOrDivideExpression();
784
785 if (rhs == nullptr)
786 return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
787
788 if (opType == '+')
789 lhs = *new Add (lhs, rhs);
790 else
791 lhs = *new Subtract (lhs, rhs);
792 }
793
794 return lhs;
795 }
796
797 TermPtr readMultiplyOrDivideExpression()
798 {
799 auto lhs = readUnaryExpression();
800 char opType;
801
802 while (lhs != nullptr && readOperator ("*/", &opType))
803 {
804 TermPtr rhs (readUnaryExpression());
805
806 if (rhs == nullptr)
807 return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
808
809 if (opType == '*')
810 lhs = *new Multiply (lhs, rhs);
811 else
812 lhs = *new Divide (lhs, rhs);
813 }
814
815 return lhs;
816 }
817
818 TermPtr readUnaryExpression()
819 {
820 char opType;
821 if (readOperator ("+-", &opType))
822 {
823 TermPtr e (readUnaryExpression());
824
825 if (e == nullptr)
826 return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
827
828 if (opType == '-')
829 e = e->negated();
830
831 return e;
832 }
833
834 return readPrimaryExpression();
835 }
836
837 TermPtr readPrimaryExpression()
838 {
839 if (auto e = readParenthesisedExpression())
840 return e;
841
842 if (auto e = readNumber())
843 return e;
844
845 return readSymbolOrFunction();
846 }
847
848 TermPtr readSymbolOrFunction()
849 {
850 String identifier;
851
852 if (readIdentifier (identifier))
853 {
854 if (readOperator ("(")) // method call...
855 {
856 auto f = new Function (identifier);
857 std::unique_ptr<Term> func (f); // (can't use std::unique_ptr<Function> in MSVC)
858
859 auto param = readExpression();
860
861 if (param == nullptr)
862 {
863 if (readOperator (")"))
864 return TermPtr (func.release());
865
866 return parseError ("Expected parameters after \"" + identifier + " (\"");
867 }
868
869 f->parameters.add (Expression (param.get()));
870
871 while (readOperator (","))
872 {
873 param = readExpression();
874
875 if (param == nullptr)
876 return parseError ("Expected expression after \",\"");
877
878 f->parameters.add (Expression (param.get()));
879 }
880
881 if (readOperator (")"))
882 return TermPtr (func.release());
883
884 return parseError ("Expected \")\"");
885 }
886
887 if (readOperator ("."))
888 {
889 TermPtr rhs (readSymbolOrFunction());
890
891 if (rhs == nullptr)
892 return parseError ("Expected symbol or function after \".\"");
893
894 if (identifier == "this")
895 return rhs;
896
897 return *new DotOperator (new SymbolTerm (identifier), rhs);
898 }
899
900 // just a symbol..
901 jassert (identifier.trim() == identifier);
902 return *new SymbolTerm (identifier);
903 }
904
905 return {};
906 }
907
908 TermPtr readParenthesisedExpression()
909 {
910 if (! readOperator ("("))
911 return {};
912
913 auto e = readExpression();
914
915 if (e == nullptr || ! readOperator (")"))
916 return {};
917
918 return e;
919 }
920
921 JUCE_DECLARE_NON_COPYABLE (Parser)
922 };
923};
924
925//==============================================================================
927 : term (new Expression::Helpers::Constant (0, false))
928{
929}
930
934
935Expression::Expression (Term* t) : term (t)
936{
937 jassert (term != nullptr);
938}
939
940Expression::Expression (const double constant)
941 : term (new Expression::Helpers::Constant (constant, false))
942{
943}
944
946 : term (other.term)
947{
948}
949
951{
952 term = other.term;
953 return *this;
954}
955
957 : term (std::move (other.term))
958{
959}
960
962{
963 term = std::move (other.term);
964 return *this;
965}
966
967Expression::Expression (const String& stringToParse, String& parseError)
968{
969 auto text = stringToParse.getCharPointer();
970 Helpers::Parser parser (text);
971 term = parser.readUpToComma();
972 parseError = parser.error;
973}
974
975Expression Expression::parse (String::CharPointerType& stringToParse, String& parseError)
976{
977 Helpers::Parser parser (stringToParse);
978 Expression e (parser.readUpToComma().get());
979 parseError = parser.error;
980 return e;
981}
982
984{
985 return evaluate (Expression::Scope());
986}
987
988double Expression::evaluate (const Expression::Scope& scope) const
989{
990 String err;
991 return evaluate (scope, err);
992}
993
994double Expression::evaluate (const Scope& scope, String& evaluationError) const
995{
996 try
997 {
998 return term->resolve (scope, 0)->toDouble();
999 }
1000 catch (Helpers::EvaluationError& e)
1001 {
1002 evaluationError = e.description;
1003 }
1004
1005 return 0;
1006}
1007
1008Expression Expression::operator+ (const Expression& other) const { return Expression (new Helpers::Add (term, other.term)); }
1009Expression Expression::operator- (const Expression& other) const { return Expression (new Helpers::Subtract (term, other.term)); }
1010Expression Expression::operator* (const Expression& other) const { return Expression (new Helpers::Multiply (term, other.term)); }
1011Expression Expression::operator/ (const Expression& other) const { return Expression (new Helpers::Divide (term, other.term)); }
1012Expression Expression::operator-() const { return Expression (term->negated().get()); }
1013Expression Expression::symbol (const String& symbol) { return Expression (new Helpers::SymbolTerm (symbol)); }
1014
1015Expression Expression::function (const String& functionName, const Array<Expression>& parameters)
1016{
1017 return Expression (new Helpers::Function (functionName, parameters));
1018}
1019
1020Expression Expression::adjustedToGiveNewResult (const double targetValue, const Expression::Scope& scope) const
1021{
1022 std::unique_ptr<Term> newTerm (term->clone());
1023
1024 auto termToAdjust = Helpers::findTermToAdjust (newTerm.get(), true);
1025
1026 if (termToAdjust == nullptr)
1027 termToAdjust = Helpers::findTermToAdjust (newTerm.get(), false);
1028
1029 if (termToAdjust == nullptr)
1030 {
1031 newTerm.reset (new Helpers::Add (*newTerm.release(), *new Helpers::Constant (0, false)));
1032 termToAdjust = Helpers::findTermToAdjust (newTerm.get(), false);
1033 }
1034
1035 jassert (termToAdjust != nullptr);
1036
1037 if (const Term* parent = Helpers::findDestinationFor (newTerm.get(), termToAdjust))
1038 {
1039 if (Helpers::TermPtr reverseTerm = parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm.get()))
1040 termToAdjust->value = Expression (reverseTerm.get()).evaluate (scope);
1041 else
1042 return Expression (targetValue);
1043 }
1044 else
1045 {
1046 termToAdjust->value = targetValue;
1047 }
1048
1049 return Expression (newTerm.release());
1050}
1051
1052Expression Expression::withRenamedSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Scope& scope) const
1053{
1054 jassert (newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
1055
1056 if (oldSymbol.symbolName == newName)
1057 return *this;
1058
1059 Expression e (term->clone());
1060 e.term->renameSymbol (oldSymbol, newName, scope, 0);
1061 return e;
1062}
1063
1064bool Expression::referencesSymbol (const Expression::Symbol& symbolToCheck, const Scope& scope) const
1065{
1066 Helpers::SymbolCheckVisitor visitor (symbolToCheck);
1067
1068 try
1069 {
1070 term->visitAllSymbols (visitor, scope, 0);
1071 }
1073 {}
1074
1075 return visitor.wasFound;
1076}
1077
1078void Expression::findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const
1079{
1080 try
1081 {
1082 Helpers::SymbolListVisitor visitor (results);
1083 term->visitAllSymbols (visitor, scope, 0);
1084 }
1086 {}
1087}
1088
1089String Expression::toString() const { return term->toString(); }
1090bool Expression::usesAnySymbols() const { return Helpers::containsAnySymbols (*term); }
1091Expression::Type Expression::getType() const noexcept { return term->getType(); }
1092String Expression::getSymbolOrFunction() const { return term->getName(); }
1093int Expression::getNumInputs() const { return term->getNumInputs(); }
1094Expression Expression::getInput (int index) const { return Expression (term->getInput (index)); }
1095
1096//==============================================================================
1097ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated()
1098{
1099 return *new Helpers::Negate (*this);
1100}
1101
1102//==============================================================================
1103Expression::Symbol::Symbol (const String& scope, const String& symbol)
1104 : scopeUID (scope), symbolName (symbol)
1105{
1106}
1107
1108bool Expression::Symbol::operator== (const Symbol& other) const noexcept
1109{
1110 return symbolName == other.symbolName && scopeUID == other.scopeUID;
1111}
1112
1113bool Expression::Symbol::operator!= (const Symbol& other) const noexcept
1114{
1115 return ! operator== (other);
1116}
1117
1118//==============================================================================
1119Expression::Scope::Scope() {}
1120Expression::Scope::~Scope() {}
1121
1123{
1124 if (symbol.isNotEmpty())
1125 throw Helpers::EvaluationError ("Unknown symbol: " + symbol);
1126
1127 return Expression();
1128}
1129
1130double Expression::Scope::evaluateFunction (const String& functionName, const double* parameters, int numParams) const
1131{
1132 if (numParams > 0)
1133 {
1134 if (functionName == "min")
1135 {
1136 double v = parameters[0];
1137 for (int i = 1; i < numParams; ++i)
1138 v = jmin (v, parameters[i]);
1139
1140 return v;
1141 }
1142
1143 if (functionName == "max")
1144 {
1145 double v = parameters[0];
1146 for (int i = 1; i < numParams; ++i)
1147 v = jmax (v, parameters[i]);
1148
1149 return v;
1150 }
1151
1152 if (numParams == 1)
1153 {
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]);
1158 }
1159 }
1160
1161 throw Helpers::EvaluationError ("Unknown function: \"" + functionName + "\"");
1162}
1163
1165{
1166 throw Helpers::EvaluationError ("Unknown symbol: " + scopeName);
1167}
1168
1170{
1171 return {};
1172}
1173
1174} // namespace juce
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 > &parameters)
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
double evaluate() const
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
String toString() 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