OpenShot Audio Library | OpenShotAudio  0.3.3
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 //==============================================================================
924  : term (new Expression::Helpers::Constant (0, false))
925 {
926 }
927 
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 
943  : term (other.term)
944 {
945 }
946 
948 {
949  term = other.term;
950  return *this;
951 }
952 
954  : term (std::move (other.term))
955 {
956 }
957 
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 //==============================================================================
1100 Expression::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 //==============================================================================
1116 Expression::Scope::Scope() {}
1117 Expression::Scope::~Scope() {}
1118 
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 
1162 {
1163  throw Helpers::EvaluationError ("Unknown symbol: " + scopeName);
1164 }
1165 
1167 {
1168  return {};
1169 }
1170 
1171 } // 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:1198
String toLowerCase() const
static String charToString(juce_wchar character)
bool containsOnly(StringRef charactersItMightContain) const noexcept