OpenShot Audio Library | OpenShotAudio  0.6.0
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 
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 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 
932 {
933 }
934 
935 Expression::Expression (Term* t) : term (t)
936 {
937  jassert (term != nullptr);
938 }
939 
940 Expression::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 
967 Expression::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 
975 Expression 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 
983 double Expression::evaluate() const
984 {
985  return evaluate (Expression::Scope());
986 }
987 
988 double Expression::evaluate (const Expression::Scope& scope) const
989 {
990  String err;
991  return evaluate (scope, err);
992 }
993 
994 double 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 
1008 Expression Expression::operator+ (const Expression& other) const { return Expression (new Helpers::Add (term, other.term)); }
1009 Expression Expression::operator- (const Expression& other) const { return Expression (new Helpers::Subtract (term, other.term)); }
1010 Expression Expression::operator* (const Expression& other) const { return Expression (new Helpers::Multiply (term, other.term)); }
1011 Expression Expression::operator/ (const Expression& other) const { return Expression (new Helpers::Divide (term, other.term)); }
1012 Expression Expression::operator-() const { return Expression (term->negated().get()); }
1013 Expression Expression::symbol (const String& symbol) { return Expression (new Helpers::SymbolTerm (symbol)); }
1014 
1015 Expression Expression::function (const String& functionName, const Array<Expression>& parameters)
1016 {
1017  return Expression (new Helpers::Function (functionName, parameters));
1018 }
1019 
1020 Expression 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 
1052 Expression 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 
1064 bool 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  }
1072  catch (Helpers::EvaluationError&)
1073  {}
1074 
1075  return visitor.wasFound;
1076 }
1077 
1078 void 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  }
1085  catch (Helpers::EvaluationError&)
1086  {}
1087 }
1088 
1089 String Expression::toString() const { return term->toString(); }
1090 bool Expression::usesAnySymbols() const { return Helpers::containsAnySymbols (*term); }
1091 Expression::Type Expression::getType() const noexcept { return term->getType(); }
1092 String Expression::getSymbolOrFunction() const { return term->getName(); }
1093 int Expression::getNumInputs() const { return term->getNumInputs(); }
1094 Expression Expression::getInput (int index) const { return Expression (term->getInput (index)); }
1095 
1096 //==============================================================================
1097 ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated()
1098 {
1099  return *new Helpers::Negate (*this);
1100 }
1101 
1102 //==============================================================================
1103 Expression::Symbol::Symbol (const String& scope, const String& symbol)
1104  : scopeUID (scope), symbolName (symbol)
1105 {
1106 }
1107 
1108 bool Expression::Symbol::operator== (const Symbol& other) const noexcept
1109 {
1110  return symbolName == other.symbolName && scopeUID == other.scopeUID;
1111 }
1112 
1113 bool Expression::Symbol::operator!= (const Symbol& other) const noexcept
1114 {
1115  return ! operator== (other);
1116 }
1117 
1118 //==============================================================================
1119 Expression::Scope::Scope() {}
1120 Expression::Scope::~Scope() {}
1121 
1123 {
1124  if (symbol.isNotEmpty())
1125  throw Helpers::EvaluationError ("Unknown symbol: " + symbol);
1126 
1127  return Expression();
1128 }
1129 
1130 double 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)
int getNumInputs() const
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
Definition: juce_String.h:1153
String toLowerCase() const
static String charToString(juce_wchar character)
bool containsOnly(StringRef charactersItMightContain) const noexcept