12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184 |
- /*
- ==============================================================================
- This file is part of the juce_core module of the JUCE library.
- Copyright (c) 2013 - Raw Material Software Ltd.
- Permission to use, copy, modify, and/or distribute this software for any purpose with
- or without fee is hereby granted, provided that the above copyright notice and this
- permission notice appear in all copies.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
- TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
- NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ------------------------------------------------------------------------------
- NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
- All other JUCE modules are covered by a dual GPL/commercial license, so if you are
- using any other modules, be sure to check that you also comply with their license.
- For more details, visit www.juce.com
- ==============================================================================
- */
- class Expression::Term : public SingleThreadedReferenceCountedObject
- {
- public:
- Term() {}
- virtual ~Term() {}
- virtual Type getType() const noexcept = 0;
- virtual Term* clone() const = 0;
- virtual ReferenceCountedObjectPtr<Term> resolve (const Scope&, int recursionDepth) = 0;
- virtual String toString() const = 0;
- virtual double toDouble() const { return 0; }
- virtual int getInputIndexFor (const Term*) const { return -1; }
- virtual int getOperatorPrecedence() const { return 0; }
- virtual int getNumInputs() const { return 0; }
- virtual Term* getInput (int) const { return nullptr; }
- virtual ReferenceCountedObjectPtr<Term> negated();
- virtual ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const Scope&, const Term* /*inputTerm*/,
- double /*overallTarget*/, Term* /*topLevelTerm*/) const
- {
- jassertfalse;
- return ReferenceCountedObjectPtr<Term>();
- }
- virtual String getName() const
- {
- jassertfalse; // You shouldn't call this for an expression that's not actually a function!
- return String();
- }
- virtual void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
- {
- for (int i = getNumInputs(); --i >= 0;)
- getInput (i)->renameSymbol (oldSymbol, newName, scope, recursionDepth);
- }
- class SymbolVisitor
- {
- public:
- virtual ~SymbolVisitor() {}
- virtual void useSymbol (const Symbol&) = 0;
- };
- virtual void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
- {
- for (int i = getNumInputs(); --i >= 0;)
- getInput(i)->visitAllSymbols (visitor, scope, recursionDepth);
- }
- private:
- JUCE_DECLARE_NON_COPYABLE (Term)
- };
- //==============================================================================
- struct Expression::Helpers
- {
- typedef ReferenceCountedObjectPtr<Term> TermPtr;
- static void checkRecursionDepth (const int depth)
- {
- if (depth > 256)
- throw EvaluationError ("Recursive symbol references");
- }
- friend class Expression::Term;
- //==============================================================================
- /** An exception that can be thrown by Expression::evaluate(). */
- class EvaluationError : public std::exception
- {
- public:
- EvaluationError (const String& desc) : description (desc)
- {
- DBG ("Expression::EvaluationError: " + description);
- }
- String description;
- };
- //==============================================================================
- class Constant : public Term
- {
- public:
- Constant (const double val, const bool resolutionTarget)
- : value (val), isResolutionTarget (resolutionTarget) {}
- Type getType() const noexcept { return constantType; }
- Term* clone() const { return new Constant (value, isResolutionTarget); }
- TermPtr resolve (const Scope&, int) { return this; }
- double toDouble() const { return value; }
- TermPtr negated() { return new Constant (-value, isResolutionTarget); }
- String toString() const
- {
- String s (value);
- if (isResolutionTarget)
- s = "@" + s;
- return s;
- }
- double value;
- bool isResolutionTarget;
- };
- //==============================================================================
- class BinaryTerm : public Term
- {
- public:
- BinaryTerm (Term* const l, Term* const r) : left (l), right (r)
- {
- jassert (l != nullptr && r != nullptr);
- }
- int getInputIndexFor (const Term* possibleInput) const
- {
- return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
- }
- Type getType() const noexcept { return operatorType; }
- int getNumInputs() const { return 2; }
- Term* getInput (int index) const { return index == 0 ? left.get() : (index == 1 ? right.get() : 0); }
- virtual double performFunction (double left, double right) const = 0;
- virtual void writeOperator (String& dest) const = 0;
- TermPtr resolve (const Scope& scope, int recursionDepth)
- {
- return new Constant (performFunction (left ->resolve (scope, recursionDepth)->toDouble(),
- right->resolve (scope, recursionDepth)->toDouble()), false);
- }
- String toString() const
- {
- String s;
- const int ourPrecendence = getOperatorPrecedence();
- if (left->getOperatorPrecedence() > ourPrecendence)
- s << '(' << left->toString() << ')';
- else
- s = left->toString();
- writeOperator (s);
- if (right->getOperatorPrecedence() >= ourPrecendence)
- s << '(' << right->toString() << ')';
- else
- s << right->toString();
- return s;
- }
- protected:
- const TermPtr left, right;
- TermPtr createDestinationTerm (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
- {
- jassert (input == left || input == right);
- if (input != left && input != right)
- return TermPtr();
- if (const Term* const dest = findDestinationFor (topLevelTerm, this))
- return dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm);
- return new Constant (overallTarget, false);
- }
- };
- //==============================================================================
- class SymbolTerm : public Term
- {
- public:
- explicit SymbolTerm (const String& sym) : symbol (sym) {}
- TermPtr resolve (const Scope& scope, int recursionDepth)
- {
- checkRecursionDepth (recursionDepth);
- return scope.getSymbolValue (symbol).term->resolve (scope, recursionDepth + 1);
- }
- Type getType() const noexcept { return symbolType; }
- Term* clone() const { return new SymbolTerm (symbol); }
- String toString() const { return symbol; }
- String getName() const { return symbol; }
- void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
- {
- checkRecursionDepth (recursionDepth);
- visitor.useSymbol (Symbol (scope.getScopeUID(), symbol));
- scope.getSymbolValue (symbol).term->visitAllSymbols (visitor, scope, recursionDepth + 1);
- }
- void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int /*recursionDepth*/)
- {
- if (oldSymbol.symbolName == symbol && scope.getScopeUID() == oldSymbol.scopeUID)
- symbol = newName;
- }
- String symbol;
- };
- //==============================================================================
- class Function : public Term
- {
- public:
- explicit Function (const String& name) : functionName (name) {}
- Function (const String& name, const Array<Expression>& params)
- : functionName (name), parameters (params)
- {}
- Type getType() const noexcept { return functionType; }
- Term* clone() const { return new Function (functionName, parameters); }
- int getNumInputs() const { return parameters.size(); }
- Term* getInput (int i) const { return parameters.getReference(i).term; }
- String getName() const { return functionName; }
- TermPtr resolve (const Scope& scope, int recursionDepth)
- {
- checkRecursionDepth (recursionDepth);
- double result = 0;
- const int numParams = parameters.size();
- if (numParams > 0)
- {
- HeapBlock<double> params ((size_t) numParams);
- for (int i = 0; i < numParams; ++i)
- params[i] = parameters.getReference(i).term->resolve (scope, recursionDepth + 1)->toDouble();
- result = scope.evaluateFunction (functionName, params, numParams);
- }
- else
- {
- result = scope.evaluateFunction (functionName, nullptr, 0);
- }
- return new Constant (result, false);
- }
- int getInputIndexFor (const Term* possibleInput) const
- {
- for (int i = 0; i < parameters.size(); ++i)
- if (parameters.getReference(i).term == possibleInput)
- return i;
- return -1;
- }
- String toString() const
- {
- if (parameters.size() == 0)
- return functionName + "()";
- String s (functionName + " (");
- for (int i = 0; i < parameters.size(); ++i)
- {
- s << parameters.getReference(i).term->toString();
- if (i < parameters.size() - 1)
- s << ", ";
- }
- s << ')';
- return s;
- }
- const String functionName;
- Array<Expression> parameters;
- };
- //==============================================================================
- class DotOperator : public BinaryTerm
- {
- public:
- DotOperator (SymbolTerm* const l, Term* const r) : BinaryTerm (l, r) {}
- TermPtr resolve (const Scope& scope, int recursionDepth)
- {
- checkRecursionDepth (recursionDepth);
- EvaluationVisitor visitor (right, recursionDepth + 1);
- scope.visitRelativeScope (getSymbol()->symbol, visitor);
- return visitor.output;
- }
- Term* clone() const { return new DotOperator (getSymbol(), right); }
- String getName() const { return "."; }
- int getOperatorPrecedence() const { return 1; }
- void writeOperator (String& dest) const { dest << '.'; }
- double performFunction (double, double) const { return 0.0; }
- void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
- {
- checkRecursionDepth (recursionDepth);
- visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->symbol));
- SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);
- try
- {
- scope.visitRelativeScope (getSymbol()->symbol, v);
- }
- catch (...) {}
- }
- void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
- {
- checkRecursionDepth (recursionDepth);
- getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth);
- SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1);
- try
- {
- scope.visitRelativeScope (getSymbol()->symbol, visitor);
- }
- catch (...) {}
- }
- private:
- //==============================================================================
- class EvaluationVisitor : public Scope::Visitor
- {
- public:
- EvaluationVisitor (const TermPtr& t, const int recursion)
- : input (t), output (t), recursionCount (recursion) {}
- void visit (const Scope& scope) { output = input->resolve (scope, recursionCount); }
- const TermPtr input;
- TermPtr output;
- const int recursionCount;
- private:
- JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor)
- };
- class SymbolVisitingVisitor : public Scope::Visitor
- {
- public:
- SymbolVisitingVisitor (const TermPtr& t, SymbolVisitor& v, const int recursion)
- : input (t), visitor (v), recursionCount (recursion) {}
- void visit (const Scope& scope) { input->visitAllSymbols (visitor, scope, recursionCount); }
- private:
- const TermPtr input;
- SymbolVisitor& visitor;
- const int recursionCount;
- JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor)
- };
- class SymbolRenamingVisitor : public Scope::Visitor
- {
- public:
- SymbolRenamingVisitor (const TermPtr& t, const Expression::Symbol& symbol_, const String& newName_, const int recursionCount_)
- : input (t), symbol (symbol_), newName (newName_), recursionCount (recursionCount_) {}
- void visit (const Scope& scope) { input->renameSymbol (symbol, newName, scope, recursionCount); }
- private:
- const TermPtr input;
- const Symbol& symbol;
- const String newName;
- const int recursionCount;
- JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor)
- };
- SymbolTerm* getSymbol() const { return static_cast <SymbolTerm*> (left.get()); }
- JUCE_DECLARE_NON_COPYABLE (DotOperator)
- };
- //==============================================================================
- class Negate : public Term
- {
- public:
- explicit Negate (const TermPtr& t) : input (t)
- {
- jassert (t != nullptr);
- }
- Type getType() const noexcept { return operatorType; }
- int getInputIndexFor (const Term* possibleInput) const { return possibleInput == input ? 0 : -1; }
- int getNumInputs() const { return 1; }
- Term* getInput (int index) const { return index == 0 ? input.get() : nullptr; }
- Term* clone() const { return new Negate (input->clone()); }
- TermPtr resolve (const Scope& scope, int recursionDepth)
- {
- return new Constant (-input->resolve (scope, recursionDepth)->toDouble(), false);
- }
- String getName() const { return "-"; }
- TermPtr negated() { return input; }
- TermPtr createTermToEvaluateInput (const Scope& scope, const Term* t, double overallTarget, Term* topLevelTerm) const
- {
- (void) t;
- jassert (t == input);
- const Term* const dest = findDestinationFor (topLevelTerm, this);
- return new Negate (dest == nullptr ? new Constant (overallTarget, false)
- : dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm));
- }
- String toString() const
- {
- if (input->getOperatorPrecedence() > 0)
- return "-(" + input->toString() + ")";
- return "-" + input->toString();
- }
- private:
- const TermPtr input;
- };
- //==============================================================================
- class Add : public BinaryTerm
- {
- public:
- Add (Term* const l, Term* const r) : BinaryTerm (l, r) {}
- Term* clone() const { return new Add (left->clone(), right->clone()); }
- double performFunction (double lhs, double rhs) const { return lhs + rhs; }
- int getOperatorPrecedence() const { return 3; }
- String getName() const { return "+"; }
- void writeOperator (String& dest) const { dest << " + "; }
- TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
- {
- const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
- if (newDest == nullptr)
- return TermPtr();
- return new Subtract (newDest, (input == left ? right : left)->clone());
- }
- private:
- JUCE_DECLARE_NON_COPYABLE (Add)
- };
- //==============================================================================
- class Subtract : public BinaryTerm
- {
- public:
- Subtract (Term* const l, Term* const r) : BinaryTerm (l, r) {}
- Term* clone() const { return new Subtract (left->clone(), right->clone()); }
- double performFunction (double lhs, double rhs) const { return lhs - rhs; }
- int getOperatorPrecedence() const { return 3; }
- String getName() const { return "-"; }
- void writeOperator (String& dest) const { dest << " - "; }
- TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
- {
- const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
- if (newDest == nullptr)
- return TermPtr();
- if (input == left)
- return new Add (newDest, right->clone());
- return new Subtract (left->clone(), newDest);
- }
- private:
- JUCE_DECLARE_NON_COPYABLE (Subtract)
- };
- //==============================================================================
- class Multiply : public BinaryTerm
- {
- public:
- Multiply (Term* const l, Term* const r) : BinaryTerm (l, r) {}
- Term* clone() const { return new Multiply (left->clone(), right->clone()); }
- double performFunction (double lhs, double rhs) const { return lhs * rhs; }
- String getName() const { return "*"; }
- void writeOperator (String& dest) const { dest << " * "; }
- int getOperatorPrecedence() const { return 2; }
- TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
- {
- const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
- if (newDest == nullptr)
- return TermPtr();
- return new Divide (newDest, (input == left ? right : left)->clone());
- }
- private:
- JUCE_DECLARE_NON_COPYABLE (Multiply)
- };
- //==============================================================================
- class Divide : public BinaryTerm
- {
- public:
- Divide (Term* const l, Term* const r) : BinaryTerm (l, r) {}
- Term* clone() const { return new Divide (left->clone(), right->clone()); }
- double performFunction (double lhs, double rhs) const { return lhs / rhs; }
- String getName() const { return "/"; }
- void writeOperator (String& dest) const { dest << " / "; }
- int getOperatorPrecedence() const { return 2; }
- TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
- {
- const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
- if (newDest == nullptr)
- return TermPtr();
- if (input == left)
- return new Multiply (newDest, right->clone());
- return new Divide (left->clone(), newDest);
- }
- private:
- JUCE_DECLARE_NON_COPYABLE (Divide)
- };
- //==============================================================================
- static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm)
- {
- const int inputIndex = topLevel->getInputIndexFor (inputTerm);
- if (inputIndex >= 0)
- return topLevel;
- for (int i = topLevel->getNumInputs(); --i >= 0;)
- {
- Term* const t = findDestinationFor (topLevel->getInput (i), inputTerm);
- if (t != nullptr)
- return t;
- }
- return nullptr;
- }
- static Constant* findTermToAdjust (Term* const term, const bool mustBeFlagged)
- {
- jassert (term != nullptr);
- if (term->getType() == constantType)
- {
- Constant* const c = static_cast<Constant*> (term);
- if (c->isResolutionTarget || ! mustBeFlagged)
- return c;
- }
- if (term->getType() == functionType)
- return nullptr;
- const int numIns = term->getNumInputs();
- for (int i = 0; i < numIns; ++i)
- {
- Term* const input = term->getInput (i);
- if (input->getType() == constantType)
- {
- Constant* const c = static_cast<Constant*> (input);
- if (c->isResolutionTarget || ! mustBeFlagged)
- return c;
- }
- }
- for (int i = 0; i < numIns; ++i)
- {
- Constant* const c = findTermToAdjust (term->getInput (i), mustBeFlagged);
- if (c != nullptr)
- return c;
- }
- return nullptr;
- }
- static bool containsAnySymbols (const Term* const t)
- {
- if (t->getType() == Expression::symbolType)
- return true;
- for (int i = t->getNumInputs(); --i >= 0;)
- if (containsAnySymbols (t->getInput (i)))
- return true;
- return false;
- }
- //==============================================================================
- class SymbolCheckVisitor : public Term::SymbolVisitor
- {
- public:
- SymbolCheckVisitor (const Symbol& symbol_) : wasFound (false), symbol (symbol_) {}
- void useSymbol (const Symbol& s) { wasFound = wasFound || s == symbol; }
- bool wasFound;
- private:
- const Symbol& symbol;
- JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor)
- };
- //==============================================================================
- class SymbolListVisitor : public Term::SymbolVisitor
- {
- public:
- SymbolListVisitor (Array<Symbol>& list_) : list (list_) {}
- void useSymbol (const Symbol& s) { list.addIfNotAlreadyThere (s); }
- private:
- Array<Symbol>& list;
- JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor)
- };
- //==============================================================================
- class Parser
- {
- public:
- //==============================================================================
- Parser (String::CharPointerType& stringToParse)
- : text (stringToParse)
- {
- }
- TermPtr readUpToComma()
- {
- if (text.isEmpty())
- return new Constant (0.0, false);
- const TermPtr e (readExpression());
- if (e == nullptr || ((! readOperator (",")) && ! text.isEmpty()))
- throw ParseError ("Syntax error: \"" + String (text) + "\"");
- return e;
- }
- private:
- String::CharPointerType& text;
- //==============================================================================
- static inline bool isDecimalDigit (const juce_wchar c) noexcept
- {
- return c >= '0' && c <= '9';
- }
- bool readChar (const juce_wchar required) noexcept
- {
- if (*text == required)
- {
- ++text;
- return true;
- }
- return false;
- }
- bool readOperator (const char* ops, char* const opType = nullptr) noexcept
- {
- text = text.findEndOfWhitespace();
- while (*ops != 0)
- {
- if (readChar ((juce_wchar) (uint8) *ops))
- {
- if (opType != nullptr)
- *opType = *ops;
- return true;
- }
- ++ops;
- }
- return false;
- }
- bool readIdentifier (String& identifier) noexcept
- {
- text = text.findEndOfWhitespace();
- String::CharPointerType t (text);
- int numChars = 0;
- if (t.isLetter() || *t == '_')
- {
- ++t;
- ++numChars;
- while (t.isLetterOrDigit() || *t == '_')
- {
- ++t;
- ++numChars;
- }
- }
- if (numChars > 0)
- {
- identifier = String (text, (size_t) numChars);
- text = t;
- return true;
- }
- return false;
- }
- Term* readNumber() noexcept
- {
- text = text.findEndOfWhitespace();
- String::CharPointerType t (text);
- const bool isResolutionTarget = (*t == '@');
- if (isResolutionTarget)
- {
- ++t;
- t = t.findEndOfWhitespace();
- text = t;
- }
- if (*t == '-')
- {
- ++t;
- t = t.findEndOfWhitespace();
- }
- if (isDecimalDigit (*t) || (*t == '.' && isDecimalDigit (t[1])))
- return new Constant (CharacterFunctions::readDoubleValue (text), isResolutionTarget);
- return nullptr;
- }
- TermPtr readExpression()
- {
- TermPtr lhs (readMultiplyOrDivideExpression());
- char opType;
- while (lhs != nullptr && readOperator ("+-", &opType))
- {
- TermPtr rhs (readMultiplyOrDivideExpression());
- if (rhs == nullptr)
- throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
- if (opType == '+')
- lhs = new Add (lhs, rhs);
- else
- lhs = new Subtract (lhs, rhs);
- }
- return lhs;
- }
- TermPtr readMultiplyOrDivideExpression()
- {
- TermPtr lhs (readUnaryExpression());
- char opType;
- while (lhs != nullptr && readOperator ("*/", &opType))
- {
- TermPtr rhs (readUnaryExpression());
- if (rhs == nullptr)
- throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
- if (opType == '*')
- lhs = new Multiply (lhs, rhs);
- else
- lhs = new Divide (lhs, rhs);
- }
- return lhs;
- }
- TermPtr readUnaryExpression()
- {
- char opType;
- if (readOperator ("+-", &opType))
- {
- TermPtr e (readUnaryExpression());
- if (e == nullptr)
- throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");
- if (opType == '-')
- e = e->negated();
- return e;
- }
- return readPrimaryExpression();
- }
- TermPtr readPrimaryExpression()
- {
- TermPtr e (readParenthesisedExpression());
- if (e != nullptr)
- return e;
- e = readNumber();
- if (e != nullptr)
- return e;
- return readSymbolOrFunction();
- }
- TermPtr readSymbolOrFunction()
- {
- String identifier;
- if (readIdentifier (identifier))
- {
- if (readOperator ("(")) // method call...
- {
- Function* const f = new Function (identifier);
- ScopedPointer<Term> func (f); // (can't use ScopedPointer<Function> in MSVC)
- TermPtr param (readExpression());
- if (param == nullptr)
- {
- if (readOperator (")"))
- return func.release();
- throw ParseError ("Expected parameters after \"" + identifier + " (\"");
- }
- f->parameters.add (Expression (param));
- while (readOperator (","))
- {
- param = readExpression();
- if (param == nullptr)
- throw ParseError ("Expected expression after \",\"");
- f->parameters.add (Expression (param));
- }
- if (readOperator (")"))
- return func.release();
- throw ParseError ("Expected \")\"");
- }
- if (readOperator ("."))
- {
- TermPtr rhs (readSymbolOrFunction());
- if (rhs == nullptr)
- throw ParseError ("Expected symbol or function after \".\"");
- if (identifier == "this")
- return rhs;
- return new DotOperator (new SymbolTerm (identifier), rhs);
- }
- // just a symbol..
- jassert (identifier.trim() == identifier);
- return new SymbolTerm (identifier);
- }
- return TermPtr();
- }
- TermPtr readParenthesisedExpression()
- {
- if (! readOperator ("("))
- return TermPtr();
- const TermPtr e (readExpression());
- if (e == nullptr || ! readOperator (")"))
- return TermPtr();
- return e;
- }
- JUCE_DECLARE_NON_COPYABLE (Parser)
- };
- };
- //==============================================================================
- Expression::Expression()
- : term (new Expression::Helpers::Constant (0, false))
- {
- }
- Expression::~Expression()
- {
- }
- Expression::Expression (Term* const term_)
- : term (term_)
- {
- jassert (term != nullptr);
- }
- Expression::Expression (const double constant)
- : term (new Expression::Helpers::Constant (constant, false))
- {
- }
- Expression::Expression (const Expression& other)
- : term (other.term)
- {
- }
- Expression& Expression::operator= (const Expression& other)
- {
- term = other.term;
- return *this;
- }
- #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
- Expression::Expression (Expression&& other) noexcept
- : term (static_cast <ReferenceCountedObjectPtr<Term>&&> (other.term))
- {
- }
- Expression& Expression::operator= (Expression&& other) noexcept
- {
- term = static_cast <ReferenceCountedObjectPtr<Term>&&> (other.term);
- return *this;
- }
- #endif
- Expression::Expression (const String& stringToParse)
- {
- String::CharPointerType text (stringToParse.getCharPointer());
- Helpers::Parser parser (text);
- term = parser.readUpToComma();
- }
- Expression Expression::parse (String::CharPointerType& stringToParse)
- {
- Helpers::Parser parser (stringToParse);
- return Expression (parser.readUpToComma());
- }
- double Expression::evaluate() const
- {
- return evaluate (Expression::Scope());
- }
- double Expression::evaluate (const Expression::Scope& scope) const
- {
- try
- {
- return term->resolve (scope, 0)->toDouble();
- }
- catch (Helpers::EvaluationError&)
- {}
- return 0;
- }
- double Expression::evaluate (const Scope& scope, String& evaluationError) const
- {
- try
- {
- return term->resolve (scope, 0)->toDouble();
- }
- catch (Helpers::EvaluationError& e)
- {
- evaluationError = e.description;
- }
- return 0;
- }
- Expression Expression::operator+ (const Expression& other) const { return Expression (new Helpers::Add (term, other.term)); }
- Expression Expression::operator- (const Expression& other) const { return Expression (new Helpers::Subtract (term, other.term)); }
- Expression Expression::operator* (const Expression& other) const { return Expression (new Helpers::Multiply (term, other.term)); }
- Expression Expression::operator/ (const Expression& other) const { return Expression (new Helpers::Divide (term, other.term)); }
- Expression Expression::operator-() const { return Expression (term->negated()); }
- Expression Expression::symbol (const String& symbol) { return Expression (new Helpers::SymbolTerm (symbol)); }
- Expression Expression::function (const String& functionName, const Array<Expression>& parameters)
- {
- return Expression (new Helpers::Function (functionName, parameters));
- }
- Expression Expression::adjustedToGiveNewResult (const double targetValue, const Expression::Scope& scope) const
- {
- ScopedPointer<Term> newTerm (term->clone());
- Helpers::Constant* termToAdjust = Helpers::findTermToAdjust (newTerm, true);
- if (termToAdjust == nullptr)
- termToAdjust = Helpers::findTermToAdjust (newTerm, false);
- if (termToAdjust == nullptr)
- {
- newTerm = new Helpers::Add (newTerm.release(), new Helpers::Constant (0, false));
- termToAdjust = Helpers::findTermToAdjust (newTerm, false);
- }
- jassert (termToAdjust != nullptr);
- const Term* const parent = Helpers::findDestinationFor (newTerm, termToAdjust);
- if (parent == nullptr)
- {
- termToAdjust->value = targetValue;
- }
- else
- {
- const Helpers::TermPtr reverseTerm (parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm));
- if (reverseTerm == nullptr)
- return Expression (targetValue);
- termToAdjust->value = reverseTerm->resolve (scope, 0)->toDouble();
- }
- return Expression (newTerm.release());
- }
- Expression Expression::withRenamedSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Scope& scope) const
- {
- jassert (newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
- if (oldSymbol.symbolName == newName)
- return *this;
- Expression e (term->clone());
- e.term->renameSymbol (oldSymbol, newName, scope, 0);
- return e;
- }
- bool Expression::referencesSymbol (const Expression::Symbol& symbolToCheck, const Scope& scope) const
- {
- Helpers::SymbolCheckVisitor visitor (symbolToCheck);
- try
- {
- term->visitAllSymbols (visitor, scope, 0);
- }
- catch (Helpers::EvaluationError&)
- {}
- return visitor.wasFound;
- }
- void Expression::findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const
- {
- try
- {
- Helpers::SymbolListVisitor visitor (results);
- term->visitAllSymbols (visitor, scope, 0);
- }
- catch (Helpers::EvaluationError&)
- {}
- }
- String Expression::toString() const { return term->toString(); }
- bool Expression::usesAnySymbols() const { return Helpers::containsAnySymbols (term); }
- Expression::Type Expression::getType() const noexcept { return term->getType(); }
- String Expression::getSymbolOrFunction() const { return term->getName(); }
- int Expression::getNumInputs() const { return term->getNumInputs(); }
- Expression Expression::getInput (int index) const { return Expression (term->getInput (index)); }
- //==============================================================================
- ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated()
- {
- return new Helpers::Negate (this);
- }
- //==============================================================================
- Expression::ParseError::ParseError (const String& message)
- : description (message)
- {
- DBG ("Expression::ParseError: " + message);
- }
- //==============================================================================
- Expression::Symbol::Symbol (const String& scopeUID_, const String& symbolName_)
- : scopeUID (scopeUID_), symbolName (symbolName_)
- {
- }
- bool Expression::Symbol::operator== (const Symbol& other) const noexcept
- {
- return symbolName == other.symbolName && scopeUID == other.scopeUID;
- }
- bool Expression::Symbol::operator!= (const Symbol& other) const noexcept
- {
- return ! operator== (other);
- }
- //==============================================================================
- Expression::Scope::Scope() {}
- Expression::Scope::~Scope() {}
- Expression Expression::Scope::getSymbolValue (const String& symbol) const
- {
- if (symbol.isNotEmpty())
- throw Helpers::EvaluationError ("Unknown symbol: " + symbol);
- return Expression();
- }
- double Expression::Scope::evaluateFunction (const String& functionName, const double* parameters, int numParams) const
- {
- if (numParams > 0)
- {
- if (functionName == "min")
- {
- double v = parameters[0];
- for (int i = 1; i < numParams; ++i)
- v = jmin (v, parameters[i]);
- return v;
- }
- if (functionName == "max")
- {
- double v = parameters[0];
- for (int i = 1; i < numParams; ++i)
- v = jmax (v, parameters[i]);
- return v;
- }
- if (numParams == 1)
- {
- if (functionName == "sin") return sin (parameters[0]);
- if (functionName == "cos") return cos (parameters[0]);
- if (functionName == "tan") return tan (parameters[0]);
- if (functionName == "abs") return std::abs (parameters[0]);
- }
- }
- throw Helpers::EvaluationError ("Unknown function: \"" + functionName + "\"");
- }
- void Expression::Scope::visitRelativeScope (const String& scopeName, Visitor&) const
- {
- throw Helpers::EvaluationError ("Unknown symbol: " + scopeName);
- }
- String Expression::Scope::getScopeUID() const
- {
- return String();
- }
|