Improve error handling by displaying an error message (#1075)

* wire up error messages

* more errors

* fix crash on render error

* Always show copy and cut

* PR comments

* Fix spelling
This commit is contained in:
Pepe Rivera
2020-03-25 15:18:34 -07:00
committed by GitHub
parent 7b51b45906
commit fc19ddcbcb
15 changed files with 582 additions and 32 deletions

View File

@@ -297,6 +297,8 @@ namespace GraphControl
{
optional<vector<shared_ptr<IEquation>>> initResult = nullopt;
bool successful = false;
m_errorCode = 0;
m_errorType = 0;
if (m_renderMain && m_graph != nullptr)
{
@@ -345,7 +347,7 @@ namespace GraphControl
parsableEquation += s_getGraphClosingTags;
// Wire up the corresponding error to an error message in the UI at some point
if (!(expr = m_solver->ParseInput(parsableEquation)))
if (!(expr = m_solver->ParseInput(parsableEquation, m_errorCode, m_errorType)))
{
co_return false;
}
@@ -356,7 +358,7 @@ namespace GraphControl
request += s_getGraphClosingTags;
}
if (graphExpression = m_solver->ParseInput(request))
if (graphExpression = m_solver->ParseInput(request, m_errorCode, m_errorType))
{
initResult = TryInitializeGraph(keepCurrentView, graphExpression.get());
@@ -386,8 +388,13 @@ namespace GraphControl
// If we failed to render then we have already lost the previous graph
shouldKeepPreviousGraph = false;
initResult = nullopt;
m_solver->HRErrorToErrorInfo(m_renderMain->GetRenderError(), m_errorCode, m_errorType);
}
}
else
{
m_solver->HRErrorToErrorInfo(m_graph->GetInitializationError(), m_errorCode, m_errorType);
}
}
if (initResult == nullopt)
@@ -398,7 +405,7 @@ namespace GraphControl
initResult = m_graph->TryInitialize();
if (initResult != nullopt)
{
UpdateGraphOptions(m_graph->GetOptions(), validEqs);
UpdateGraphOptions(m_graph->GetOptions(), vector<Equation^>());
SetGraphArgs(m_graph);
m_renderMain->Graph = m_graph;
@@ -431,6 +438,8 @@ namespace GraphControl
{
if (!eq->IsValidated)
{
eq->GraphErrorType = static_cast<ErrorType>(m_errorType);
eq->GraphErrorCode = m_errorCode;
eq->HasGraphError = true;
}
}
@@ -457,7 +466,7 @@ namespace GraphControl
request += equation->GetRequest()->Data();
request += s_getGraphClosingTags;
if (unique_ptr<IExpression> graphExpression = m_solver->ParseInput(request))
if (unique_ptr<IExpression> graphExpression = m_solver->ParseInput(request, m_errorCode, m_errorType))
{
if (graph->TryInitialize(graphExpression.get()))
{
@@ -524,7 +533,7 @@ namespace GraphControl
m_graph->SetArgValue(variableName->Data(), newValue);
m_renderMain->GetCriticalSection().unlock();
m_renderMain->RunRenderPassAsync();
m_renderMain->RunRenderPass();
});
ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::None);
@@ -549,7 +558,7 @@ namespace GraphControl
auto lineColor = eq->LineColor;
graphColors.emplace_back(lineColor.R, lineColor.G, lineColor.B, lineColor.A);
if (eq->IsSelected)
if (eq->GraphedEquation != nullptr && !eq->HasGraphError && eq->IsSelected)
{
eq->GraphedEquation->TrySelectEquation();
}
@@ -1001,7 +1010,7 @@ String ^ Grapher::ConvertToLinear(String ^ mmlString)
{
m_solver->FormatOptions().SetFormatType(FormatType::LinearInput);
auto expression = m_solver->ParseInput(mmlString->Data());
auto expression = m_solver->ParseInput(mmlString->Data(), m_errorCode, m_errorType);
auto linearExpression = m_solver->Serialize(expression.get());
m_solver->FormatOptions().SetFormatType(s_defaultFormatType);
@@ -1011,7 +1020,7 @@ String ^ Grapher::ConvertToLinear(String ^ mmlString)
String ^ Grapher::FormatMathML(String ^ mmlString)
{
auto expression = m_solver->ParseInput(mmlString->Data());
auto expression = m_solver->ParseInput(mmlString->Data(), m_errorCode, m_errorType);
auto formattedExpression = m_solver->Serialize(expression.get());
return ref new String(formattedExpression.c_str());
}

View File

@@ -335,6 +335,8 @@ public
bool m_Moving;
Windows::UI::Xaml::DispatcherTimer ^ m_TracingTrackingTimer;
Windows::UI::Core::CoreCursor ^ m_cachedCursor;
int m_errorType;
int m_errorCode;
public:
Windows::Storage::Streams::RandomAccessStreamReference ^ GetGraphBitmapStream();

View File

@@ -274,7 +274,9 @@ namespace GraphControl::DX
pRenderTarget->BeginDraw();
bool hasMissingData = false;
successful = SUCCEEDED(renderer->DrawD2D1(pFactory, pRenderTarget, hasMissingData));
m_HResult = renderer->DrawD2D1(pFactory, pRenderTarget, hasMissingData);
successful = SUCCEEDED(m_HResult);
// We ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
// is lost. It will be handled during the next call to Present.
@@ -345,6 +347,11 @@ namespace GraphControl::DX
return successful;
}
HRESULT RenderMain::GetRenderError()
{
return m_HResult;
}
void RenderMain::OnLoaded(Object ^ sender, RoutedEventArgs ^ e)
{
RunRenderPass();

View File

@@ -61,6 +61,8 @@ namespace GraphControl::DX
return m_isRenderPassSuccesful;
}
HRESULT GetRenderError();
// Indicates if we are in active tracing mode (the tracing box is being used and controlled through keyboard input)
property bool ActiveTracing
{
@@ -189,5 +191,7 @@ namespace GraphControl::DX
Windows::Foundation::IAsyncAction ^ m_renderPass = nullptr;
bool m_isRenderPassSuccesful;
HRESULT m_HResult;
};
}

