[poincare] Escape when recursion too deep

This commit is contained in:
Léa Saviot
2018-11-08 15:12:02 +01:00
committed by Émilie Feral
parent 54b2566b04
commit cb678e370e
3 changed files with 84 additions and 8 deletions

View File

@@ -90,7 +90,11 @@ class Expression : public TreeHandle {
friend class SymbolNode;
public:
static void TidyAfterException() {
UnlockRecursionCountReset();
}
static bool isExpression() { return true; }
/* Constructor & Destructor */
Expression() : TreeHandle() {}
Expression clone() const;
@@ -253,6 +257,11 @@ protected:
private:
/* Simplification */
static constexpr int sRecursionLimit = 2000; //TODO value?
static bool ResetRecursionCountAndLockReset();
static void UnlockRecursionCountReset();
static void IncrementRecursionCount();
static bool RecursionMaximalDepthExceeded();
Expression deepReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols = true);
void deepReduceChildren(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols) {
return node()->deepReduceChildren(context, angleUnit, replaceSymbols);

View File

@@ -13,6 +13,9 @@
namespace Poincare {
static int sRecursionCount = 0;
static bool sRecursionCountReinitializationIsLocked = false;
/* Constructor & Destructor */
Expression Expression::clone() const { TreeHandle c = TreeHandle::clone(); return static_cast<Expression&>(c); }
@@ -75,15 +78,32 @@ bool Expression::isRationalOne() const {
}
bool Expression::recursivelyMatches(ExpressionTest test, Context & context) const {
if (test(*this, context)) {
return true;
}
for (int i = 0; i < this->numberOfChildren(); i++) {
if (childAtIndex(i).recursivelyMatches(test, context)) {
return true;
// Reset recursion count if needed
bool willHaveToUnlock = ResetRecursionCountAndLockReset();
bool result = false;
IncrementRecursionCount();
if (RecursionMaximalDepthExceeded()) {
//TODO propagate recursion error?
} else {
if (test(*this, context)) {
result = true;
} else {
for (int i = 0; i < this->numberOfChildren(); i++) {
if (childAtIndex(i).recursivelyMatches(test, context)) {
result = true;
break;
}
}
}
}
return false;
// Unlock recursion count reset if needed
if (willHaveToUnlock) {
UnlockRecursionCountReset();
}
return result;
}
bool Expression::isApproximate(Context & context) const {
@@ -223,6 +243,11 @@ void Expression::defaultSetChildrenInPlace(Expression other) {
template<typename U>
Evaluation<U> Expression::approximateToEvaluation(Context& context, Preferences::AngleUnit angleUnit) const {
assert(sRecursionCountReinitializationIsLocked == true);
IncrementRecursionCount();
if (RecursionMaximalDepthExceeded()) {
return Complex<U>::Undefined(); // TODO Propagate error "Recursion too deep"
}
return node()->approximate(U(), context, angleUnit);
}
@@ -309,10 +334,47 @@ Expression Expression::simplify(Context & context, Preferences::AngleUnit angleU
}
Expression Expression::reduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols) {
return deepReduce(context, angleUnit, replaceSymbols);
// Reset recursion count if needed
bool willHaveToUnlock = ResetRecursionCountAndLockReset();
Expression result = deepReduce(context, angleUnit, replaceSymbols);
// Unlock recursion count reinitialization if needed
if (willHaveToUnlock) {
UnlockRecursionCountReset();
}
return result;
}
bool Expression::ResetRecursionCountAndLockReset() {
if (!sRecursionCountReinitializationIsLocked) {
sRecursionCount = 0;
sRecursionCountReinitializationIsLocked = true;
return true;
}
return false;
}
void Expression::UnlockRecursionCountReset() {
sRecursionCountReinitializationIsLocked = false;
}
void Expression::IncrementRecursionCount() {
sRecursionCount++;
}
bool Expression::RecursionMaximalDepthExceeded() {
return sRecursionCount >= Expression::sRecursionLimit;
}
Expression Expression::deepReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols) {
IncrementRecursionCount();
if (RecursionMaximalDepthExceeded()) {
sSimplificationHasBeenInterrupted = true;
return *this;
}
#if MATRIX_EXACT_REDUCING
#else
if (IsMatrix(*this, context)) {
@@ -320,6 +382,7 @@ Expression Expression::deepReduce(Context & context, Preferences::AngleUnit angl
return *this;
}
#endif
deepReduceChildren(context, angleUnit, replaceSymbols);
return shallowReduce(context, angleUnit, replaceSymbols);
}

View File

@@ -1,4 +1,5 @@
#include <poincare/init.h>
#include <poincare/expression.h>
#include <poincare/integer.h>
#include <poincare/tree_pool.h>
@@ -13,6 +14,9 @@ void Init() {
void Tidy() {
// Clean Integer
Integer::TidyIntegerBuffer();
// Unlock recursion count
Expression::TidyAfterException();
}
}