| @@ -656,8 +656,7 @@ struct Expression::Helpers | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| Parser (String::CharPointerType& stringToParse) | |||
| : text (stringToParse) | |||
| Parser (String::CharPointerType& stringToParse) : text (stringToParse) | |||
| { | |||
| } | |||
| @@ -669,14 +668,24 @@ struct Expression::Helpers | |||
| const TermPtr e (readExpression()); | |||
| if (e == nullptr || ((! readOperator (",")) && ! text.isEmpty())) | |||
| throw ParseError ("Syntax error: \"" + String (text) + "\""); | |||
| return parseError ("Syntax error: \"" + String (text) + "\""); | |||
| return e; | |||
| } | |||
| String error; | |||
| private: | |||
| String::CharPointerType& text; | |||
| Term* parseError (const String& message) | |||
| { | |||
| if (error.isEmpty()) | |||
| error = message; | |||
| return nullptr; | |||
| } | |||
| //============================================================================== | |||
| static inline bool isDecimalDigit (const juce_wchar c) noexcept | |||
| { | |||
| @@ -777,7 +786,7 @@ struct Expression::Helpers | |||
| TermPtr rhs (readMultiplyOrDivideExpression()); | |||
| if (rhs == nullptr) | |||
| throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\""); | |||
| return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\""); | |||
| if (opType == '+') | |||
| lhs = new Add (lhs, rhs); | |||
| @@ -798,7 +807,7 @@ struct Expression::Helpers | |||
| TermPtr rhs (readUnaryExpression()); | |||
| if (rhs == nullptr) | |||
| throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\""); | |||
| return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\""); | |||
| if (opType == '*') | |||
| lhs = new Multiply (lhs, rhs); | |||
| @@ -817,7 +826,7 @@ struct Expression::Helpers | |||
| TermPtr e (readUnaryExpression()); | |||
| if (e == nullptr) | |||
| throw ParseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\""); | |||
| return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\""); | |||
| if (opType == '-') | |||
| e = e->negated(); | |||
| @@ -858,7 +867,7 @@ struct Expression::Helpers | |||
| if (readOperator (")")) | |||
| return func.release(); | |||
| throw ParseError ("Expected parameters after \"" + identifier + " (\""); | |||
| return parseError ("Expected parameters after \"" + identifier + " (\""); | |||
| } | |||
| f->parameters.add (Expression (param)); | |||
| @@ -868,7 +877,7 @@ struct Expression::Helpers | |||
| param = readExpression(); | |||
| if (param == nullptr) | |||
| throw ParseError ("Expected expression after \",\""); | |||
| return parseError ("Expected expression after \",\""); | |||
| f->parameters.add (Expression (param)); | |||
| } | |||
| @@ -876,7 +885,7 @@ struct Expression::Helpers | |||
| if (readOperator (")")) | |||
| return func.release(); | |||
| throw ParseError ("Expected \")\""); | |||
| return parseError ("Expected \")\""); | |||
| } | |||
| if (readOperator (".")) | |||
| @@ -884,7 +893,7 @@ struct Expression::Helpers | |||
| TermPtr rhs (readSymbolOrFunction()); | |||
| if (rhs == nullptr) | |||
| throw ParseError ("Expected symbol or function after \".\""); | |||
| return parseError ("Expected symbol or function after \".\""); | |||
| if (identifier == "this") | |||
| return rhs; | |||
| @@ -926,8 +935,7 @@ Expression::~Expression() | |||
| { | |||
| } | |||
| Expression::Expression (Term* const term_) | |||
| : term (term_) | |||
| Expression::Expression (Term* t) : term (t) | |||
| { | |||
| jassert (term != nullptr); | |||
| } | |||
| @@ -961,17 +969,20 @@ Expression& Expression::operator= (Expression&& other) noexcept | |||
| } | |||
| #endif | |||
| Expression::Expression (const String& stringToParse) | |||
| Expression::Expression (const String& stringToParse, String& parseError) | |||
| { | |||
| String::CharPointerType text (stringToParse.getCharPointer()); | |||
| Helpers::Parser parser (text); | |||
| term = parser.readUpToComma(); | |||
| parseError = parser.error; | |||
| } | |||
| Expression Expression::parse (String::CharPointerType& stringToParse) | |||
| Expression Expression::parse (String::CharPointerType& stringToParse, String& parseError) | |||
| { | |||
| Helpers::Parser parser (stringToParse); | |||
| return Expression (parser.readUpToComma()); | |||
| Expression e (parser.readUpToComma()); | |||
| parseError = parser.error; | |||
| return e; | |||
| } | |||
| double Expression::evaluate() const | |||
| @@ -981,14 +992,7 @@ double Expression::evaluate() const | |||
| double Expression::evaluate (const Expression::Scope& scope) const | |||
| { | |||
| try | |||
| { | |||
| return term->resolve (scope, 0)->toDouble(); | |||
| } | |||
| catch (Helpers::EvaluationError&) | |||
| {} | |||
| return 0; | |||
| return term->resolve (scope, 0)->toDouble(); | |||
| } | |||
| double Expression::evaluate (const Scope& scope, String& evaluationError) const | |||
| @@ -1104,15 +1108,8 @@ ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated() | |||
| } | |||
| //============================================================================== | |||
| 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_) | |||
| Expression::Symbol::Symbol (const String& scope, const String& symbol) | |||
| : scopeUID (scope), symbolName (symbol) | |||
| { | |||
| } | |||
| @@ -55,9 +55,6 @@ public: | |||
| /** Destructor. */ | |||
| ~Expression(); | |||
| /** Creates a simple expression with a specified constant value. */ | |||
| explicit Expression (double constant); | |||
| /** Creates a copy of an expression. */ | |||
| Expression (const Expression&); | |||
| @@ -69,11 +66,13 @@ public: | |||
| Expression& operator= (Expression&&) noexcept; | |||
| #endif | |||
| /** Creates an expression by parsing a string. | |||
| If there's a syntax error in the string, this will throw a ParseError exception. | |||
| @throws ParseError | |||
| /** Creates a simple expression with a specified constant value. */ | |||
| explicit Expression (double constant); | |||
| /** Attempts to create an expression by parsing a string. | |||
| Any errors are returned in the parseError argument provided. | |||
| */ | |||
| explicit Expression (const String& stringToParse); | |||
| Expression (const String& stringToParse, String& parseError); | |||
| /** Returns a string version of the expression. */ | |||
| String toString() const; | |||
| @@ -101,10 +100,10 @@ public: | |||
| The pointer is incremented so that on return, it indicates the character that follows | |||
| the end of the expression that was parsed. | |||
| If there's a syntax error in the string, this will throw a ParseError exception. | |||
| @throws ParseError | |||
| If there's a syntax error in parsing, the parseError argument will be set | |||
| to a description of the problem. | |||
| */ | |||
| static Expression parse (String::CharPointerType& stringToParse); | |||
| static Expression parse (String::CharPointerType& stringToParse, String& parseError); | |||
| //============================================================================== | |||
| /** When evaluating an Expression object, this class is used to resolve symbols and | |||
| @@ -216,16 +215,6 @@ public: | |||
| /** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */ | |||
| void findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const; | |||
| //============================================================================== | |||
| /** An exception that can be thrown by Expression::parse(). */ | |||
| class ParseError : public std::exception | |||
| { | |||
| public: | |||
| ParseError (const String& message); | |||
| String description; | |||
| }; | |||
| //============================================================================== | |||
| /** Expression type. | |||
| @see Expression::getType() | |||
| @@ -87,12 +87,8 @@ RelativeCoordinate::RelativeCoordinate (const double absoluteDistanceFromOrigin) | |||
| RelativeCoordinate::RelativeCoordinate (const String& s) | |||
| { | |||
| try | |||
| { | |||
| term = Expression (s); | |||
| } | |||
| catch (Expression::ParseError&) | |||
| {} | |||
| String error; | |||
| term = Expression (s, error); | |||
| } | |||
| RelativeCoordinate::~RelativeCoordinate() | |||
| @@ -111,52 +107,35 @@ bool RelativeCoordinate::operator!= (const RelativeCoordinate& other) const noex | |||
| double RelativeCoordinate::resolve (const Expression::Scope* scope) const | |||
| { | |||
| try | |||
| { | |||
| if (scope != nullptr) | |||
| return term.evaluate (*scope); | |||
| if (scope != nullptr) | |||
| return term.evaluate (*scope); | |||
| return term.evaluate(); | |||
| } | |||
| catch (Expression::ParseError&) | |||
| {} | |||
| return 0.0; | |||
| return term.evaluate(); | |||
| } | |||
| bool RelativeCoordinate::isRecursive (const Expression::Scope* scope) const | |||
| { | |||
| try | |||
| { | |||
| if (scope != nullptr) | |||
| term.evaluate (*scope); | |||
| else | |||
| term.evaluate(); | |||
| } | |||
| catch (Expression::ParseError&) | |||
| { | |||
| return true; | |||
| } | |||
| String error; | |||
| return false; | |||
| if (scope != nullptr) | |||
| term.evaluate (*scope, error); | |||
| else | |||
| term.evaluate (Expression::Scope(), error); | |||
| return error.isNotEmpty(); | |||
| } | |||
| void RelativeCoordinate::moveToAbsolute (double newPos, const Expression::Scope* scope) | |||
| { | |||
| try | |||
| if (scope != nullptr) | |||
| { | |||
| term = term.adjustedToGiveNewResult (newPos, *scope); | |||
| } | |||
| else | |||
| { | |||
| if (scope != nullptr) | |||
| { | |||
| term = term.adjustedToGiveNewResult (newPos, *scope); | |||
| } | |||
| else | |||
| { | |||
| Expression::Scope defaultScope; | |||
| term = term.adjustedToGiveNewResult (newPos, defaultScope); | |||
| } | |||
| Expression::Scope defaultScope; | |||
| term = term.adjustedToGiveNewResult (newPos, defaultScope); | |||
| } | |||
| catch (Expression::ParseError&) | |||
| {} | |||
| } | |||
| bool RelativeCoordinate::isDynamic() const | |||
| @@ -55,10 +55,11 @@ RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordi | |||
| RelativePoint::RelativePoint (const String& s) | |||
| { | |||
| String error; | |||
| String::CharPointerType text (s.getCharPointer()); | |||
| x = RelativeCoordinate (Expression::parse (text)); | |||
| x = RelativeCoordinate (Expression::parse (text, error)); | |||
| RelativePointHelpers::skipComma (text); | |||
| y = RelativeCoordinate (Expression::parse (text)); | |||
| y = RelativeCoordinate (Expression::parse (text, error)); | |||
| } | |||
| bool RelativePoint::operator== (const RelativePoint& other) const noexcept | |||
| @@ -84,14 +84,15 @@ RelativeRectangle::RelativeRectangle (const Rectangle<float>& rect) | |||
| RelativeRectangle::RelativeRectangle (const String& s) | |||
| { | |||
| String error; | |||
| String::CharPointerType text (s.getCharPointer()); | |||
| left = RelativeCoordinate (Expression::parse (text)); | |||
| left = RelativeCoordinate (Expression::parse (text, error)); | |||
| RelativeRectangleHelpers::skipComma (text); | |||
| top = RelativeCoordinate (Expression::parse (text)); | |||
| top = RelativeCoordinate (Expression::parse (text, error)); | |||
| RelativeRectangleHelpers::skipComma (text); | |||
| right = RelativeCoordinate (Expression::parse (text)); | |||
| right = RelativeCoordinate (Expression::parse (text, error)); | |||
| RelativeRectangleHelpers::skipComma (text); | |||
| bottom = RelativeCoordinate (Expression::parse (text)); | |||
| bottom = RelativeCoordinate (Expression::parse (text, error)); | |||
| } | |||
| bool RelativeRectangle::operator== (const RelativeRectangle& other) const noexcept | |||