View File

@@ -7,6 +7,200 @@
namespace GraphControl
{
public enum class ErrorType
{
Evaluation,
Syntax,
Abort,
};
public enum class EvaluationErrorCode
{
// Number is too large. To see this error, assign a large number to variable a, then keep doing "a:=a*a" until it happens
Overflow = 2,
// doing trig in calculus and current mode is not Radians
RequireRadiansMode = 3,
// This is actually abort code generated as time limit reached.
TooComplexToSolve = 4,
// degree sign present and the current mode is not Degrees
RequireDegreesMode = 5,
// n! and n is not an non-negative integer or m/2
FactorialInvalidArgument = -1,
// n!! and n is not an non-negative integer or odd negative integers
Factorial2InvalidArgument = -2,
// n! and n is too big
FactorialCannotPerformOnLargeNumber = -3,
// x mod y, and one of them is not an integer
ModuloCannotPerformOnFloat = -5,
// below are equation solving specific errors
// example1: sin(x)+x=2 example2: x^4-x^3-8x=9
EquationTooComplexToSolveSymbolic = -7,
// example1: x-x=3 example2: x^2=-1
EquationHasNoSolution = -8,
// only used for numeric solve where the algorithm doesn't converge
EquationTooComplexToSolve = -9,
// used when equation cannot be ploted
EquationTooComplexToPlot = -10,
// example1: 1/0
DivideByZero = -15,
// the inequality is too complex for the engine to solve
InequalityTooComplexToSolve = -41,
// the inequality has no solution
InequalityHasNoSolution = -42,
// An exression contains logical conditions that are mutually exclusive
MutuallyExclusiveConditions = -43,
// Arbitrary Precision Evaluation input is out of domain
OutOfDomain = -101,
// Not supported.
GE_NotSupported = -503,
// General error for graphing engine
GE_GeneralError = -504,
// Failed to calculate
GE_TooComplexToSolve = -506,
};
public enum class SyntaxErrorCode
{
// found ) without matching (
ParenthesisMismatch = 1,
// found ( without matching )
UnmatchedParenthesis = 2,
// more than 1 decimal point in a number. Example: 7.3.2
TooManyDecimalPoints = 3,
// decimal point on its own without any digits surrounding it. Example: 3+.+4
DecimalPointWithoutDigits = 4,
// example: 3-4*
UnexpectedEndOfExpression = 5,
// example: 3-*4
UnexpectedToken = 6,
// example: [ (or many other special characters), another example: "3,5" (comma is invalid here)
InvalidToken = 7,
// example: solve(x+3=8=x)
TooManyEquals = 8,
// example: ploteq(4+83=9)
EqualWithoutGraphVariable = 10,
// <para>example: ploteq(x+y) (expecting "=" in equation ploting)</para>
// <para>example2: Solve(5*x+9) (expecting = in the equation solving)</para>
InvalidEquationSyntax = 11,
// there is nothing in the expression
EmptyExpression = 12,
// example: factor(x=3) (expecting solve(x=3)).
EqualWithoutEquation = 14,
// example: solve( (x=3)*2 )
InvalidEquationFormat = 15,
// This error only occurs when CasContext.ParsingOptions.AllowImplicitParentheses == false.
// example: sin a (expecting sin(a))
ExpectParenthesisAfterFunctionName = 25,
// example: root(a) (expecting 2 parameters)
IncorrectNumParameter = 26,
// exmaple: "x_", "x_@", "x__1"
InvalidVariableNameFormat = 32,
// found } without matching {
BracketMismatch = 34,
// found { without matching }
UnmatchedBracket = 35,
// syntax error in MathML format. Used only if CasContext.ParsingOptions.FormatType is MathML or MathMLNoWrapper
InvalidMathMLFormat = 40,
// The input has an unknown MathML entity. Used only if CasContext.ParsingOptions.FormatType is MathML or MathMLNoWrapper
UnknownMathMLEntity = 41,
// The input has an unknown MathML element. Used only if CasContext.ParsingOptions.FormatType is MathML or MathMLNoWrapper
UnknownMathMLElement = 42,
// "i" and "I" cannot be used as variable names in real number field
CannotUseIInReal = 48,
// General error
GeneralError = 52,
// used in parsing numbers with arbitrary bases. example: base(2, 1020), base(16, 1AG)
InvalidNumberDigit = 55,
// a valid number base must be an integer >=2 and &lt;=36
InvalidNumberBase = 56,
// some functions require a variable in certain argument position. e.g. 2nd argument of deriv, integral, limit, etc.
// this error code is used if the argument at the position is not a variable
InvalidVariableSpecification = 57,
// all operands of logical operators must be logical. example: "true and 1"
ExpectingLogicalOperands = 58,
// all operands of a non-logical operator must not be logical. example: "sin(true)"
ExpectingScalarOperands = 59,
// a list can contain logicals or scalars, but not both.
CannotMixLogicalScalarInList = 60,
// in definite integral, seriesSum and seriesProduct, the index variable is used in the lower/upper limits.
// example: integral(sin(x), x, 0, x)
CannotUseIndexVarInOpLimits = 61,
// in limit, the index variable is used in the limit point
// example: limit(sin(x), x, x-1)
CannotUseIndexVarInLimPoint = 62,
/// ComplexInfinity cannot be used in real number field
CannotUseComplexInfinityInReal = 72,
// complex numbers are not allowed in inequality solving
CannotUseIInInequalitySolving = 123,
// Indicate a bug in the MathRichEdit serializer
RichEditSerializationError = 201,
// can't initialize math zone in richedit, meaning it's the wrong version richedit dll, need reinstall
RichEditInitialization = 202,
// indicate bug in either richedit or richedit wrapper
RichEditInlineObjectStructure = 203,
// in a structure like integral, sum, product, one of the boxes is not filled
RichEditMissingArgument = 204,
// errors in richedit wrapper that are not specifically handled for
RichEditGeneralError = 210,
};
[Windows::UI::Xaml::Data::Bindable] public ref class Equation sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
@@ -18,6 +212,8 @@ namespace GraphControl
OBSERVABLE_NAMED_PROPERTY_RW(bool, IsValidated);
OBSERVABLE_NAMED_PROPERTY_RW(bool, HasGraphError);
OBSERVABLE_NAMED_PROPERTY_RW(bool, IsSelected);
OBSERVABLE_NAMED_PROPERTY_RW(ErrorType, GraphErrorType);
OBSERVABLE_NAMED_PROPERTY_RW(int, GraphErrorCode);
property Windows::UI::Color LineColor
{